Files
Wolf3D-iOS/wolf3d/wolfextractor/wolf/wolf_map.c

693 lines
13 KiB
C

/*
Copyright (C) 2004-2005 Michael Liebscher
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* wolf_map.c: Decode Wolfenstein 3-D Map data.
*
* Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
* Date: 2004
*
* Acknowledgement:
* This code was derived from Wolfenstein 3-D, and was originally
* written by Id Software, Inc.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "wolf_def.h"
#include "../string/com_string.h"
#include "../loaders/tga.h"
#include "../filesys/file.h"
#include "../../../common/arch.h"
#include "../memory/memory.h"
#include "../../../common/common_utils.h"
#define MAPHEADNAME "MAPHEAD"
#define MAPNAME "GAMEMAPS"
PRIVATE FILE *maphandle;
PRIVATE W32 headeroffsets[ 100 ];
PRIVATE W32 TotalMaps;
PRIVATE W16 RLEWtag;
PRIVATE W16 gameversion;
PRIVATE const W32 vgaCeilingWL6[] =
{
0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xbfbf,
0x4e4e,0x4e4e,0x4e4e,0x1d1d,0x8d8d,0x4e4e,0x1d1d,0x2d2d,0x1d1d,0x8d8d,
0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x1d1d,0x2d2d,0xdddd,0x1d1d,0x1d1d,0x9898,
0x1d1d,0x9d9d,0x2d2d,0xdddd,0xdddd,0x9d9d,0x2d2d,0x4d4d,0x1d1d,0xdddd,
0x7d7d,0x1d1d,0x2d2d,0x2d2d,0xdddd,0xd7d7,0x1d1d,0x1d1d,0x1d1d,0x2d2d,
0x1d1d,0x1d1d,0x1d1d,0x1d1d,0xdddd,0xdddd,0x7d7d,0xdddd,0xdddd,0xdddd
};
PRIVATE const W32 vgaCeilingSOD[] =
{
0x6f6f,0x4f4f,0x1d1d,0xdede,0xdfdf,0x2e2e,0x7f7f,0x9e9e,0xaeae,0x7f7f,
0x1d1d,0xdede,0xdfdf,0xdede,0xdfdf,0xdede,0xe1e1,0xdcdc,0x2e2e,0x1d1d,0xdcdc
};
PRIVATE W32 WL6_songs[] =
{
//
// Episode One
//
GETTHEM_MUS,
SEARCHN_MUS,
POW_MUS,
SUSPENSE_MUS,
GETTHEM_MUS,
SEARCHN_MUS,
POW_MUS,
SUSPENSE_MUS,
WARMARCH_MUS, // Boss level
CORNER_MUS, // Secret level
//
// Episode Two
//
NAZI_OMI_MUS,
PREGNANT_MUS,
GOINGAFT_MUS,
HEADACHE_MUS,
NAZI_OMI_MUS,
PREGNANT_MUS,
HEADACHE_MUS,
GOINGAFT_MUS,
WARMARCH_MUS, // Boss level
DUNGEON_MUS, // Secret level
//
// Episode Three
//
INTROCW3_MUS,
NAZI_RAP_MUS,
TWELFTH_MUS,
ZEROHOUR_MUS,
INTROCW3_MUS,
NAZI_RAP_MUS,
TWELFTH_MUS,
ZEROHOUR_MUS,
ULTIMATE_MUS, // Boss level
PACMAN_MUS, // Secret level
//
// Episode Four
//
GETTHEM_MUS,
SEARCHN_MUS,
POW_MUS,
SUSPENSE_MUS,
GETTHEM_MUS,
SEARCHN_MUS,
POW_MUS,
SUSPENSE_MUS,
WARMARCH_MUS, // Boss level
CORNER_MUS, // Secret level
//
// Episode Five
//
NAZI_OMI_MUS,
PREGNANT_MUS,
GOINGAFT_MUS,
HEADACHE_MUS,
NAZI_OMI_MUS,
PREGNANT_MUS,
HEADACHE_MUS,
GOINGAFT_MUS,
WARMARCH_MUS, // Boss level
DUNGEON_MUS, // Secret level
//
// Episode Six
//
INTROCW3_MUS,
NAZI_RAP_MUS,
TWELFTH_MUS,
ZEROHOUR_MUS,
INTROCW3_MUS,
NAZI_RAP_MUS,
TWELFTH_MUS,
ZEROHOUR_MUS,
ULTIMATE_MUS, // Boss level
FUNKYOU_MUS // Secret level
};
PRIVATE W32 SOD_songs[] =
{
SOD_XTIPTOE_MUS,
SOD_XFUNKIE_MUS,
SOD_XDEATH_MUS,
SOD_XGETYOU_MUS, // DON'T KNOW
SOD_ULTIMATE_MUS, // Trans Grosse
SOD_DUNGEON_MUS,
SOD_GOINGAFT_MUS,
SOD_POW_MUS,
SOD_TWELFTH_MUS,
SOD_ULTIMATE_MUS, // Barnacle Wilhelm BOSS
SOD_NAZI_OMI_MUS,
SOD_GETTHEM_MUS,
SOD_SUSPENSE_MUS,
SOD_SEARCHN_MUS,
SOD_ZEROHOUR_MUS,
SOD_ULTIMATE_MUS, // Super Mutant BOSS
SOD_XPUTIT_MUS,
SOD_ULTIMATE_MUS, // Death Knight BOSS
SOD_XJAZNAZI_MUS, // Secret level
SOD_XFUNKIE_MUS, // Secret level (DON'T KNOW)
SOD_XEVIL_MUS // Angel of Death BOSS
};
typedef struct
{
float time;
char timestr[ 6 ];
} times;
PRIVATE times parTimesWL6[] =
{
//
// Episode One Par Times
//
{ 1.5, "01:30" },
{ 2, "02:00" },
{ 2, "02:00" },
{ 3.5, "03:30" },
{ 3, "03:00" },
{ 3, "03:00" },
{ 2.5, "02:30" },
{ 2.5, "02:30" },
{ 0, "??:??" }, // Boss level
{ 0, "??:??" }, // Secret level
//
// Episode Two Par Times
//
{ 1.5, "01:30" },
{ 3.5, "03:30" },
{ 3, "03:00" },
{ 2, "02:00" },
{ 4, "04:00" },
{ 6, "06:00" },
{ 1, "01:00" },
{ 3, "03:00" },
{ 0, "??:??" },
{ 0, "??:??" },
//
// Episode Three Par Times
//
{ 1.5, "01:30" },
{ 1.5, "01:30" },
{ 2.5, "02:30" },
{ 2.5, "02:30" },
{ 3.5, "03:30" },
{ 2.5, "02:30" },
{ 2, "02:00" },
{ 6, "06:00" },
{ 0, "??:??" },
{ 0, "??:??" },
//
// Episode Four Par Times
//
{ 2, "02:00" },
{ 2, "02:00" },
{ 1.5, "01:30" },
{ 1, "01:00" },
{ 4.5, "04:30" },
{ 3.5, "03:30" },
{ 2, "02:00" },
{ 4.5, "04:30" },
{ 0, "??:??" },
{ 0, "??:??" },
//
// Episode Five Par Times
//
{ 2.5, "02:30" },
{ 1.5, "01:30" },
{ 2.5, "02:30" },
{ 2.5, "02:30" },
{ 4, "04:00" },
{ 3, "03:00" },
{ 4.5, "04:30" },
{ 3.5, "03:30" },
{ 0, "??:??" },
{ 0, "??:??" },
//
// Episode Six Par Times
//
{ 6.5, "06:30" },
{ 4, "04:00" },
{ 4.5, "04:30" },
{ 6, "06:00" },
{ 5, "05:00" },
{ 5.5, "05:30" },
{ 5.5, "05:30" },
{ 8.5, "08:30" },
{ 0, "??:??" },
{ 0, "??:??" }
};
PRIVATE times parTimesSOD[] =
{
//
// SPEAR OF DESTINY TIMES
//
{ 1.5, "01:30" },
{ 3.5, "03:30" },
{ 2.75,"02:45" },
{ 3.5, "03:30" },
{ 0, "??:??" }, // Boss 1
{ 4.5, "04:30" },
{ 3.25,"03:15" },
{ 2.75,"02:45" },
{ 4.75,"04:45" },
{ 0, "??:??" }, // Boss 2
{ 6.5, "06:30" },
{ 4.5, "04:30" },
{ 2.75,"02:45" },
{ 4.5, "04:30" },
{ 6, "06:00" },
{ 0, "??:??" }, // Boss 3
{ 6, "06:00" },
{ 0, "??:??" }, // Boss 4
{ 0, "??:??" }, // Secret level 1
{ 0, "??:??" }, // Secret level 2
};
/*
-----------------------------------------------------------------------------
Function: CAL_SetupMapFile -Setup map files for decoding.
Parameters: extension -[in] file extension for map data files.
Returns: Non-zero on success, zero otherwise.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE W8 CAL_SetupMapFile( const char *extension )
{
FILE *handle;
SW32 length;
char fname[ 13 ];
//
// load maphead.xxx (offsets and tileinfo for map file)
//
cs_strlcpy( fname, MAPHEADNAME, sizeof( fname ) );
cs_strlcat( fname, extension, sizeof( fname ) );
handle = fopen( cs_strupr( fname ), "rb" );
if( handle == NULL )
{
handle = fopen( cs_strlwr( fname ), "rb" );
if( handle == NULL )
{
printf( "Could not open file (%s) for read!\n", fname );
return 0;
}
}
length = FS_FileLength( handle );
fread( &RLEWtag, 2, 1, handle );
for( TotalMaps = 0 ; TotalMaps < length ; ++TotalMaps )
{
fread( &headeroffsets[ TotalMaps ], 4, 1, handle );
if( ! headeroffsets[ TotalMaps ] )
{
break;
}
}
fclose( handle );
cs_strlcpy( fname, MAPNAME, sizeof( fname ) );
cs_strlcat( fname, extension, sizeof( fname ) );
maphandle = fopen( cs_strupr( fname ), "rb");
if( NULL == maphandle )
{
maphandle = fopen( cs_strlwr( fname ), "rb");
if( NULL == maphandle )
{
return 0;
}
}
return 1;
}
/*
-----------------------------------------------------------------------------
Function: CAL_ShutdownMapFile -Shutdown map file.
Parameters: Nothing.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE void CAL_ShutdownMapFile( void )
{
if( maphandle )
{
fclose( maphandle );
}
}
/*
-----------------------------------------------------------------------------
Function: CA_CacheMap -Cache and save map data.
Parameters:
ChunkOffset -[in] Chunk offset.
Chunklength -[in] Length of chunk.
filename -[in] File name to save map as.
index -[in] File name index number.
Returns: Non-zero on success, otherwise zero.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE W8 CA_CacheMap( W32 ChunkOffset, W32 Chunklength, const char *filename, W32 index )
{
W32 offset[ 3 ];
W32 offsetin[ 3 ];
W32 temp;
W16 length[ 3 ];
W8 sig[ 5 ];
W16 w, h;
W8 *data;
W32 ceiling;
W32 floor;
FILE *fout;
float ftime;
char *stime;
char name[ 32 ];
char musicName[ 64 ];
extern char gamepal[];
SW32 jmp;
if( gameversion == SOD_PAK )
{
temp = (vgaCeilingSOD[ index ] & 0xff) * 3;
ceiling = ( (gamepal[ temp ] << 2) << 16 ) | ( (gamepal[ temp+1 ] << 2 ) << 8) | (gamepal[ temp+2 ]<<2);
temp = 0x19 * 3;
floor = ( (gamepal[ temp ] << 2) << 16 ) | ( (gamepal[ temp+1 ] << 2 ) << 8) | (gamepal[ temp+2 ]<<2);
ftime = parTimesSOD[ index ].time;
stime = parTimesSOD[ index ].timestr;
cs_snprintf( musicName, sizeof( musicName ), "music/%s.ogg", GetMusicFileName_SOD( SOD_songs[ index ] ) );
}
else
{
temp = (vgaCeilingWL6[ index ] & 0xff) * 3;
ceiling = ( (gamepal[ temp ] << 2) << 16 ) | ( (gamepal[ temp+1 ] << 2 ) << 8) | (gamepal[ temp+2 ]<<2);
temp = 0x19 * 3;
floor = ( (gamepal[ temp ] << 2) << 16 ) | ( (gamepal[ temp+1 ] << 2 ) << 8) | (gamepal[ temp+2 ]<<2);
ftime = parTimesWL6[ index ].time;
stime = parTimesWL6[ index ].timestr;
cs_snprintf( musicName, sizeof( musicName ), "music/%s.ogg", GetMusicFileName_WL6( WL6_songs[ index ] ) );
}
fout = fopen( filename, "wb");
if( NULL == fout )
{
return 0;
}
fseek( maphandle, ChunkOffset, SEEK_SET );
fread( &offsetin, sizeof( W32 ), 3, maphandle );
fread( &length, sizeof( W16 ), 3, maphandle );
fread( &w, sizeof( W16 ), 1, maphandle );
fread( &h, sizeof( W16 ), 1, maphandle );
fread( name, sizeof( W8 ), 16, maphandle );
fread( sig, sizeof( W8 ), 4, maphandle );
//
// Output header
//
// Map file header signature
fwrite( sig, sizeof( W8 ), 4, fout );
// RLE Word tag
fwrite( &RLEWtag, sizeof( W16 ), 1, fout );
// Max Width
fwrite( &w, sizeof( W16 ), 1, fout );
// Max Height
fwrite( &h, sizeof( W16 ), 1, fout );
// Ceiling Colour
fwrite( &ceiling, sizeof( W32 ), 1, fout );
// Floor Colour
fwrite( &floor, sizeof( W32 ), 1, fout );
// Length of layers
temp = length[ 0 ];
fwrite( &temp, sizeof( W16 ), 1, fout ); // Length One
temp = length[ 1 ];
fwrite( &temp, sizeof( W16 ), 1, fout ); // Length Two
temp = length[ 2 ];
fwrite( &temp, sizeof( W16 ), 1, fout ); // Length Three
jmp = ftell( fout );
temp = 0;
fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset One
fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Two
fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Three
// Map name length
temp = strlen( name );
fwrite( &temp, sizeof( W16 ), 1, fout );
// Music name length
temp = strlen( musicName );
fwrite( &temp, sizeof( W16 ), 1, fout );
// Par time Float
fwrite( &ftime, sizeof( float ), 1, fout );
// Par time string
fwrite( stime, sizeof( W8 ), 5 , fout );
// Map name
fwrite( name, sizeof( W8 ), strlen( name ), fout );
// Music file name
fwrite( musicName, sizeof( W8 ), strlen( musicName ), fout );
data = MM_MALLOC( length[ 0 ] );
if( data == NULL )
{
return 0;
}
offset[ 0 ] = ftell( fout );
fseek( maphandle, offsetin[ 0 ], SEEK_SET );
fread( data, 1, length[ 0 ], maphandle );
fwrite( data, 1, length[ 0 ], fout );
data = MM_REALLOC( data, length[ 1 ] );
if( data == NULL )
{
return 0;
}
offset[ 1 ] = ftell( fout );
fseek( maphandle, offsetin[ 1 ], SEEK_SET );
fread( data, 1, length[ 1 ], maphandle );
fwrite( data, 1, length[ 1 ], fout );
data = MM_REALLOC( data, length[ 2 ] );
if( data == NULL )
{
return 0;
}
offset[ 2 ] = ftell( fout );
fseek( maphandle, offsetin[ 2 ], SEEK_SET );
fread( data, 1, length[ 2 ], maphandle );
fwrite( data, 1, length[ 2 ], fout );
MM_FREE( data );
fseek( fout, jmp, SEEK_SET );
temp = offset[ 0 ];
fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset One
temp = offset[ 1 ];
fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Two
temp = offset[ 2 ];
fwrite( &temp, sizeof( W32 ), 1, fout ); // Offset Three
fclose( fout );
return 1;
}
/*
-----------------------------------------------------------------------------
Function: MapRipper -Re-encode map data.
Parameters: extension -[in] file extension for map data files.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC _boolean MapRipper( const char *fextension, W16 version )
{
W32 i;
char fname[ 32 ];
gameversion = version;
//
// Setup
//
if( 0 == FS_Mkdir( MAPDIR ) )
{
printf( "[%s] Could not create directory (%s)!\n", "wolf_map.c", MAPDIR );
return false;
}
if( ! CAL_SetupMapFile( fextension ) )
{
CAL_ShutdownMapFile();
return false;
}
//
// Decode Map data
//
printf( "Decoding Map Data...\n" );
for( i = 0 ; i < TotalMaps ; ++i )
{
cs_snprintf( fname, sizeof( fname ), "%s/%c%.2d.map", MAPDIR, TOLOWER( fextension[ 1 ] ), i );
CA_CacheMap( headeroffsets[ i ],
headeroffsets[ i + 1 ] - headeroffsets[ i ],
fname, i );
}
//
// Shutdown
//
CAL_ShutdownMapFile();
return true;
}