2021-04-06 13:07:12 +00:00
/*
2021-04-21 20:30:44 +00:00
* * def . cpp
2021-04-06 13:07:12 +00:00
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2021 Christoph Oelckers
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
* *
*/
2021-04-20 22:46:32 +00:00
# include "build.h"
# include "buildtiles.h"
# include "bitmap.h"
# include "m_argv.h"
2021-08-22 23:00:30 +00:00
# include "gamestruct.h"
2021-04-20 22:46:32 +00:00
# include "gamecontrol.h"
# include "palettecontainer.h"
# include "mapinfo.h"
# include "hw_voxels.h"
2022-01-12 22:33:44 +00:00
# include "psky.h"
2022-09-30 17:40:37 +00:00
# include "gamefuncs.h"
2022-09-30 14:25:21 +00:00
# include "models/modeldata.h"
2021-04-20 22:46:32 +00:00
2021-07-13 07:48:14 +00:00
int tileSetHightileReplacement ( int picnum , int palnum , const char * filename , float alphacut , float xscale , float yscale , float specpower , float specfactor , bool indexed = false ) ;
int tileSetSkybox ( int picnum , int palnum , FString * facenames , bool indexed = false ) ;
2021-04-07 22:47:07 +00:00
void tileRemoveReplacement ( int num ) ;
2022-09-30 17:40:37 +00:00
void AddUserMapHack ( const FString & title , const FString & mhkfile , uint8_t * md4 ) ;
2021-04-07 22:47:07 +00:00
2021-04-20 22:46:32 +00:00
static void defsparser ( FScanner & sc ) ;
static void performInclude ( FScanner * sc , const char * fn , FScriptPosition * pos )
{
int lump = fileSystem . FindFile ( fn ) ;
if ( lump = = - 1 )
{
if ( ! pos ) Printf ( " Warning: Unable to open %s \n " , fn ) ;
else pos - > Message ( MSG_ERROR , " Unable to open %s " , fn ) ;
}
else
{
FScanner included ;
included . OpenLumpNum ( lump ) ;
if ( sc ) included . symbols = std : : move ( sc - > symbols ) ;
defsparser ( included ) ;
if ( sc ) sc - > symbols = std : : move ( included . symbols ) ;
}
}
void parseInclude ( FScanner & sc , FScriptPosition & pos )
{
sc . MustGetString ( ) ;
performInclude ( & sc , sc . String , & pos ) ;
}
void parseIncludeDefault ( FScanner & sc , FScriptPosition & pos )
{
performInclude ( & sc , G_DefaultDefFile ( ) , & pos ) ;
}
2022-12-05 16:14:01 +00:00
//===========================================================================
//
// Helpers for tile parsing
//
//===========================================================================
bool ValidateTileRange ( const char * cmd , int & begin , int & end , FScriptPosition pos , bool allowswap = true )
{
if ( end < begin )
{
pos . Message ( MSG_WARNING , " %s: tile range [%d..%d] is backwards. Indices were swapped. " , cmd , begin , end ) ;
std : : swap ( begin , end ) ;
}
if ( ( unsigned ) begin > = MAXUSERTILES | | ( unsigned ) end > = MAXUSERTILES )
{
pos . Message ( MSG_ERROR , " %s: Invalid tile range [%d..%d] " , cmd , begin , end ) ;
return false ;
}
return true ;
}
bool ValidateTilenum ( const char * cmd , int tile , FScriptPosition pos )
{
if ( ( unsigned ) tile > = MAXUSERTILES )
{
pos . Message ( MSG_ERROR , " %s: Invalid tile number %d " , cmd , tile ) ;
return false ;
}
return true ;
}
//===========================================================================
//
// Internal worker for tileImportTexture
//
//===========================================================================
void processTileImport ( const char * cmd , FScriptPosition & pos , TileImport & imp )
{
if ( ! ValidateTilenum ( cmd , imp . tile , pos ) )
return ;
if ( imp . crc32 ! = INT64_MAX & & int ( imp . crc32 ) ! = tileGetCRC32 ( imp . tile ) )
return ;
if ( imp . sizex ! = INT_MAX & & tileWidth ( imp . tile ) ! = imp . sizex & & tileHeight ( imp . tile ) ! = imp . sizey )
return ;
imp . alphacut = clamp ( imp . alphacut , 0 , 255 ) ;
gi - > SetTileProps ( imp . tile , imp . surface , imp . vox , imp . shade ) ;
if ( imp . fn . IsNotEmpty ( ) & & tileImportFromTexture ( imp . fn , imp . tile , imp . alphacut , imp . istexture ) < 0 ) return ;
TileFiles . tiledata [ imp . tile ] . picanm . sf | = imp . flags ;
// This is not quite the same as originally, for two reasons:
// 1: Since these are texture properties now, there's no need to clear them.
// 2: The original code assumed that an imported texture cannot have an offset. But this can import Doom patches and PNGs with grAb, so the situation is very different.
if ( imp . xoffset = = INT_MAX ) imp . xoffset = tileLeftOffset ( imp . tile ) ;
else imp . xoffset = clamp ( imp . xoffset , - 128 , 127 ) ;
if ( imp . yoffset = = INT_MAX ) imp . yoffset = tileTopOffset ( imp . tile ) ;
else imp . yoffset = clamp ( imp . yoffset , - 128 , 127 ) ;
auto tex = tileGetTexture ( imp . tile ) ;
if ( tex )
{
tex - > SetOffsets ( imp . xoffset , imp . yoffset ) ;
if ( imp . flags & PICANM_NOFULLBRIGHT_BIT )
{
tex - > SetDisableBrightmap ( ) ;
}
}
if ( imp . extra ! = INT_MAX ) TileFiles . tiledata [ imp . tile ] . picanm . extra = imp . extra ;
}
//===========================================================================
//
// Internal worker for tileSetAnim
//
//===========================================================================
void processSetAnim ( const char * cmd , FScriptPosition & pos , SetAnim & imp )
{
if ( ! ValidateTilenum ( cmd , imp . tile1 , pos ) | |
! ValidateTilenum ( cmd , imp . tile2 , pos ) )
return ;
if ( imp . type < 0 | | imp . type > 3 )
{
pos . Message ( MSG_ERROR , " %s: animation type must be 0-3, got %d " , cmd , imp . type ) ;
return ;
}
int count = imp . tile2 - imp . tile1 ;
if ( imp . type = = ( PICANM_ANIMTYPE_BACK > > PICANM_ANIMTYPE_SHIFT ) & & imp . tile1 > imp . tile2 )
count = - count ;
TileFiles . setAnim ( imp . tile1 , imp . type , imp . speed , count ) ;
}
2021-04-07 19:59:47 +00:00
//===========================================================================
//
//
//
//===========================================================================
2021-04-08 18:03:50 +00:00
template < int cnt >
void parseSkip ( FScanner & sc , FScriptPosition & pos )
{
2021-04-10 14:35:29 +00:00
for ( int i = 0 ; i < cnt ; i + + ) if ( ! sc . GetString ( ) ) return ;
2021-04-08 18:03:50 +00:00
}
2021-04-09 17:57:56 +00:00
void parseDefine ( FScanner & sc , FScriptPosition & pos )
{
FString name ;
if ( ! sc . GetString ( name ) ) return ;
if ( ! sc . GetNumber ( ) ) return ;
sc . AddSymbol ( name , sc . Number ) ;
}
//===========================================================================
//
//
//
//===========================================================================
2021-04-07 22:47:07 +00:00
void parseDefineTexture ( FScanner & sc , FScriptPosition & pos )
{
int tile , palette ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! sc . GetNumber ( palette , true ) ) return ;
if ( ! sc . GetNumber ( true ) ) return ; //formerly x-center, unused
if ( ! sc . GetNumber ( true ) ) return ; //formerly y-center, unused
if ( ! sc . GetNumber ( true ) ) return ; //formerly x-size, unused
if ( ! sc . GetNumber ( true ) ) return ; //formerly y-size, unused
if ( ! sc . GetString ( ) ) return ;
tileSetHightileReplacement ( tile , palette , sc . String , - 1.0 , 1.0 , 1.0 , 1.0 , 1.0 ) ;
}
2021-04-07 19:59:47 +00:00
//===========================================================================
//
//
//
//===========================================================================
2021-04-21 15:56:42 +00:00
static void parseTexturePaletteBlock ( FScanner & sc , int tile )
2021-04-10 12:09:08 +00:00
{
FScanner : : SavedPos blockend ;
2021-04-21 15:56:42 +00:00
FScriptPosition pos = sc ;
2021-04-10 12:09:08 +00:00
int pal = - 1 , xsiz = 0 , ysiz = 0 ;
FString fn ;
2021-05-11 23:55:06 +00:00
float alphacut = - 1.0 , xscale = 1.0 , yscale = 1.0 , specpower = 1.0 , specfactor = 1.0 ;
2021-07-13 07:48:14 +00:00
bool indexed = false ;
2021-04-10 12:09:08 +00:00
if ( ! sc . GetNumber ( pal , true ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . GetString ( ) ;
if ( sc . Compare ( " file " ) ) sc . GetString ( fn ) ;
else if ( sc . Compare ( " alphacut " ) ) sc . GetFloat ( alphacut , true ) ;
else if ( sc . Compare ( { " xscale " , " scale " , " intensity " , " detailscale " } ) ) sc . GetFloat ( xscale , true ) ; // what's the point of all of these names?
else if ( sc . Compare ( " yscale " ) ) sc . GetFloat ( yscale , true ) ;
else if ( sc . Compare ( { " specpower " , " specularpower " , " parallaxscale " } ) ) sc . GetFloat ( specpower , true ) ;
else if ( sc . Compare ( { " specfactor " , " specularfactor " , " parallaxbias " } ) ) sc . GetFloat ( specfactor , true ) ;
else if ( sc . Compare ( " orig_sizex " ) ) sc . GetNumber ( xsiz , true ) ;
else if ( sc . Compare ( " orig_sizey " ) ) sc . GetNumber ( ysiz , true ) ;
2021-07-13 07:48:14 +00:00
else if ( sc . Compare ( " indexed " ) ) indexed = true ;
2021-04-10 12:09:08 +00:00
} ;
if ( ( unsigned ) tile < MAXUSERTILES )
{
2021-04-21 15:56:42 +00:00
if ( ( unsigned ) pal > = MAXREALPAL ) pos . Message ( MSG_ERROR , " texture (%d): invalid palette number %d " , tile , pal ) ;
else if ( fn . IsEmpty ( ) ) pos . Message ( MSG_ERROR , " texture (%d): missing file name in palette definition " , tile ) ;
else if ( ! fileSystem . FileExists ( fn ) ) pos . Message ( MSG_ERROR , " texture (%d): file '%s' not found in palette definition " , tile , fn . GetChars ( ) ) ;
2021-04-10 12:09:08 +00:00
else
{
if ( xsiz > 0 & & ysiz > 0 )
{
tileSetDummy ( tile , xsiz , ysiz ) ;
}
xscale = 1.0f / xscale ;
yscale = 1.0f / yscale ;
2021-07-13 07:48:14 +00:00
tileSetHightileReplacement ( tile , pal , fn , alphacut , xscale , yscale , specpower , specfactor , indexed ) ;
2021-04-10 12:09:08 +00:00
}
}
}
2021-04-21 15:56:42 +00:00
static void parseTextureSpecialBlock ( FScanner & sc , int tile , int pal )
2021-04-10 12:09:08 +00:00
{
FScanner : : SavedPos blockend ;
2021-04-21 15:56:42 +00:00
FScriptPosition pos = sc ;
2021-04-10 12:09:08 +00:00
FString fn ;
2021-05-11 23:55:06 +00:00
float xscale = 1.0 , yscale = 1.0 , specpower = 1.0 , specfactor = 1.0 ;
2021-04-10 12:09:08 +00:00
2021-04-21 15:56:42 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
2021-04-10 12:09:08 +00:00
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . GetString ( ) ;
if ( sc . Compare ( " file " ) ) sc . GetString ( fn ) ;
else if ( sc . Compare ( { " xscale " , " scale " , " intensity " , " detailscale " } ) ) sc . GetFloat ( xscale , true ) ; // what's the point of all of these names?
else if ( sc . Compare ( " yscale " ) ) sc . GetFloat ( yscale , true ) ;
else if ( sc . Compare ( { " specpower " , " specularpower " , " parallaxscale " } ) ) sc . GetFloat ( specpower , true ) ;
else if ( sc . Compare ( { " specfactor " , " specularfactor " , " parallaxbias " } ) ) sc . GetFloat ( specfactor , true ) ;
} ;
if ( ( unsigned ) tile < MAXUSERTILES )
{
2021-04-21 15:56:42 +00:00
if ( fn . IsEmpty ( ) ) pos . Message ( MSG_ERROR , " texture (%d): missing file name for layer definition " , tile ) ;
else if ( ! fileSystem . FileExists ( fn ) ) pos . Message ( MSG_ERROR , " texture (%d): file '%s' not found in layer definition " , tile , fn . GetChars ( ) ) ;
2021-04-10 12:09:08 +00:00
else
{
if ( pal = = DETAILPAL )
{
xscale = 1.0f / xscale ;
yscale = 1.0f / yscale ;
}
tileSetHightileReplacement ( tile , pal , fn , - 1.f , xscale , yscale , specpower , specfactor ) ;
}
}
}
void parseTexture ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int tile = - 1 ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
ValidateTilenum ( " texture " , tile , pos ) ; // do not abort, we still need to parse over the data.
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
2021-04-21 15:56:42 +00:00
if ( sc . Compare ( " pal " ) ) parseTexturePaletteBlock ( sc , tile ) ;
else if ( sc . Compare ( " detail " ) ) parseTextureSpecialBlock ( sc , tile , DETAILPAL ) ;
else if ( sc . Compare ( " glow " ) ) parseTextureSpecialBlock ( sc , tile , GLOWPAL ) ;
else if ( sc . Compare ( " specular " ) ) parseTextureSpecialBlock ( sc , tile , SPECULARPAL ) ;
else if ( sc . Compare ( " normal " ) ) parseTextureSpecialBlock ( sc , tile , NORMALPAL ) ;
2021-04-10 12:09:08 +00:00
}
}
//===========================================================================
//
//
//
//===========================================================================
2021-04-13 19:02:14 +00:00
void parseUndefTexture ( FScanner & sc , FScriptPosition & pos )
{
if ( ! sc . GetNumber ( true ) ) return ;
if ( ValidateTilenum ( " undeftexture " , sc . Number , pos ) ) tileRemoveReplacement ( sc . Number ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseUndefTextureRange ( FScanner & sc , FScriptPosition & pos )
{
int start , end ;
if ( ! sc . GetNumber ( start , true ) ) return ;
if ( ! sc . GetNumber ( end , true ) ) return ;
if ( ValidateTileRange ( " undeftexturerange " , start , end , pos ) )
for ( int i = start ; i < = end ; i + + ) tileRemoveReplacement ( i ) ;
}
//===========================================================================
//
//
//
//===========================================================================
2021-04-13 16:17:28 +00:00
void parseTileFromTexture ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
TileImport imp ;
if ( ! sc . GetNumber ( imp . tile , true ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( { " file " , " name " } ) ) sc . GetString ( imp . fn ) ;
else if ( sc . Compare ( " alphacut " ) ) sc . GetNumber ( imp . alphacut , true ) ;
else if ( sc . Compare ( { " xoff " , " xoffset " } ) ) sc . GetNumber ( imp . xoffset , true ) ;
else if ( sc . Compare ( { " yoff " , " yoffset " } ) ) sc . GetNumber ( imp . yoffset , true ) ;
else if ( sc . Compare ( " texhitscan " ) ) imp . flags | = PICANM_TEXHITSCAN_BIT ;
else if ( sc . Compare ( " nofullbright " ) ) imp . flags | = PICANM_NOFULLBRIGHT_BIT ;
else if ( sc . Compare ( " texture " ) ) imp . istexture = 1 ;
else if ( sc . Compare ( " ifcrc " ) ) sc . GetNumber ( imp . crc32 , true ) ;
else if ( sc . Compare ( " extra " ) ) sc . GetNumber ( imp . extra , true ) ;
else if ( sc . Compare ( " surface " ) ) sc . GetNumber ( imp . surface , true ) ;
else if ( sc . Compare ( " voxel " ) ) sc . GetNumber ( imp . vox , true ) ;
else if ( sc . Compare ( " shade " ) ) sc . GetNumber ( imp . shade , true ) ;
else if ( sc . Compare ( " view " ) ) { sc . GetNumber ( imp . extra , true ) ; imp . extra & = 7 ; }
else if ( sc . Compare ( " ifmatch " ) )
{
FScanner : : SavedPos blockend2 ;
if ( sc . StartBraces ( & blockend2 ) ) return ;
while ( ! sc . FoundEndBrace ( blockend2 ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " size " ) )
{
sc . GetNumber ( imp . sizex , true ) ;
sc . GetNumber ( imp . sizey , true ) ;
}
else if ( sc . Compare ( " crc32 " ) ) sc . GetNumber ( imp . crc32 , true ) ;
}
}
}
processTileImport ( " tilefromtexture " , pos , imp ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseCopyTile ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int tile = - 1 , source = - 1 ;
int havetile = 0 , xoffset = - 1024 , yoffset = - 1024 ;
2021-11-14 14:03:50 +00:00
int flags = 0 , temppal = - 1 , tempsource = - 1 ;
2021-04-13 16:17:28 +00:00
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " tile " ) )
{
if ( sc . GetNumber ( tempsource , true ) )
{
if ( ValidateTilenum ( " copytile " , tempsource , pos ) )
{
source = tempsource ;
havetile = true ;
}
}
}
else if ( sc . Compare ( " pal " ) )
{
// This is a bit messy because it doesn't wait until everything is parsed. Sadly that quirk needs to be replicated...
if ( sc . GetNumber ( temppal , true ) )
{
// palettize self case
if ( ! havetile )
{
if ( ValidateTilenum ( " copytile " , tile , pos ) ) havetile = true ;
}
2021-04-21 15:56:42 +00:00
if ( ( unsigned ) temppal > = MAXREALPAL )
2021-04-13 16:17:28 +00:00
{
2021-10-08 17:06:41 +00:00
pos . Message ( MSG_ERROR , " copytile: palette number %d out of range (max=%d) \n " , temppal , MAXREALPAL - 1 ) ;
2021-04-13 16:17:28 +00:00
break ;
}
}
}
else if ( sc . Compare ( { " xoff " , " xoffset " } ) ) sc . GetNumber ( xoffset , true ) ;
else if ( sc . Compare ( { " yoff " , " yoffset " } ) ) sc . GetNumber ( yoffset , true ) ;
else if ( sc . Compare ( " texhitscan " ) ) flags | = PICANM_TEXHITSCAN_BIT ;
else if ( sc . Compare ( " nofullbright " ) ) flags | = PICANM_NOFULLBRIGHT_BIT ;
}
if ( ! ValidateTilenum ( " copytile " , tile , pos ) ) return ;
// if !havetile, we have never confirmed a valid source
if ( ! havetile & & ! ValidateTilenum ( " copytile " , source , pos ) ) return ;
tileCopy ( tile , source , temppal , xoffset , yoffset , flags ) ;
}
//===========================================================================
//
//
//
//===========================================================================
2021-04-13 16:17:54 +00:00
void parseImportTile ( FScanner & sc , FScriptPosition & pos )
{
int tile ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! sc . GetString ( ) ) return ;
if ( ! ValidateTilenum ( " importtile " , tile , pos ) ) return ;
int texstatus = tileImportFromTexture ( sc . String , tile , 255 , 0 ) ;
if ( texstatus > = 0 ) TileFiles . tiledata [ tile ] . picanm = { } ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseDummyTile ( FScanner & sc , FScriptPosition & pos )
{
int tile , xsiz , ysiz ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! sc . GetNumber ( xsiz , true ) ) return ;
if ( ! sc . GetNumber ( ysiz , true ) ) return ;
if ( ! ValidateTilenum ( " dummytile " , tile , pos ) ) return ;
tileSetDummy ( tile , xsiz , ysiz ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseDummyTileRange ( FScanner & sc , FScriptPosition & pos )
{
int tile1 , tile2 , xsiz , ysiz ;
if ( ! sc . GetNumber ( tile1 , true ) ) return ;
if ( ! sc . GetNumber ( tile2 , true ) ) return ;
if ( ! sc . GetNumber ( xsiz , true ) ) return ;
if ( ! sc . GetNumber ( ysiz , true ) ) return ;
if ( ! ValidateTileRange ( " dummytilerange " , tile1 , tile2 , pos ) ) return ;
if ( xsiz < 0 | | ysiz < 0 ) return ;
for ( int i = tile1 ; i < = tile2 ; i + + ) tileSetDummy ( i , xsiz , ysiz ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseUndefineTile ( FScanner & sc , FScriptPosition & pos )
{
int tile ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ValidateTilenum ( " undefinetile " , tile , pos ) )
tileDelete ( tile ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseUndefineTileRange ( FScanner & sc , FScriptPosition & pos )
{
int tile1 , tile2 ;
if ( ! sc . GetNumber ( tile1 , true ) ) return ;
if ( ! sc . GetNumber ( tile2 , true ) ) return ;
if ( ! ValidateTileRange ( " undefinetilerange " , tile1 , tile2 , pos ) ) return ;
for ( int i = tile1 ; i < = tile2 ; i + + ) tileDelete ( i ) ;
}
//===========================================================================
//
//
//
//===========================================================================
2021-04-07 22:47:07 +00:00
void parseDefineSkybox ( FScanner & sc , FScriptPosition & pos )
{
int tile , palette ;
FString fn [ 6 ] ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! sc . GetNumber ( palette , true ) ) return ;
if ( ! sc . GetNumber ( true ) ) return ; //'future extension' (for what?)
for ( int i = 0 ; i < 6 ; i + + )
{
if ( ! sc . GetString ( ) ) return ;
fn [ i ] = sc . String ;
}
tileSetSkybox ( tile , palette , fn ) ;
}
2021-04-07 19:59:47 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseSkybox ( FScanner & sc , FScriptPosition & pos )
{
2021-04-10 12:09:08 +00:00
FString faces [ 6 ] ;
FScanner : : SavedPos blockend ;
int tile = - 1 , pal = 0 ;
2021-07-13 07:48:14 +00:00
bool indexed = false ;
2021-04-10 12:09:08 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " tile " ) ) sc . GetNumber ( tile , true ) ;
else if ( sc . Compare ( " pal " ) ) sc . GetNumber ( pal , true ) ;
else if ( sc . Compare ( { " ft " , " front " , " forward " } ) ) sc . GetString ( faces [ 0 ] ) ;
else if ( sc . Compare ( { " rt " , " right " } ) ) sc . GetString ( faces [ 1 ] ) ;
else if ( sc . Compare ( { " bk " , " back " } ) ) sc . GetString ( faces [ 2 ] ) ;
else if ( sc . Compare ( { " lt " , " lf " , " left " } ) ) sc . GetString ( faces [ 3 ] ) ;
else if ( sc . Compare ( { " up " , " ceiling " , " top " , " ceil " } ) ) sc . GetString ( faces [ 4 ] ) ;
else if ( sc . Compare ( { " dn " , " floor " , " bottom " , " down " } ) ) sc . GetString ( faces [ 5 ] ) ;
2021-07-13 07:48:14 +00:00
else if ( sc . Compare ( " indexed " ) ) indexed = true ;
2021-04-07 19:59:47 +00:00
// skip over everything else.
2021-04-10 12:09:08 +00:00
}
2021-04-21 15:56:42 +00:00
if ( tile < 0 ) pos . Message ( MSG_ERROR , " skybox: missing tile number " ) ;
2021-07-13 07:48:14 +00:00
else tileSetSkybox ( tile , pal , faces , indexed ) ;
2021-04-07 19:59:47 +00:00
}
//===========================================================================
//
//
//
//===========================================================================
2021-04-06 14:22:24 +00:00
void parseSetupTile ( FScanner & sc , FScriptPosition & pos )
{
int tile ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! ValidateTilenum ( " setuptile " , tile , pos ) ) return ;
auto & tiled = TileFiles . tiledata [ tile ] ;
if ( ! sc . GetNumber ( tiled . hiofs . xsize , true ) ) return ;
if ( ! sc . GetNumber ( tiled . hiofs . ysize , true ) ) return ;
if ( ! sc . GetNumber ( tiled . hiofs . xoffs , true ) ) return ;
if ( ! sc . GetNumber ( tiled . hiofs . yoffs , true ) ) return ;
}
2021-04-07 19:59:47 +00:00
//===========================================================================
//
//
//
//===========================================================================
2021-04-06 14:22:24 +00:00
void parseSetupTileRange ( FScanner & sc , FScriptPosition & pos )
{
int tilestart , tileend ;
if ( ! sc . GetNumber ( tilestart , true ) ) return ;
if ( ! sc . GetNumber ( tileend , true ) ) return ;
if ( ! ValidateTileRange ( " setuptilerange " , tilestart , tileend , pos ) ) return ;
TileOffs hiofs ;
if ( ! sc . GetNumber ( hiofs . xsize , true ) ) return ;
if ( ! sc . GetNumber ( hiofs . ysize , true ) ) return ;
if ( ! sc . GetNumber ( hiofs . xoffs , true ) ) return ;
if ( ! sc . GetNumber ( hiofs . yoffs , true ) ) return ;
for ( int i = tilestart ; i < = tileend ; i + + ) TileFiles . tiledata [ i ] . hiofs = hiofs ;
}
2021-04-06 13:07:12 +00:00
2021-04-07 19:59:47 +00:00
//===========================================================================
//
//
//
//===========================================================================
2021-04-06 13:07:12 +00:00
void parseAnimTileRange ( FScanner & sc , FScriptPosition & pos )
{
SetAnim set ;
if ( ! sc . GetNumber ( set . tile1 , true ) ) return ;
if ( ! sc . GetNumber ( set . tile2 , true ) ) return ;
if ( ! sc . GetNumber ( set . speed , true ) ) return ;
if ( ! sc . GetNumber ( set . type , true ) ) return ;
processSetAnim ( " animtilerange " , pos , set ) ;
}
2021-04-09 17:57:56 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseAlphahack ( FScanner & sc , FScriptPosition & pos )
{
int tile ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! sc . GetFloat ( true ) ) return ;
if ( ( unsigned ) tile < MAXTILES ) TileFiles . tiledata [ tile ] . texture - > alphaThreshold = ( float ) sc . Float ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseAlphahackRange ( FScanner & sc , FScriptPosition & pos )
{
int tilestart , tileend ;
if ( ! sc . GetNumber ( tilestart , true ) ) return ;
if ( ! sc . GetNumber ( tileend , true ) ) return ;
if ( ! sc . GetFloat ( true ) ) return ;
if ( ! ValidateTileRange ( " alphahackrange " , tilestart , tileend , pos ) ) return ;
for ( int i = tilestart ; i < = tileend ; i + + )
TileFiles . tiledata [ i ] . texture - > alphaThreshold = ( float ) sc . Number ;
}
2021-04-11 16:37:11 +00:00
//===========================================================================
//
//
//
//===========================================================================
static int lastvoxid = - 1 ;
void parseDefineVoxel ( FScanner & sc , FScriptPosition & pos )
{
sc . MustGetString ( ) ;
while ( nextvoxid < MAXVOXELS & & voxreserve [ nextvoxid ] ) nextvoxid + + ;
if ( nextvoxid = = MAXVOXELS )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " Maximum number of voxels (%d) already defined. " , MAXVOXELS ) ;
2021-04-11 16:37:11 +00:00
return ;
}
if ( voxDefine ( nextvoxid , sc . String ) )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " Unable to load voxel file \" %s \" " , sc . String ) ;
2021-04-11 16:37:11 +00:00
return ;
}
lastvoxid = nextvoxid + + ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineVoxelTiles ( FScanner & sc , FScriptPosition & pos )
{
int tilestart , tileend ;
if ( ! sc . GetNumber ( tilestart , true ) ) return ;
if ( ! sc . GetNumber ( tileend , true ) ) return ;
if ( ! ValidateTileRange ( " definevoxeltiles " , tilestart , tileend , pos ) ) return ;
if ( lastvoxid < 0 )
{
pos . Message ( MSG_WARNING , " Warning: Ignoring voxel tiles definition without valid voxel. \n " ) ;
return ;
}
for ( int i = tilestart ; i < = tileend ; i + + ) tiletovox [ i ] = lastvoxid ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseVoxel ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int tile0 = MAXTILES , tile1 = - 1 ;
FString fn ;
2021-05-10 22:48:35 +00:00
bool error = false ;
2021-04-11 16:37:11 +00:00
if ( ! sc . GetString ( fn ) ) return ;
while ( nextvoxid < MAXVOXELS & & voxreserve [ nextvoxid ] ) nextvoxid + + ;
if ( nextvoxid = = MAXVOXELS )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " Maximum number of voxels (%d) already defined. " , MAXVOXELS ) ;
2021-05-10 22:48:35 +00:00
error = true ;
2021-04-11 16:37:11 +00:00
}
2021-05-10 22:48:35 +00:00
else if ( voxDefine ( nextvoxid , fn ) )
2021-04-11 16:37:11 +00:00
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " Unable to load voxel file \" %s \" " , fn . GetChars ( ) ) ;
2021-05-10 22:48:35 +00:00
error = true ;
2021-04-11 16:37:11 +00:00
}
int lastvoxid = nextvoxid + + ;
2021-12-30 09:30:21 +00:00
2021-04-11 16:37:11 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " tile " ) )
{
sc . GetNumber ( true ) ;
2021-05-10 22:48:35 +00:00
if ( ValidateTilenum ( " voxel " , sc . Number , pos ) )
{
if ( ! error ) tiletovox [ sc . Number ] = lastvoxid ;
}
2021-04-11 16:37:11 +00:00
}
if ( sc . Compare ( " tile0 " ) ) sc . GetNumber ( tile0 , true ) ;
if ( sc . Compare ( " tile1 " ) )
{
sc . GetNumber ( tile1 , true ) ;
2021-05-10 22:48:35 +00:00
if ( ValidateTileRange ( " voxel " , tile0 , tile1 , pos ) & & ! error )
2021-04-11 16:37:11 +00:00
{
for ( int i = tile0 ; i < = tile1 ; i + + ) tiletovox [ i ] = lastvoxid ;
}
}
if ( sc . Compare ( " scale " ) )
{
sc . GetFloat ( true ) ;
2021-05-10 22:48:35 +00:00
if ( ! error ) voxscale [ lastvoxid ] = ( float ) sc . Float ;
2021-04-11 16:37:11 +00:00
}
2021-05-10 22:48:35 +00:00
if ( sc . Compare ( " rotate " ) & & ! error ) voxrotate . Set ( lastvoxid ) ;
2021-04-11 16:37:11 +00:00
}
}
2021-04-09 17:57:56 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseDefineTint ( FScanner & sc , FScriptPosition & pos )
{
int pal , r , g , b , f ;
if ( ! sc . GetNumber ( pal , true ) ) return ;
if ( ! sc . GetNumber ( r ) ) return ;
if ( ! sc . GetNumber ( g ) ) return ;
if ( ! sc . GetNumber ( b ) ) return ;
if ( ! sc . GetNumber ( f ) ) return ;
lookups . setPaletteTint ( pal , r , g , b , 0 , 0 , 0 , f ) ;
}
2021-12-30 09:30:21 +00:00
2021-04-10 14:35:29 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseFogpal ( FScanner & sc , FScriptPosition & pos )
{
int pal , r , g , b ;
if ( ! sc . GetNumber ( pal , true ) ) return ;
if ( ! sc . GetNumber ( r ) ) return ;
if ( ! sc . GetNumber ( g ) ) return ;
if ( ! sc . GetNumber ( b ) ) return ;
r = clamp ( r , 0 , 63 ) ;
g = clamp ( g , 0 , 63 ) ;
b = clamp ( b , 0 , 63 ) ;
lookups . makeTable ( pal , nullptr , r < < 2 , g < < 2 , b < < 2 , 1 ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseNoFloorpalRange ( FScanner & sc , FScriptPosition & pos )
{
int start , end ;
if ( ! sc . GetNumber ( start , true ) ) return ;
if ( ! sc . GetNumber ( end , true ) ) return ;
if ( start > 1 ) start = 1 ;
if ( end > MAXPALOOKUPS - 1 ) end = MAXPALOOKUPS - 1 ;
for ( int i = start ; i < = end ; i + + )
lookups . tables [ i ] . noFloorPal = true ;
}
2021-04-11 13:23:42 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseTint ( FScanner & sc , FScriptPosition & pos )
{
int red = 255 , green = 255 , blue = 255 , shadered = 0 , shadegreen = 0 , shadeblue = 0 , pal = - 1 , flags = 0 ;
FScanner : : SavedPos blockend ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " pal " ) ) sc . GetNumber ( pal , true ) ;
else if ( sc . Compare ( { " red " , " r " } ) ) sc . GetNumber ( red ) ;
else if ( sc . Compare ( { " green " , " g " } ) ) sc . GetNumber ( green ) ;
else if ( sc . Compare ( { " blue " , " b " } ) ) sc . GetNumber ( blue ) ;
else if ( sc . Compare ( { " shadered " , " sr " } ) ) sc . GetNumber ( shadered ) ;
else if ( sc . Compare ( { " shadegreen " , " sg " } ) ) sc . GetNumber ( shadegreen ) ;
else if ( sc . Compare ( { " shadeblue " , " sb " } ) ) sc . GetNumber ( shadeblue ) ;
else if ( sc . Compare ( " flags " ) ) sc . GetNumber ( flags , true ) ;
}
if ( pal < 0 )
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " tint: palette number missing " ) ;
2021-04-11 13:23:42 +00:00
else
lookups . setPaletteTint ( pal , clamp ( red , 0 , 255 ) , clamp ( green , 0 , 255 ) , clamp ( blue , 0 , 255 ) ,
clamp ( shadered , 0 , 255 ) , clamp ( shadegreen , 0 , 255 ) , clamp ( shadeblue , 0 , 255 ) , flags ) ;
}
2021-04-12 22:28:51 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseMusic ( FScanner & sc , FScriptPosition & pos )
{
FString id , file ;
FScanner : : SavedPos blockend ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " id " ) ) sc . GetString ( id ) ;
else if ( sc . Compare ( " file " ) ) sc . GetString ( file ) ;
}
2021-09-05 18:35:10 +00:00
SetMusicReplacement ( id , file ) ;
2021-04-12 22:28:51 +00:00
}
//===========================================================================
//
//
//
//===========================================================================
void parseMapinfo ( FScanner & sc , FScriptPosition & pos )
{
2022-09-30 17:40:37 +00:00
FString title ;
FString mhkfile ;
uint8_t md4b [ 16 ] { } ;
2021-04-12 22:28:51 +00:00
FScanner : : SavedPos blockend ;
2021-11-28 17:37:57 +00:00
TArray < FString > md4s ;
2021-04-12 22:28:51 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " mapfile " ) ) sc . GetString ( ) ;
2022-09-30 17:40:37 +00:00
else if ( sc . Compare ( " maptitle " ) ) sc . GetString ( title ) ;
else if ( sc . Compare ( " mhkfile " ) ) sc . GetString ( mhkfile ) ;
2021-04-12 22:28:51 +00:00
else if ( sc . Compare ( " mapmd4 " ) )
{
sc . GetString ( ) ;
2021-11-28 17:37:57 +00:00
md4s . Push ( sc . String ) ;
}
}
for ( auto & md4 : md4s )
{
for ( int i = 0 ; i < 16 ; i + + )
{
char smallbuf [ 3 ] = { md4 [ 2 * i ] , md4 [ 2 * i + 1 ] , 0 } ;
2022-09-30 17:40:37 +00:00
md4b [ i ] = ( uint8_t ) strtol ( smallbuf , nullptr , 16 ) ;
2021-04-12 22:28:51 +00:00
}
2022-09-30 17:40:37 +00:00
AddUserMapHack ( title , mhkfile , md4b ) ;
2021-04-12 22:28:51 +00:00
}
}
//===========================================================================
//
//
//
//===========================================================================
void parseEcho ( FScanner & sc , FScriptPosition & pos )
{
sc . MustGetString ( ) ;
Printf ( " %s \n " , sc . String ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseMultiPsky ( FScanner & sc , FScriptPosition & pos )
{
2022-01-12 22:33:44 +00:00
// The maximum tile offset ever used in any tiled parallaxed multi-sky.
enum { PSKYOFF_MAX = 16 } ;
2021-04-12 22:28:51 +00:00
FScanner : : SavedPos blockend ;
2022-01-12 22:33:44 +00:00
SkyDefinition sky { } ;
2021-04-12 22:28:51 +00:00
2022-01-12 22:33:44 +00:00
bool crc ;
sky . scale = 1.f ;
sky . baselineofs = INT_MIN ;
if ( sc . CheckString ( " crc " ) )
{
if ( ! sc . GetNumber ( sky . crc32 , true ) ) return ;
crc = true ;
}
else
{
if ( ! sc . GetNumber ( sky . tilenum , true ) ) return ;
crc = false ;
}
2021-04-12 22:28:51 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
2022-01-12 22:33:44 +00:00
if ( sc . Compare ( " horizfrac " ) ) sc . GetNumber ( true ) ; // not used anymore
else if ( sc . Compare ( " yoffset " ) ) sc . GetNumber ( sky . pmoffset , true ) ;
else if ( sc . Compare ( " baseline " ) ) sc . GetNumber ( sky . baselineofs , true ) ;
2021-04-12 22:28:51 +00:00
else if ( sc . Compare ( " lognumtiles " ) ) sc . GetNumber ( sky . lognumtiles , true ) ;
2022-10-12 17:00:29 +00:00
else if ( sc . Compare ( " yscale " ) ) { int intscale ; sc . GetNumber ( intscale , true ) ; sky . scale = intscale * ( 1.f / 65536.f ) ; }
2021-04-12 22:28:51 +00:00
else if ( sc . Compare ( { " tile " , " panel " } ) )
{
2022-01-13 15:01:26 +00:00
if ( ! sc . CheckString ( " } " ) )
{
int panel = 0 , offset = 0 ;
sc . GetNumber ( panel , true ) ;
sc . GetNumber ( offset , true ) ;
if ( ( unsigned ) panel < MAXPSKYTILES & & ( unsigned ) offset < = PSKYOFF_MAX ) sky . offsets [ panel ] = offset ;
}
else
{
int panel = 0 , offset ;
while ( ! sc . CheckString ( " } " ) )
{
sc . GetNumber ( offset , true ) ;
if ( ( unsigned ) panel < MAXPSKYTILES & & ( unsigned ) offset < = PSKYOFF_MAX ) sky . offsets [ panel ] = offset ;
panel + + ;
}
}
2021-04-12 22:28:51 +00:00
}
}
2022-01-12 22:33:44 +00:00
if ( sky . baselineofs = = INT_MIN ) sky . baselineofs = sky . pmoffset ;
if ( ! crc & & sky . tilenum ! = DEFAULTPSKY & & ( unsigned ) sky . tilenum > = MAXUSERTILES ) return ;
2021-04-12 22:28:51 +00:00
if ( ( 1 < < sky . lognumtiles ) > MAXPSKYTILES ) return ;
2022-01-12 22:33:44 +00:00
if ( crc ) addSkyCRC ( sky , sky . crc32 ) ;
else addSky ( sky , sky . tilenum ) ;
2021-04-12 22:28:51 +00:00
}
2021-04-13 16:15:12 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseRffDefineId ( FScanner & sc , FScriptPosition & pos )
{
FString resName ;
FString resType ;
int resID ;
if ( ! sc . GetString ( resName ) ) return ;
if ( ! sc . GetString ( resType ) ) return ;
if ( ! sc . GetNumber ( resID ) ) return ;
if ( ! sc . GetString ( ) ) return ;
resName . AppendFormat ( " .%s " , resType . GetChars ( ) ) ;
fileSystem . CreatePathlessCopy ( resName , resID , 0 ) ;
}
//===========================================================================
//
// empty stub
//
//===========================================================================
2021-04-13 16:16:34 +00:00
void parseEmptyBlock ( FScanner & sc , FScriptPosition & pos )
2021-04-13 16:15:12 +00:00
{
FScanner : : SavedPos blockend ;
if ( sc . StartBraces ( & blockend ) ) return ;
2021-04-13 17:22:28 +00:00
sc . RestorePos ( blockend ) ;
2021-04-20 18:41:04 +00:00
sc . CheckString ( " } " ) ;
2021-04-13 16:15:12 +00:00
}
2021-04-20 18:41:04 +00:00
void parseEmptyBlockWithParm ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
sc . MustGetString ( ) ;
if ( sc . StartBraces ( & blockend ) ) return ;
sc . RestorePos ( blockend ) ;
sc . CheckString ( " } " ) ;
}
2021-04-13 16:15:56 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseTexHitscanRange ( FScanner & sc , FScriptPosition & pos )
{
int start , end ;
if ( ! sc . GetNumber ( start , true ) ) return ;
if ( ! sc . GetNumber ( end , true ) ) return ;
if ( start < 0 ) start = 0 ;
if ( end > = MAXUSERTILES ) end = MAXUSERTILES - 1 ;
for ( int i = start ; i < = end ; i + + )
TileFiles . tiledata [ i ] . picanm . sf | = PICANM_TEXHITSCAN_BIT ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseNoFullbrightRange ( FScanner & sc , FScriptPosition & pos )
{
int start , end ;
if ( ! sc . GetNumber ( start , true ) ) return ;
if ( ! sc . GetNumber ( end , true ) ) return ;
if ( start < 0 ) start = 0 ;
if ( end > = MAXUSERTILES ) end = MAXUSERTILES - 1 ;
for ( int i = start ; i < = end ; i + + )
{
auto tex = tileGetTexture ( i ) ;
if ( tex - > isValid ( ) ) tex - > SetDisableBrightmap ( ) ;
}
}
2021-04-13 16:17:04 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseArtFile ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
FString file ;
int tile = - 1 ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " file " ) ) sc . GetString ( file ) ;
else if ( sc . Compare ( " tile " ) ) sc . GetNumber ( tile , true ) ;
}
if ( file . IsEmpty ( ) )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " artfile: missing file name " ) ;
2021-04-13 16:17:04 +00:00
}
else if ( tile > = 0 & & ValidateTilenum ( " artfile " , tile , pos ) )
TileFiles . LoadArtFile ( file , nullptr , tile ) ;
}
2021-04-13 17:22:28 +00:00
//===========================================================================
//
// this is only left in for compatibility purposes.
// There's way better methods to handle translucency.
//
//===========================================================================
2021-04-21 15:56:42 +00:00
static void parseBlendTableGlBlend ( FScanner & sc , int id )
2021-04-13 17:22:28 +00:00
{
FScanner : : SavedPos blockend ;
2021-04-21 15:56:42 +00:00
FScriptPosition pos = sc ;
2021-04-13 17:22:28 +00:00
FString file ;
if ( sc . StartBraces ( & blockend ) ) return ;
glblend_t * const glb = glblend + id ;
* glb = nullglblend ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
int which = 0 ;
sc . MustGetString ( ) ;
if ( sc . Compare ( " forward " ) ) which = 1 ;
else if ( sc . Compare ( " reverse " ) ) which = 2 ;
else if ( sc . Compare ( " both " ) ) which = 3 ;
else continue ;
FScanner : : SavedPos blockend2 ;
if ( sc . StartBraces ( & blockend2 ) ) return ;
glblenddef_t bdef { } ;
while ( ! sc . FoundEndBrace ( blockend2 ) )
{
int whichb = 0 ;
sc . MustGetString ( ) ;
2021-04-20 18:41:04 +00:00
if ( sc . Compare ( " } " ) ) break ;
2021-04-13 17:22:28 +00:00
if ( sc . Compare ( { " src " , " sfactor " , " top " } ) ) whichb = 0 ;
else if ( sc . Compare ( { " dst " , " dfactor " , " bottom " } ) ) whichb = 1 ;
else if ( sc . Compare ( " alpha " ) )
{
sc . GetFloat ( true ) ;
bdef . alpha = ( float ) sc . Float ;
continue ;
}
uint8_t * const factor = whichb = = 0 ? & bdef . src : & bdef . dst ;
2021-04-20 18:41:04 +00:00
sc . MustGetString ( ) ;
2021-04-13 17:22:28 +00:00
if ( sc . Compare ( " ZERO " ) ) * factor = STYLEALPHA_Zero ;
else if ( sc . Compare ( " ONE " ) ) * factor = STYLEALPHA_One ;
else if ( sc . Compare ( " SRC_COLOR " ) ) * factor = STYLEALPHA_SrcCol ;
else if ( sc . Compare ( " ONE_MINUS_SRC_COLOR " ) ) * factor = STYLEALPHA_InvSrcCol ;
else if ( sc . Compare ( " SRC_ALPHA " ) ) * factor = STYLEALPHA_Src ;
else if ( sc . Compare ( " ONE_MINUS_SRC_ALPHA " ) ) * factor = STYLEALPHA_InvSrc ;
else if ( sc . Compare ( " DST_ALPHA " ) ) * factor = STYLEALPHA_Dst ;
else if ( sc . Compare ( " ONE_MINUS_DST_ALPHA " ) ) * factor = STYLEALPHA_InvDst ;
else if ( sc . Compare ( " DST_COLOR " ) ) * factor = STYLEALPHA_DstCol ;
else if ( sc . Compare ( " ONE_MINUS_DST_COLOR " ) ) * factor = STYLEALPHA_InvDstCol ;
else sc . ScriptMessage ( " Unknown blend operation %s " , sc . String ) ;
}
if ( which & 1 ) glb - > def [ 0 ] = bdef ;
if ( which & 2 ) glb - > def [ 1 ] = bdef ;
}
}
void parseBlendTable ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int id ;
if ( ! sc . GetNumber ( id , true ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
if ( ( unsigned ) id > = MAXBLENDTABS )
{
pos . Message ( MSG_ERROR , " blendtable: Invalid blendtable number %d " , id ) ;
sc . RestorePos ( blockend ) ;
return ;
}
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " raw " ) ) parseEmptyBlock ( sc , pos ) ; // Raw translucency map for the software renderer. We have no use for this.
2021-04-21 15:56:42 +00:00
else if ( sc . Compare ( " glblend " ) ) parseBlendTableGlBlend ( sc , id ) ;
2021-04-13 17:22:28 +00:00
else if ( sc . Compare ( " undef " ) ) glblend [ id ] = defaultglblend ;
else if ( sc . Compare ( " copy " ) )
{
sc . GetNumber ( true ) ;
if ( ( unsigned ) sc . Number > = MAXBLENDTABS | | sc . Number = = id )
{
pos . Message ( MSG_ERROR , " blendtable: Invalid source blendtable number %d in copy " , sc . Number ) ;
}
else glblend [ id ] = glblend [ sc . Number ] ;
}
}
}
2021-04-13 17:40:43 +00:00
//===========================================================================
//
// thw same note as for blendtable applies here.
//
//===========================================================================
void parseNumAlphaTabs ( FScanner & sc , FScriptPosition & pos )
{
int value ;
if ( ! sc . GetNumber ( value ) ) return ;
for ( int a = 1 , value2 = value * 2 + ( value & 1 ) ; a < = value ; + + a )
{
float finv2value = 1.f / ( float ) value2 ;
glblend_t * const glb = glblend + a ;
* glb = defaultglblend ;
glb - > def [ 0 ] . alpha = ( float ) ( value2 - a ) * finv2value ;
glb - > def [ 1 ] . alpha = ( float ) a * finv2value ;
}
}
2021-04-20 20:43:02 +00:00
//===========================================================================
//
//
//
//===========================================================================
static bool parseBasePaletteRaw ( FScanner & sc , FScriptPosition & pos , int id )
{
FScanner : : SavedPos blockend ;
FString fn ;
int32_t offset = 0 ;
int32_t shiftleft = 0 ;
if ( sc . StartBraces ( & blockend ) ) return false ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " file " ) ) sc . GetString ( fn ) ;
else if ( sc . Compare ( " offset " ) ) sc . GetNumber ( offset , true ) ;
else if ( sc . Compare ( " shiftleft " ) ) sc . GetNumber ( shiftleft , true ) ;
}
if ( fn . IsEmpty ( ) )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " basepalette: filename missing " ) ;
2021-04-20 20:43:02 +00:00
}
else if ( offset < 0 )
{
pos . Message ( MSG_ERROR , " basepalette: Invalid file offset " ) ;
}
else if ( ( unsigned ) shiftleft > = 8 )
{
pos . Message ( MSG_ERROR , " basepalette: Invalid left shift %d provided " , shiftleft ) ;
}
else
{
FileReader fil = fileSystem . OpenFileReader ( fn ) ;
if ( ! fil . isOpen ( ) )
{
pos . Message ( MSG_ERROR , " basepalette: Failed opening \" %s \" " , fn . GetChars ( ) ) ;
}
else
{
2021-04-21 15:56:42 +00:00
fil . Seek ( offset , FileReader : : SeekSet ) ;
2021-04-20 20:43:02 +00:00
auto palbuf = fil . Read ( ) ;
if ( palbuf . Size ( ) < 768 )
{
pos . Message ( MSG_ERROR , " basepalette: Read failed " ) ;
}
else
{
if ( shiftleft ! = 0 )
{
2021-12-14 09:15:58 +00:00
for ( auto & pe : palbuf )
pe < < = shiftleft ;
2021-04-20 20:43:02 +00:00
}
paletteSetColorTable ( id , palbuf . Data ( ) , false , false ) ;
return true ;
}
}
}
return false ;
}
void parseBasePalette ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int id ;
bool didLoadPal = false ;
if ( ! sc . GetNumber ( id ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
if ( ( unsigned ) id > = MAXBASEPALS )
{
pos . Message ( MSG_ERROR , " basepalette: Invalid basepal number %d " , id ) ;
sc . RestorePos ( blockend ) ;
sc . CheckString ( " { " ) ;
return ;
}
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " raw " ) ) didLoadPal | = parseBasePaletteRaw ( sc , pos , id ) ;
else if ( sc . Compare ( " copy " ) )
{
int source = - 1 ;
sc . GetNumber ( source ) ;
if ( ( unsigned ) source > = MAXBASEPALS | | source = = id )
{
pos . Message ( MSG_ERROR , " basepalette: Invalid source basepal number %d " , source ) ;
}
else
{
auto sourcepal = GPalette . GetTranslation ( Translation_BasePalettes , source ) ;
if ( sourcepal = = nullptr )
{
pos . Message ( MSG_ERROR , " basepalette: Source basepal %d does not exist " , source ) ;
}
else
{
GPalette . CopyTranslation ( TRANSLATION ( Translation_BasePalettes , id ) , TRANSLATION ( Translation_BasePalettes , source ) ) ;
didLoadPal = true ;
}
}
}
else if ( sc . Compare ( " undef " ) )
{
GPalette . ClearTranslationSlot ( TRANSLATION ( Translation_BasePalettes , id ) ) ;
didLoadPal = 0 ;
if ( id = = 0 ) paletteloaded & = ~ PALETTE_MAIN ;
}
}
if ( didLoadPal & & id = = 0 )
{
paletteloaded | = PALETTE_MAIN ;
}
}
//===========================================================================
//
//
//
//===========================================================================
void parseUndefBasePaletteRange ( FScanner & sc , FScriptPosition & pos )
{
int start , end ;
if ( ! sc . GetNumber ( start ) ) return ;
if ( ! sc . GetNumber ( end ) ) return ;
if ( start > end | | ( unsigned ) start > = MAXBASEPALS | | ( unsigned ) end > = MAXBASEPALS )
{
pos . Message ( MSG_ERROR , " undefbasepaletterange: Invalid range [%d, %d] " , start , end ) ;
return ;
}
for ( int i = start ; i < = end ; i + + ) GPalette . ClearTranslationSlot ( TRANSLATION ( Translation_BasePalettes , i ) ) ;
if ( start = = 0 ) paletteloaded & = ~ PALETTE_MAIN ;
}
2021-04-13 18:33:21 +00:00
//===========================================================================
//
// sadly this looks broken by design with its hard coded 32 shades...
//
//===========================================================================
2021-04-21 15:56:42 +00:00
static void parsePalookupRaw ( FScanner & sc , int id , int & didLoadShade )
2021-04-13 18:33:21 +00:00
{
FScanner : : SavedPos blockend ;
2021-04-21 15:56:42 +00:00
FScriptPosition pos = sc ;
2021-04-13 18:33:21 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
FString fn ;
int32_t offset = 0 ;
int32_t length = 256 * 32 ; // hardcoding 32 instead of numshades
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " file " ) ) sc . GetString ( fn ) ;
else if ( sc . Compare ( " offset " ) ) sc . GetNumber ( offset ) ;
else if ( sc . Compare ( " noshades " ) ) length = 256 ;
}
if ( fn . IsEmpty ( ) )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " palookup: filename missing " ) ;
2021-04-13 18:33:21 +00:00
}
else if ( offset < 0 )
{
pos . Message ( MSG_ERROR , " palookup: Invalid file offset %d " , offset ) ;
}
else
{
FileReader fil = fileSystem . OpenFileReader ( fn ) ;
if ( ! fil . isOpen ( ) )
{
pos . Message ( MSG_ERROR , " palookup: Failed opening \" %s \" " , fn . GetChars ( ) ) ;
}
else
{
2021-04-21 15:56:42 +00:00
fil . Seek ( offset , FileReader : : SeekSet ) ;
2021-04-13 18:33:21 +00:00
auto palookupbuf = fil . Read ( ) ;
if ( palookupbuf . Size ( ) < 256 )
{
pos . Message ( MSG_ERROR , " palookup: Read failed " ) ;
}
else if ( palookupbuf . Size ( ) > = 256 * 32 )
{
didLoadShade = 1 ;
numshades = 32 ;
lookups . setTable ( id , palookupbuf . Data ( ) ) ;
}
else
{
if ( ! ( paletteloaded & PALETTE_SHADE ) )
{
pos . Message ( MSG_ERROR , " palookup: Shade tables not loaded " ) ;
}
else
lookups . makeTable ( id , palookupbuf . Data ( ) , 0 , 0 , 0 , lookups . tables [ id ] . noFloorPal ) ;
}
}
}
}
2021-04-21 15:56:42 +00:00
static void parsePalookupFogpal ( FScanner & sc , int id )
2021-04-13 18:33:21 +00:00
{
FScanner : : SavedPos blockend ;
2021-04-21 15:56:42 +00:00
FScriptPosition pos = sc ;
2021-04-13 18:33:21 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
int red = 0 , green = 0 , blue = 0 ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( { " r " , " red " } ) ) sc . GetNumber ( red ) ;
else if ( sc . Compare ( { " g " , " green " } ) ) sc . GetNumber ( green ) ;
else if ( sc . Compare ( { " b " , " blue " } ) ) sc . GetNumber ( blue ) ;
}
red = clamp ( red , 0 , 255 ) ;
green = clamp ( green , 0 , 255 ) ;
blue = clamp ( blue , 0 , 255 ) ;
if ( ! ( paletteloaded & PALETTE_SHADE ) )
{
pos . Message ( MSG_ERROR , " palookup: Shade tables not loaded " ) ;
}
else
lookups . makeTable ( id , nullptr , red , green , blue , 1 ) ;
}
static void parsePalookupMakePalookup ( FScanner & sc , FScriptPosition & pos , int id , int & didLoadShade )
{
FScanner : : SavedPos blockend ;
if ( sc . StartBraces ( & blockend ) ) return ;
int red = 0 , green = 0 , blue = 0 ;
int remappal = - 1 ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( { " r " , " red " } ) ) sc . GetNumber ( red ) ;
else if ( sc . Compare ( { " g " , " green " } ) ) sc . GetNumber ( green ) ;
else if ( sc . Compare ( { " b " , " blue " } ) ) sc . GetNumber ( blue ) ;
else if ( sc . Compare ( " remappal " ) ) sc . GetNumber ( remappal , true ) ;
else if ( sc . Compare ( " remapself " ) ) remappal = id ;
}
red = clamp ( red , 0 , 255 ) ;
green = clamp ( green , 0 , 255 ) ;
blue = clamp ( blue , 0 , 255 ) ;
if ( ( unsigned ) remappal > = MAXPALOOKUPS )
{
pos . Message ( MSG_ERROR , " palookup: Invalid remappal %d " , remappal ) ;
}
else if ( ! ( paletteloaded & PALETTE_SHADE ) )
{
pos . Message ( MSG_ERROR , " palookup: Shade tables not loaded " ) ;
}
else
lookups . makeTable ( id , nullptr , red , green , blue , lookups . tables [ id ] . noFloorPal ) ;
}
void parsePalookup ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int id ;
int didLoadShade = 0 ;
if ( ! sc . GetNumber ( id , true ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
if ( ( unsigned ) id > = MAXPALOOKUPS )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " palookup: Invalid palette number %d " , id ) ;
2021-04-13 18:33:21 +00:00
sc . RestorePos ( blockend ) ;
return ;
}
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
2021-04-21 15:56:42 +00:00
if ( sc . Compare ( " raw " ) ) parsePalookupRaw ( sc , id , didLoadShade ) ;
else if ( sc . Compare ( " fogpal " ) ) parsePalookupFogpal ( sc , id ) ;
2021-04-13 18:33:21 +00:00
else if ( sc . Compare ( " makepalookup " ) ) parsePalookupMakePalookup ( sc , pos , id , didLoadShade ) ;
else if ( sc . Compare ( " floorpal " ) ) lookups . tables [ id ] . noFloorPal = 0 ;
else if ( sc . Compare ( " nofloorpal " ) ) lookups . tables [ id ] . noFloorPal = 1 ;
else if ( sc . Compare ( " copy " ) )
{
2021-12-07 22:27:12 +00:00
int source = 0 ;
2021-04-13 18:33:21 +00:00
sc . GetNumber ( source , true ) ;
if ( ( unsigned ) source > = MAXPALOOKUPS | | source = = id )
{
pos . Message ( MSG_ERROR , " palookup: Invalid source pal number %d " , source ) ;
}
else if ( source = = 0 & & ! ( paletteloaded & PALETTE_SHADE ) )
{
pos . Message ( MSG_ERROR , " palookup: Shade tables not loaded " ) ;
}
else
{
// do not overwrite the base with an empty table.
if ( lookups . checkTable ( source ) | | id > 0 ) lookups . copyTable ( id , source ) ;
didLoadShade = 1 ;
}
}
else if ( sc . Compare ( " undef " ) )
{
lookups . clearTable ( id ) ;
didLoadShade = 0 ;
if ( id = = 0 ) paletteloaded & = ~ PALETTE_SHADE ;
}
}
if ( didLoadShade & & id = = 0 )
{
paletteloaded | = PALETTE_SHADE ;
}
}
2021-04-13 18:46:33 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseMakePalookup ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int red = 0 , green = 0 , blue = 0 , pal = - 1 ;
2021-04-21 15:56:42 +00:00
int remappal = 0 ;
2021-04-13 18:46:33 +00:00
int nofloorpal = - 1 ;
2021-04-21 15:56:42 +00:00
bool havepal = false , haveremappal = false , haveremapself = false ;
2021-04-13 18:46:33 +00:00
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( { " r " , " red " } ) ) sc . GetNumber ( red ) ;
else if ( sc . Compare ( { " g " , " green " } ) ) sc . GetNumber ( green ) ;
else if ( sc . Compare ( { " b " , " blue " } ) ) sc . GetNumber ( blue ) ;
else if ( sc . Compare ( " remappal " ) )
{
sc . GetNumber ( remappal , true ) ;
2021-04-21 15:56:42 +00:00
haveremappal = true ;
2021-04-13 18:46:33 +00:00
}
else if ( sc . Compare ( " remapself " ) )
{
2021-04-21 15:56:42 +00:00
haveremapself = true ;
2021-04-13 18:46:33 +00:00
}
else if ( sc . Compare ( " nofloorpal " ) ) sc . GetNumber ( nofloorpal , true ) ;
2021-04-20 18:44:22 +00:00
else if ( sc . Compare ( " pal " ) )
{
2021-04-21 15:56:42 +00:00
havepal = true ;
2021-04-20 18:44:22 +00:00
sc . GetNumber ( pal , true ) ;
}
2021-04-13 18:46:33 +00:00
}
red = clamp ( red , 0 , 63 ) ;
green = clamp ( green , 0 , 63 ) ;
blue = clamp ( blue , 0 , 63 ) ;
2021-04-21 15:56:42 +00:00
if ( ! havepal )
2021-04-13 18:46:33 +00:00
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " makepalookup: missing palette number " ) ;
}
else if ( pal = = 0 | | ( unsigned ) pal > = MAXREALPAL )
2021-04-13 18:46:33 +00:00
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " makepalookup: palette number %d out of range (1 .. %d) " , pal , MAXREALPAL - 1 ) ;
2021-04-13 18:46:33 +00:00
}
2021-04-21 15:56:42 +00:00
else if ( haveremappal & & haveremapself )
2021-04-13 18:46:33 +00:00
{
// will also disallow multiple remappals or remapselfs
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " makepalookup: must have either 'remappal' or 'remapself' but not both " ) ;
2021-04-13 18:46:33 +00:00
}
2021-04-21 15:56:42 +00:00
else if ( ( haveremappal & & ( unsigned ) remappal > = MAXREALPAL ) )
2021-04-13 18:46:33 +00:00
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_ERROR , " makepalookup: remap palette number %d out of range (0 .. %d) " , pal , MAXREALPAL - 1 ) ;
2021-04-13 18:46:33 +00:00
}
else
{
2021-04-21 15:56:42 +00:00
if ( haveremapself ) remappal = pal ;
2021-04-13 18:46:33 +00:00
lookups . makeTable ( pal , lookups . getTable ( remappal ) , red < < 2 , green < < 2 , blue < < 2 ,
remappal = = 0 ? 1 : ( nofloorpal = = - 1 ? lookups . tables [ remappal ] . noFloorPal : nofloorpal ) ) ;
}
}
2021-04-13 18:51:19 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseUndefPalookupRange ( FScanner & sc , FScriptPosition & pos )
{
int id0 , id1 ;
if ( ! sc . GetNumber ( id0 , true ) ) return ;
if ( ! sc . GetNumber ( id1 , true ) ) return ;
if ( id0 > id1 | | ( unsigned ) id0 > = MAXPALOOKUPS | | ( unsigned ) id1 > = MAXPALOOKUPS )
{
pos . Message ( MSG_ERROR , " undefpalookuprange: Invalid range " ) ;
}
else
{
for ( int i = id0 ; i < = id1 ; i + + ) lookups . clearTable ( i ) ;
if ( id0 = = 0 ) paletteloaded & = ~ PALETTE_SHADE ;
}
}
2021-04-20 20:43:02 +00:00
//===========================================================================
//
//
//
//===========================================================================
void parseHighpalookup ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
int basepal = - 1 , pal = - 1 ;
FString fn ;
if ( sc . StartBraces ( & blockend ) ) return ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " basepal " ) ) sc . GetNumber ( basepal ) ;
else if ( sc . Compare ( " pal " ) ) sc . GetNumber ( pal ) ;
else if ( sc . Compare ( " file " ) ) sc . GetString ( fn ) ;
}
if ( ( unsigned ) basepal > = MAXBASEPALS )
{
pos . Message ( MSG_ERROR , " highpalookup: invalid base palette number %d " , basepal ) ;
}
2021-04-21 15:56:42 +00:00
else if ( ( unsigned ) pal > = MAXREALPAL )
2021-04-20 20:43:02 +00:00
{
pos . Message ( MSG_ERROR , " highpalookup: invalid palette number %d " , pal ) ;
}
else if ( fn . IsEmpty ( ) )
{
pos . Message ( MSG_ERROR , " highpalookup: missing file name " ) ;
}
else if ( ! fileSystem . FileExists ( fn ) )
{
pos . Message ( MSG_ERROR , " highpalookup: file %s not found " , fn . GetChars ( ) ) ;
}
// todo
}
2021-04-20 21:13:42 +00:00
struct ModelStatics
{
int lastmodelid ;
int modelskin , lastmodelskin ;
int seenframe ;
} mdglobal ;
//===========================================================================
//
//
//
//===========================================================================
void parseDefineModel ( FScanner & sc , FScriptPosition & pos )
{
FString modelfn ;
double scale ;
int shadeoffs ;
if ( ! sc . GetString ( modelfn ) ) return ;
if ( ! sc . GetFloat ( scale , true ) ) return ;
if ( ! sc . GetNumber ( shadeoffs , true ) ) return ;
2022-09-30 14:25:21 +00:00
mdglobal . lastmodelid = modelManager . LoadModel ( modelfn ) ;
2021-04-20 21:13:42 +00:00
if ( mdglobal . lastmodelid < 0 )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_WARNING , " definemodel: unable to load model file '%s' " , modelfn . GetChars ( ) ) ;
2021-04-20 21:13:42 +00:00
}
else
{
2022-09-30 14:25:21 +00:00
modelManager . SetMisc ( mdglobal . lastmodelid , ( float ) scale , shadeoffs , 0.0 , 0.0 , 0 ) ;
2021-04-20 21:13:42 +00:00
mdglobal . modelskin = mdglobal . lastmodelskin = 0 ;
mdglobal . seenframe = 0 ;
}
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineModelFrame ( FScanner & sc , FScriptPosition & pos )
{
FString framename ;
bool ok = true ;
int firsttile , lasttile ;
if ( ! sc . GetString ( framename ) ) return ;
if ( ! sc . GetNumber ( firsttile , true ) ) return ;
if ( ! sc . GetNumber ( lasttile , true ) ) return ;
if ( ! ValidateTileRange ( " definemodelframe " , firsttile , lasttile , pos ) ) return ;
if ( mdglobal . lastmodelid < 0 )
{
pos . Message ( MSG_WARNING , " definemodelframe: Ignoring frame definition outside model. " ) ;
return ;
}
for ( int i = firsttile ; i < = lasttile & & ok ; i + + )
{
2022-09-30 14:25:21 +00:00
int err = ( modelManager . DefineFrame ( mdglobal . lastmodelid , framename , i , max ( 0 , mdglobal . modelskin ) , 0.0f , 0 ) ) ;
2021-04-20 21:13:42 +00:00
if ( err < 0 ) ok = false ;
if ( err = = - 2 ) pos . Message ( MSG_ERROR , " Invalid tile number %d " , i ) ;
2021-10-08 17:06:41 +00:00
else if ( err = = - 3 ) pos . Message ( MSG_ERROR , " Invalid frame name '%s' " , framename . GetChars ( ) ) ;
2021-04-20 21:13:42 +00:00
}
mdglobal . seenframe = 1 ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineModelAnim ( FScanner & sc , FScriptPosition & pos )
{
FString startframe , endframe ;
int32_t flags ;
double dfps ;
if ( ! sc . GetString ( startframe ) ) return ;
if ( ! sc . GetString ( endframe ) ) return ;
if ( ! sc . GetFloat ( dfps , true ) ) return ;
if ( ! sc . GetNumber ( flags , true ) ) return ;
if ( mdglobal . lastmodelid < 0 )
{
pos . Message ( MSG_WARNING , " definemodelframe: Ignoring animation definition outside model. " ) ;
return ;
}
2022-09-30 14:25:21 +00:00
int err = ( modelManager . DefineAnimation ( mdglobal . lastmodelid , startframe , endframe , ( int32_t ) ( dfps * ( 65536.0 * .001 ) ) , flags ) ) ;
2021-04-21 15:56:42 +00:00
if ( err = = - 2 ) pos . Message ( MSG_ERROR , " Invalid start frame name %s " , startframe . GetChars ( ) ) ;
else if ( err = = - 3 ) pos . Message ( MSG_ERROR , " Invalid end frame name %s " , endframe . GetChars ( ) ) ;
2021-04-20 21:13:42 +00:00
}
//===========================================================================
//
//
//
//===========================================================================
void parseDefineModelSkin ( FScanner & sc , FScriptPosition & pos )
{
int palnum ;
FString skinfn ;
if ( ! sc . GetNumber ( palnum , true ) ) return ;
if ( ! sc . GetString ( skinfn ) ) return ;
if ( mdglobal . seenframe ) { mdglobal . modelskin = + + mdglobal . lastmodelskin ; }
mdglobal . seenframe = 0 ;
if ( ! fileSystem . FileExists ( skinfn ) ) return ;
2022-09-30 14:25:21 +00:00
int err = ( modelManager . DefineSkin ( mdglobal . lastmodelid , skinfn , palnum , max ( 0 , mdglobal . modelskin ) , 0 , 0.0f , 1.0f , 1.0f , 0 ) ) ;
2021-04-20 21:13:42 +00:00
if ( err = = - 2 ) pos . Message ( MSG_ERROR , " Invalid skin file name %s " , skinfn . GetChars ( ) ) ;
else if ( err = = - 3 ) pos . Message ( MSG_ERROR , " Invalid palette %d " , palnum ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseSelectModelSkin ( FScanner & sc , FScriptPosition & pos )
{
sc . GetNumber ( mdglobal . modelskin , true ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void parseUndefModel ( FScanner & sc , FScriptPosition & pos )
{
int tile ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! ValidateTilenum ( " undefmodel " , tile , pos ) ) return ;
2022-09-30 14:25:21 +00:00
modelManager . UndefineTile ( tile ) ;
2021-04-20 21:13:42 +00:00
}
void parseUndefModelRange ( FScanner & sc , FScriptPosition & pos )
{
int start , end ;
if ( ! sc . GetNumber ( start , true ) ) return ;
if ( ! sc . GetNumber ( end , true ) ) return ;
if ( ! ValidateTileRange ( " undefmodel " , start , end , pos ) ) return ;
2022-09-30 14:25:21 +00:00
for ( int i = start ; i < = end ; i + + ) modelManager . UndefineTile ( i ) ;
2021-04-20 21:13:42 +00:00
}
void parseUndefModelOf ( FScanner & sc , FScriptPosition & pos )
{
int tile ;
if ( ! sc . GetNumber ( tile , true ) ) return ;
if ( ! ValidateTilenum ( " undefmodelof " , tile , pos ) ) return ;
pos . Message ( MSG_WARNING , " undefmodelof: currently non-functional. " ) ;
}
2021-04-20 22:00:14 +00:00
//===========================================================================
//
//
//
//===========================================================================
static bool parseModelFrameBlock ( FScanner & sc , FixedBitArray < 1024 > & usedframes )
{
FScanner : : SavedPos blockend ;
FScriptPosition pos = sc ;
FString framename ;
bool ok = true ;
int pal = - 1 ;
int starttile = - 1 , endtile = - 1 ;
2021-05-11 23:55:06 +00:00
float smoothduration = 0.1f ;
2021-04-20 22:00:14 +00:00
if ( sc . StartBraces ( & blockend ) ) return false ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " pal " ) ) sc . GetNumber ( pal , true ) ;
else if ( sc . Compare ( { " name " , " frame " } ) ) sc . GetString ( framename ) ;
else if ( sc . Compare ( " tile " ) ) { sc . GetNumber ( starttile , true ) ; endtile = starttile ; }
else if ( sc . Compare ( " tile0 " ) ) sc . GetNumber ( starttile , true ) ;
else if ( sc . Compare ( " tile1 " ) ) sc . GetNumber ( endtile , true ) ;
else if ( sc . Compare ( " smoothduration " ) ) sc . GetFloat ( smoothduration , true ) ;
}
2021-04-21 15:56:42 +00:00
if ( ! ValidateTileRange ( " model/frame " , starttile , endtile , pos ) ) return false ;
2021-04-20 22:00:14 +00:00
if ( smoothduration > 1.0 )
{
pos . Message ( MSG_WARNING , " smoothduration out of range " ) ;
smoothduration = 1.0 ;
}
for ( int i = starttile ; i < = endtile & & ok ; i + + )
{
2022-09-30 14:25:21 +00:00
int res = modelManager . DefineFrame ( mdglobal . lastmodelid , framename , i , max ( 0 , mdglobal . modelskin ) , smoothduration , pal ) ;
2021-04-20 22:00:14 +00:00
if ( res < 0 )
{
ok = false ;
if ( res = = - 2 ) pos . Message ( MSG_WARNING , " Invalid tile number %d " , i ) ;
else if ( res = = - 3 ) pos . Message ( MSG_WARNING , " %s: Invalid frame name " , framename . GetChars ( ) ) ;
}
else if ( res < 1024 ) usedframes . Set ( res ) ;
}
mdglobal . seenframe = 1 ;
return ok ;
}
static bool parseModelAnimBlock ( FScanner & sc )
{
FScanner : : SavedPos blockend ;
FScriptPosition pos = sc ;
FString startframe , endframe ;
int flags = 0 ;
double fps = 1.0 ;
if ( sc . StartBraces ( & blockend ) ) return false ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " frame0 " ) ) sc . GetString ( startframe ) ;
else if ( sc . Compare ( " frame1 " ) ) sc . GetString ( endframe ) ;
else if ( sc . Compare ( " fps " ) ) sc . GetFloat ( fps , true ) ;
else if ( sc . Compare ( " flags " ) ) sc . GetNumber ( flags , true ) ;
}
if ( startframe . IsEmpty ( ) )
{
pos . Message ( MSG_ERROR , " missing start frame for anim definition " ) ;
return false ;
}
if ( endframe . IsEmpty ( ) )
{
pos . Message ( MSG_ERROR , " missing end frame for anim definition " ) ;
return false ;
}
2022-09-30 14:25:21 +00:00
int res = modelManager . DefineAnimation ( mdglobal . lastmodelid , startframe , endframe , ( int ) ( fps * ( 65536.0 * .001 ) ) , flags ) ;
2021-04-20 22:00:14 +00:00
if ( res < 0 )
{
2021-04-21 15:56:42 +00:00
if ( res = = - 2 ) pos . Message ( MSG_ERROR , " Invalid start frame name %s " , startframe . GetChars ( ) ) ;
else if ( res = = - 3 ) pos . Message ( MSG_ERROR , " Invalid end frame name %s " , endframe . GetChars ( ) ) ;
2021-04-20 22:00:14 +00:00
return false ;
}
return true ;
}
2021-04-20 22:46:32 +00:00
static bool parseModelSkinBlock ( FScanner & sc , int pal )
2021-04-20 22:00:14 +00:00
{
FScanner : : SavedPos blockend ;
FScriptPosition pos = sc ;
FString filename ;
2021-04-20 22:46:32 +00:00
int surface = 0 ;
2021-05-11 23:55:06 +00:00
float param = 1.0 , specpower = 1.0 , specfactor = 1.0 ;
2021-04-20 22:00:14 +00:00
int flags = 0 ;
if ( sc . StartBraces ( & blockend ) ) return false ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " pal " ) ) sc . GetNumber ( pal , true ) ;
else if ( sc . Compare ( " file " ) ) sc . GetString ( filename ) ;
else if ( sc . Compare ( { " surface " , " surf " } ) ) sc . GetNumber ( surface , true ) ;
else if ( sc . Compare ( { " intensity " , " scale " , " detailscale " } ) ) sc . GetFloat ( param , true ) ;
else if ( sc . Compare ( { " specpower " , " specularpower " , " parallaxscale " } ) ) sc . GetFloat ( specpower , true ) ;
else if ( sc . Compare ( { " specfactor " , " specularfactor " , " parallaxbias " } ) ) sc . GetFloat ( specfactor , true ) ;
else if ( sc . Compare ( " forcefilter " ) ) { /* not suppoted yet*/ }
}
if ( filename . IsEmpty ( ) )
{
pos . Message ( MSG_ERROR , " missing 'skin filename' for skin definition " ) ;
return false ;
}
if ( mdglobal . seenframe ) mdglobal . modelskin = + + mdglobal . lastmodelskin ;
mdglobal . seenframe = 0 ;
if ( ! fileSystem . FileExists ( filename ) )
{
pos . Message ( MSG_ERROR , " %s: file not found " , filename . GetChars ( ) ) ;
return false ;
}
2021-05-11 23:55:06 +00:00
if ( pal = = DETAILPAL ) param = 1.f / param ;
2022-09-30 14:25:21 +00:00
int res = modelManager . DefineSkin ( mdglobal . lastmodelid , filename , pal , max ( 0 , mdglobal . modelskin ) , surface , param , specpower , specfactor , flags ) ;
2021-04-20 22:00:14 +00:00
if ( res < 0 )
{
if ( res = = - 2 ) pos . Message ( MSG_ERROR , " Invalid skin filename %s " , filename . GetChars ( ) ) ;
else if ( res = = - 3 ) pos . Message ( MSG_ERROR , " Invalid palette number %d " , pal ) ;
return false ;
}
return true ;
}
static bool parseModelHudBlock ( FScanner & sc )
{
FScanner : : SavedPos blockend ;
FScriptPosition pos = sc ;
int starttile = - 1 , endtile = - 1 , flags = 0 , fov = - 1 , angadd = 0 ;
DVector3 add { } ;
if ( sc . StartBraces ( & blockend ) ) return false ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " tile " ) ) { sc . GetNumber ( starttile , true ) ; endtile = starttile ; }
else if ( sc . Compare ( " tile0 " ) ) sc . GetNumber ( starttile , true ) ;
else if ( sc . Compare ( " tile1 " ) ) sc . GetNumber ( endtile , true ) ;
else if ( sc . Compare ( " xadd " ) ) sc . GetFloat ( add . X , true ) ;
else if ( sc . Compare ( " yadd " ) ) sc . GetFloat ( add . Y , true ) ;
else if ( sc . Compare ( " zadd " ) ) sc . GetFloat ( add . Z , true ) ;
else if ( sc . Compare ( " angadd " ) ) sc . GetNumber ( angadd , true ) ;
else if ( sc . Compare ( " fov " ) ) sc . GetNumber ( fov , true ) ;
else if ( sc . Compare ( " hide " ) ) flags | = HUDFLAG_HIDE ;
else if ( sc . Compare ( " nobob " ) ) flags | = HUDFLAG_NOBOB ;
else if ( sc . Compare ( " flipped " ) ) flags | = HUDFLAG_FLIPPED ;
else if ( sc . Compare ( " nodepth " ) ) flags | = HUDFLAG_NODEPTH ;
}
if ( ! ValidateTileRange ( " hud " , starttile , endtile , pos ) ) return false ;
for ( int i = starttile ; i < = endtile ; i + + )
{
2021-12-14 08:58:01 +00:00
FVector3 addf = { ( float ) add . X , ( float ) add . Y , ( float ) add . Z } ;
2022-09-30 14:25:21 +00:00
int res = modelManager . DefineHud ( mdglobal . lastmodelid , i , addf , angadd , flags , fov ) ;
2021-04-20 22:00:14 +00:00
if ( res < 0 )
{
if ( res = = - 2 ) pos . Message ( MSG_ERROR , " Invalid tile number %d " , i ) ;
return false ;
}
}
return true ;
}
void parseModel ( FScanner & sc , FScriptPosition & pos )
{
FScanner : : SavedPos blockend ;
FString modelfn ;
double scale = 1.0 , mzadd = 0.0 , myoffset = 0.0 ;
2021-11-14 14:03:50 +00:00
int32_t shadeoffs = 0 , flags = 0 ;
2021-04-20 22:00:14 +00:00
FixedBitArray < 1024 > usedframes ;
usedframes . Zero ( ) ;
mdglobal . modelskin = mdglobal . lastmodelskin = 0 ;
mdglobal . seenframe = 0 ;
if ( ! sc . GetString ( modelfn ) ) return ;
if ( sc . StartBraces ( & blockend ) ) return ;
2022-09-30 14:25:21 +00:00
mdglobal . lastmodelid = modelManager . LoadModel ( modelfn ) ;
2021-04-20 22:00:14 +00:00
if ( mdglobal . lastmodelid < 0 )
{
2021-04-21 15:56:42 +00:00
pos . Message ( MSG_WARNING , " Unable to load model file '%s' " , modelfn . GetChars ( ) ) ;
2021-04-20 22:00:14 +00:00
sc . RestorePos ( blockend ) ;
sc . CheckString ( " } " ) ;
return ;
}
bool ok = true ;
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " scale " ) ) sc . GetFloat ( scale , true ) ;
else if ( sc . Compare ( " shade " ) ) sc . GetNumber ( shadeoffs , true ) ;
else if ( sc . Compare ( " zadd " ) ) sc . GetFloat ( mzadd , true ) ;
else if ( sc . Compare ( " yoffset " ) ) sc . GetFloat ( myoffset , true ) ;
else if ( sc . Compare ( " frame " ) ) ok & = parseModelFrameBlock ( sc , usedframes ) ;
else if ( sc . Compare ( " anim " ) ) ok & = parseModelAnimBlock ( sc ) ;
else if ( sc . Compare ( " skin " ) ) ok & = parseModelSkinBlock ( sc , 0 ) ;
else if ( sc . Compare ( " detail " ) ) ok & = parseModelSkinBlock ( sc , DETAILPAL ) ;
else if ( sc . Compare ( " glow " ) ) ok & = parseModelSkinBlock ( sc , GLOWPAL ) ;
else if ( sc . Compare ( " specular " ) ) ok & = parseModelSkinBlock ( sc , SPECULARPAL ) ;
else if ( sc . Compare ( " normal " ) ) ok & = parseModelSkinBlock ( sc , NORMALPAL ) ;
else if ( sc . Compare ( " hud " ) ) ok & = parseModelHudBlock ( sc ) ;
else if ( sc . Compare ( " flags " ) ) sc . GetNumber ( flags , true ) ;
}
if ( ! ok )
{
if ( mdglobal . lastmodelid > = 0 )
{
pos . Message ( MSG_ERROR , " Removing model %d due to errors. " , mdglobal . lastmodelid ) ;
2022-09-30 14:25:21 +00:00
modelManager . UndefineModel ( mdglobal . lastmodelid ) ;
2021-04-20 22:00:14 +00:00
}
}
else
{
2022-09-30 14:25:21 +00:00
modelManager . SetMisc ( mdglobal . lastmodelid , ( float ) scale , shadeoffs , ( float ) mzadd , ( float ) myoffset , flags ) ;
2021-04-20 22:00:14 +00:00
mdglobal . modelskin = mdglobal . lastmodelskin = 0 ;
mdglobal . seenframe = 0 ;
}
}
2021-04-20 22:46:32 +00:00
2021-08-22 23:00:30 +00:00
//===========================================================================
//
//
//
//===========================================================================
2021-11-14 21:52:20 +00:00
static bool parseDefineQAVInterpolateIgnoreBlock ( FScanner & sc , const int res_id , TMap < int , TArray < int > > & ignoredata , const int numframes )
2021-08-22 23:00:30 +00:00
{
FScanner : : SavedPos blockend ;
FScriptPosition pos = sc ;
FString scframes , sctiles ;
TArray < int > framearray , tilearray ;
if ( sc . StartBraces ( & blockend ) )
{
2021-08-26 00:33:24 +00:00
pos . Message ( MSG_ERROR , " defineqav (%d): interpolate: ignore: malformed syntax, unable to continue " , res_id ) ;
2021-08-22 23:00:30 +00:00
return false ;
}
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . GetString ( ) ;
if ( sc . Compare ( " frames " ) ) sc . GetString ( scframes ) ;
else if ( sc . Compare ( " tiles " ) ) sc . GetString ( sctiles ) ;
}
// Confirm we received something for 'frames' and 'tiles'.
if ( scframes . IsEmpty ( ) | | sctiles . IsEmpty ( ) )
{
2021-08-26 00:33:24 +00:00
pos . Message ( MSG_ERROR , " defineqav (%d): interpolate: ignore: unable to get any values for 'frames' or 'tiles', unable to continue " , res_id ) ;
2021-08-22 23:00:30 +00:00
return false ;
}
2021-11-14 21:52:20 +00:00
auto arraybuilder = [ & ] ( const FString & input , TArray < int > & output , const int maxvalue ) - > bool
2021-08-22 23:00:30 +00:00
{
2021-08-23 05:05:38 +00:00
if ( input . CompareNoCase ( " all " ) = = 0 )
2021-08-22 23:00:30 +00:00
{
2021-08-23 05:05:38 +00:00
// All indices from 0 through to maxvalue are to be added to output array.
output . Push ( 0 ) ;
output . Push ( maxvalue ) ;
}
else if ( input . IndexOf ( " - " ) ! = - 1 )
{
// Input is a range of values, split on the hypthen and add each value to the output array.
2021-08-22 23:00:30 +00:00
auto temparray = input . Split ( " - " ) ;
2021-08-23 05:34:14 +00:00
if ( temparray . Size ( ) = = 2 )
{
// Test if keywords 'first' and 'last' have been used.'
output . Push ( temparray [ 0 ] . CompareNoCase ( " first " ) = = 0 ? 0 : atoi ( temparray [ 0 ] ) ) ;
output . Push ( temparray [ 1 ] . CompareNoCase ( " last " ) = = 0 ? maxvalue : atoi ( temparray [ 1 ] ) ) ;
}
2021-08-22 23:00:30 +00:00
}
else
{
2021-08-23 05:05:38 +00:00
// We just have a number. Convert the string into an int and push it twice to the output array.
2021-08-22 23:00:30 +00:00
auto tempvalue = atoi ( input ) ;
for ( auto i = 0 ; i < 2 ; i + + ) output . Push ( tempvalue ) ;
}
2021-08-23 05:05:38 +00:00
if ( output . Size ( ) ! = 2 | | output [ 0 ] > output [ 1 ] | | output [ 0 ] < 0 | | output [ 1 ] > maxvalue )
2021-08-22 23:00:30 +00:00
{
pos . Message ( MSG_ERROR , " defineqav (%d): interpolate: ignore: value of '%s' is malformed, unable to continue " , res_id , input . GetChars ( ) ) ;
return false ;
}
return true ;
} ;
if ( ! arraybuilder ( scframes , framearray , numframes - 1 ) ) return false ;
if ( ! arraybuilder ( sctiles , tilearray , 7 ) ) return false ;
// Process arrays and add ignored frames as required.
for ( auto i = framearray [ 0 ] ; i < = framearray [ 1 ] ; i + + )
{
auto & frametiles = ignoredata [ i ] ;
for ( auto j = tilearray [ 0 ] ; j < = tilearray [ 1 ] ; j + + )
{
if ( ! frametiles . Contains ( j ) ) frametiles . Push ( j ) ;
}
}
return true ;
}
2021-11-14 21:52:20 +00:00
static bool parseDefineQAVInterpolateBlock ( FScanner & sc , const int res_id , const int numframes )
2021-08-22 23:00:30 +00:00
{
FScanner : : SavedPos blockend ;
FScriptPosition pos = sc ;
FString interptype ;
bool loopable = false ;
TMap < int , TArray < int > > ignoredata ;
if ( sc . StartBraces ( & blockend ) )
{
2021-08-26 00:33:24 +00:00
pos . Message ( MSG_ERROR , " defineqav (%d): interpolate: malformed syntax, unable to continue " , res_id ) ;
2021-08-22 23:00:30 +00:00
return false ;
}
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . GetString ( ) ;
if ( sc . Compare ( " type " ) )
{
2021-08-23 04:19:33 +00:00
if ( interptype . IsNotEmpty ( ) )
{
2021-08-26 00:33:24 +00:00
pos . Message ( MSG_ERROR , " defineqav (%d): interpolate: more than one interpolation type defined, unable to continue " , res_id ) ;
2021-08-23 04:19:33 +00:00
return false ;
}
2021-08-22 23:00:30 +00:00
sc . GetString ( interptype ) ;
if ( ! gi - > IsQAVInterpTypeValid ( interptype ) )
{
2021-08-26 00:33:24 +00:00
pos . Message ( MSG_ERROR , " defineqav (%d): interpolate: interpolation type not found " , res_id ) ;
2021-08-22 23:00:30 +00:00
return false ;
}
}
else if ( sc . Compare ( " loopable " ) ) loopable = true ;
else if ( sc . Compare ( " ignore " ) ) if ( ! parseDefineQAVInterpolateIgnoreBlock ( sc , res_id , ignoredata , numframes ) ) return false ;
}
// Add interpolation properties to game for processing while drawing.
2021-11-14 21:52:20 +00:00
gi - > AddQAVInterpProps ( res_id , interptype , loopable , std : : move ( ignoredata ) ) ;
2021-08-22 23:00:30 +00:00
return true ;
}
2021-11-14 21:52:20 +00:00
static void parseDefineQAV ( FScanner & sc , FScriptPosition & pos )
2021-08-22 23:00:30 +00:00
{
FScanner : : SavedPos blockend ;
FString fn ;
int res_id = - 1 ;
int numframes = - 1 ;
bool interpolate = false ;
if ( ! sc . GetNumber ( res_id , true ) )
{
pos . Message ( MSG_ERROR , " defineqav: invalid or non-defined resource ID " ) ;
return ;
}
if ( sc . StartBraces ( & blockend ) )
{
pos . Message ( MSG_ERROR , " defineqav (%d): malformed syntax, unable to continue " , res_id ) ;
return ;
}
while ( ! sc . FoundEndBrace ( blockend ) )
{
sc . MustGetString ( ) ;
if ( sc . Compare ( " file " ) )
{
2021-08-23 04:19:33 +00:00
if ( fn . IsNotEmpty ( ) )
{
pos . Message ( MSG_ERROR , " defineqav (%d): more than one file defined, unable to continue " , res_id ) ;
return ;
}
2021-08-22 23:00:30 +00:00
sc . GetString ( fn ) ;
// Test file's validity.
FixPathSeperator ( fn ) ;
auto lump = fileSystem . FindFile ( fn ) ;
if ( lump < 0 )
{
pos . Message ( MSG_ERROR , " defineqav (%d): file '%s' could not be found " , res_id , fn . GetChars ( ) ) ;
return ;
}
// Read file to get number of frames from QAV, skipping first 8 bytes.
auto fr = fileSystem . OpenFileReader ( lump ) ;
fr . ReadUInt64 ( ) ;
numframes = fr . ReadInt32 ( ) ;
}
else if ( sc . Compare ( " interpolate " ) )
{
2021-08-23 04:19:33 +00:00
if ( interpolate )
{
pos . Message ( MSG_ERROR , " defineqav (%d): more than one interpolate block defined, unable to continue " , res_id ) ;
return ;
}
2021-08-22 23:00:30 +00:00
interpolate = true ;
if ( ! parseDefineQAVInterpolateBlock ( sc , res_id , numframes ) ) return ;
}
}
// If we're not interpolating, remove any reference to interpolation data for this res_id.
if ( ! interpolate ) gi - > RemoveQAVInterpProps ( res_id ) ;
// Add new file to filesystem.
fileSystem . CreatePathlessCopy ( fn , res_id , 0 ) ;
}
2022-11-25 15:52:08 +00:00
static void parseTileFlags ( FScanner & sc , FScriptPosition & pos )
{
int num = - 1 ;
sc . SetCMode ( true ) ;
sc . GetNumber ( num , true ) ;
if ( ! sc . CheckString ( " { " ) )
{
pos . Message ( MSG_ERROR , " tileflags:'{' expected, unable to continue " ) ;
sc . SetCMode ( false ) ;
return ;
}
while ( ! sc . CheckString ( " } " ) )
{
sc . MustGetString ( ) ;
int tile = TileFiles . tileForName ( sc . String ) ;
if ( tile = = - 1 )
{
pos . Message ( MSG_ERROR , " tileflags:Unknown tile name '%s' " , sc . String ) ;
}
else
{
TileFiles . tiledata [ tile ] . tileflags | = num ;
}
}
sc . SetCMode ( false ) ;
}
2021-04-20 22:46:32 +00:00
//===========================================================================
//
//
//
//===========================================================================
struct dispatch
{
const char * text ;
void ( * handler ) ( FScanner & sc , FScriptPosition & pos ) ;
} ;
static const dispatch basetokens [ ] =
{
{ " include " , parseInclude } ,
{ " #include " , parseInclude } ,
{ " includedefault " , parseIncludeDefault } ,
{ " #includedefault " , parseIncludeDefault } ,
{ " define " , parseDefine } ,
{ " #define " , parseDefine } ,
// deprecated style
{ " definetexture " , parseDefineTexture } ,
{ " defineskybox " , parseDefineSkybox } ,
{ " definetint " , parseDefineTint } ,
{ " definemodel " , parseDefineModel } ,
{ " definemodelframe " , parseDefineModelFrame } ,
{ " definemodelanim " , parseDefineModelAnim } ,
{ " definemodelskin " , parseDefineModelSkin } ,
{ " selectmodelskin " , parseSelectModelSkin } ,
{ " definevoxel " , parseDefineVoxel } ,
{ " definevoxeltiles " , parseDefineVoxelTiles } ,
// new style
{ " model " , parseModel } ,
{ " voxel " , parseVoxel } ,
{ " skybox " , parseSkybox } ,
{ " highpalookup " , parseHighpalookup } ,
{ " tint " , parseTint } ,
{ " makepalookup " , parseMakePalookup } ,
{ " texture " , parseTexture } ,
{ " tile " , parseTexture } ,
{ " music " , parseMusic } ,
2021-04-21 15:56:42 +00:00
{ " sound " , parseEmptyBlock } ,
2021-04-20 22:46:32 +00:00
{ " animsounds " , parseEmptyBlockWithParm } ,
{ " cutscene " , parseEmptyBlockWithParm } ,
{ " nofloorpalrange " , parseNoFloorpalRange } ,
{ " texhitscanrange " , parseTexHitscanRange } ,
{ " nofullbrightrange " , parseNoFullbrightRange } ,
// other stuff
{ " undefmodel " , parseUndefModel } ,
{ " undefmodelrange " , parseUndefModelRange } ,
{ " undefmodelof " , parseUndefModelOf } ,
{ " undeftexture " , parseUndefTexture } ,
{ " undeftexturerange " , parseUndefTextureRange } ,
{ " alphahack " , parseAlphahack } ,
{ " alphahackrange " , parseAlphahackRange } ,
2021-04-21 16:34:34 +00:00
{ " spritecol " , parseSkip < 3 > } ,
2021-04-20 22:46:32 +00:00
{ " 2dcol " , parseSkip < 4 > } ,
2021-04-21 16:34:34 +00:00
{ " 2dcolidxrange " , parseSkip < 3 > } ,
2021-04-20 22:46:32 +00:00
{ " fogpal " , parseFogpal } ,
{ " loadgrp " , parseSkip < 1 > } ,
2021-04-21 16:34:34 +00:00
{ " dummytile " , parseDummyTile } ,
2021-04-20 22:46:32 +00:00
{ " dummytilerange " , parseDummyTileRange } ,
{ " setuptile " , parseSetupTile } ,
{ " setuptilerange " , parseSetupTileRange } ,
{ " undefinetile " , parseUndefineTile } ,
{ " undefinetilerange " , parseUndefineTileRange } ,
{ " animtilerange " , parseAnimTileRange } ,
2021-04-21 16:34:34 +00:00
{ " cachesize " , parseSkip < 1 > } ,
2021-04-20 22:46:32 +00:00
{ " dummytilefrompic " , parseImportTile } ,
{ " tilefromtexture " , parseTileFromTexture } ,
{ " artfile " , parseArtFile } ,
{ " mapinfo " , parseMapinfo } ,
{ " echo " , parseEcho } ,
{ " globalflags " , parseSkip < 1 > } ,
{ " copytile " , parseCopyTile } ,
{ " globalgameflags " , parseSkip < 1 > } ,
{ " multipsky " , parseMultiPsky } ,
{ " basepalette " , parseBasePalette } ,
{ " palookup " , parsePalookup } ,
{ " blendtable " , parseBlendTable } ,
{ " numalphatables " , parseNumAlphaTabs } ,
{ " undefbasepaletterange " , parseUndefBasePaletteRange } ,
{ " undefpalookuprange " , parseUndefPalookupRange } ,
{ " undefblendtablerange " , parseSkip < 2 > } ,
{ " shadefactor " , parseSkip < 1 > } ,
{ " newgamechoices " , parseEmptyBlock } ,
{ " rffdefineid " , parseRffDefineId } ,
2021-08-22 23:00:30 +00:00
{ " defineqav " , parseDefineQAV } ,
2022-01-26 22:53:05 +00:00
2022-11-25 15:52:08 +00:00
{ " tileflag " , parseTileFlags } ,
2021-07-11 07:16:26 +00:00
{ nullptr , nullptr } ,
2021-04-20 22:46:32 +00:00
} ;
static void defsparser ( FScanner & sc )
{
int iter = 0 ;
sc . SetNoFatalErrors ( true ) ;
sc . SetNoOctals ( true ) ;
while ( 1 )
{
if ( + + iter > = 50 )
{
Printf ( " . " ) ;
iter = 0 ;
}
FScriptPosition pos = sc ;
if ( ! sc . GetString ( ) ) return ;
int index = sc . MustMatchString ( & basetokens [ 0 ] . text , sizeof ( basetokens [ 0 ] ) ) ;
if ( index ! = - 1 ) basetokens [ index ] . handler ( sc , pos ) ;
}
}
2021-06-09 06:38:40 +00:00
void loaddefinitionsfile ( const char * fn , bool cumulative , bool maingame )
2021-04-20 22:46:32 +00:00
{
bool done = false ;
auto parseit = [ & ] ( int lump )
{
FScanner sc ;
sc . OpenLumpNum ( lump ) ;
defsparser ( sc ) ;
done = true ;
Printf ( PRINT_NONOTIFY , " \n " ) ;
} ;
2021-04-22 08:50:49 +00:00
cycle_t deftimer ;
deftimer . Reset ( ) ;
auto printtimer = [ & ] ( const char * fn )
{
deftimer . Unclock ( ) ;
DPrintf ( DMSG_SPAMMY , " Definitions file \" %s \" loaded, %f ms. \n " , fn , deftimer . TimeMS ( ) ) ;
2021-04-22 08:57:41 +00:00
deftimer . Reset ( ) ;
2021-04-22 08:50:49 +00:00
} ;
2021-04-20 22:46:32 +00:00
if ( ! cumulative )
{
int lump = fileSystem . FindFile ( fn ) ;
if ( lump > = 0 )
{
Printf ( PRINT_NONOTIFY , " Loading \" %s \" \n " , fn ) ;
2021-04-22 08:57:41 +00:00
deftimer . Clock ( ) ;
2021-04-20 22:46:32 +00:00
parseit ( lump ) ;
2021-04-22 08:50:49 +00:00
printtimer ( fn ) ;
2021-04-20 22:46:32 +00:00
}
}
else
{
int lump , lastlump = 0 ;
while ( ( lump = fileSystem . FindLumpFullName ( fn , & lastlump ) ) > = 0 )
{
2021-06-09 06:38:40 +00:00
if ( maingame & & fileSystem . GetFileContainer ( lump ) > fileSystem . GetMaxIwadNum ( ) ) break ;
2021-04-20 22:46:32 +00:00
Printf ( PRINT_NONOTIFY , " Loading \" %s \" \n " , fileSystem . GetFileFullPath ( lump ) . GetChars ( ) ) ;
2021-04-22 08:57:41 +00:00
deftimer . Clock ( ) ;
2021-04-20 22:46:32 +00:00
parseit ( lump ) ;
2021-04-22 08:50:49 +00:00
printtimer ( fn ) ;
2021-04-20 22:46:32 +00:00
}
}
}