mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
1301 lines
27 KiB
C++
1301 lines
27 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
OpenMoHAA source code 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.
|
|
|
|
OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// tiki_parse.cpp : TIKI Parser
|
|
|
|
#include "q_shared.h"
|
|
#include "qcommon.h"
|
|
#include "../server/server.h"
|
|
#include "../skeletor/skeletor.h"
|
|
#include <tiki.h>
|
|
|
|
/*
|
|
===============
|
|
TIKI_FileExtension
|
|
===============
|
|
*/
|
|
const char *TIKI_FileExtension( const char *in )
|
|
{
|
|
static char exten[ 8 ];
|
|
int i;
|
|
|
|
for( i = 0; in[ i ] != 0; i++ )
|
|
{
|
|
if( in[ i ] == '.' )
|
|
{
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !in[ i ] )
|
|
{
|
|
return "";
|
|
}
|
|
|
|
strncpy( exten, &in[ i ], sizeof( exten ) );
|
|
return exten;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseFrameCommands
|
|
===============
|
|
*/
|
|
void TIKI_ParseFrameCommands( dloaddef_t *ld, dloadframecmd_t **cmdlist, int maxcmds, int *numcmds )
|
|
{
|
|
qboolean usecurrentframe = false;
|
|
const char *token;
|
|
dloadframecmd_t *cmds;
|
|
int framenum = 0;
|
|
int i;
|
|
char *pszArgs[ 256 ];
|
|
|
|
ld->tikiFile.GetToken( true );
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "}" ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( *numcmds < maxcmds )
|
|
{
|
|
cmds = ( dloadframecmd_t * )TIKI_AllocateLoadData( sizeof( dloadframecmd_t ) );
|
|
cmdlist[ *numcmds ] = cmds;
|
|
if( !cmds )
|
|
{
|
|
TIKI_Error( "TIKI_ParseFrameCommands: could not allocate storage for dloadframecmd_t in %s on line %d.\n", ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
continue;
|
|
}
|
|
|
|
cmds->num_args = 0;
|
|
( *numcmds )++;
|
|
|
|
if( !stricmp( token, "start" ) || !stricmp( token, "first" ) )
|
|
{
|
|
framenum = TIKI_FRAME_FIRST;
|
|
}
|
|
else if( !stricmp( token, "end" ) )
|
|
{
|
|
framenum = TIKI_FRAME_END;
|
|
}
|
|
else if( !stricmp( token, "last" ) )
|
|
{
|
|
framenum = TIKI_FRAME_LAST;
|
|
}
|
|
else if( !stricmp( token, "every" ) )
|
|
{
|
|
framenum = TIKI_FRAME_EVERY;
|
|
}
|
|
else if( !stricmp( token, "exit" ) )
|
|
{
|
|
framenum = TIKI_FRAME_EXIT;
|
|
}
|
|
else if( !stricmp( token, "entry" ) || !stricmp( token, "enter" ) )
|
|
{
|
|
framenum = TIKI_FRAME_ENTRY;
|
|
}
|
|
else if( !stricmp( token, "(" ) )
|
|
{
|
|
usecurrentframe = true;
|
|
ld->tikiFile.UnGetToken();
|
|
}
|
|
else if( !stricmp( token, ")" ) )
|
|
{
|
|
usecurrentframe = false;
|
|
ld->tikiFile.UnGetToken();
|
|
}
|
|
else if( !usecurrentframe )
|
|
{
|
|
framenum = atoi( token );
|
|
}
|
|
else
|
|
{
|
|
ld->tikiFile.UnGetToken();
|
|
}
|
|
|
|
if( framenum < TIKI_FRAME_LAST )
|
|
{
|
|
TIKI_Error( "TIKI_ParseFrameCommands: illegal frame number %d on line %d in %s\n", framenum, ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
ld->tikiFile.GetToken( false );
|
|
( *numcmds )--;
|
|
continue;
|
|
}
|
|
|
|
cmds->frame_num = framenum;
|
|
if( ld->tikiFile.currentScript )
|
|
{
|
|
sprintf( cmds->location, "%s, line: %d", ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
}
|
|
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
|
|
if( cmds->num_args > 255 )
|
|
{
|
|
TIKI_Error( "TIKI_ParseFrameCommands: too many args in anim commands in %s.\n", ld->tikiFile.Filename() );
|
|
continue;
|
|
}
|
|
|
|
pszArgs[ cmds->num_args ] = TIKI_CopyString( token );
|
|
cmds->num_args++;
|
|
}
|
|
|
|
cmds->args = ( char ** )TIKI_AllocateLoadData( cmds->num_args * sizeof( char * ) );
|
|
for( i = 0; i < cmds->num_args; i++ )
|
|
cmds->args[ i ] = pszArgs[ i ];
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseFrameCommands: too many anim commands in %s starting on line %i.\n", ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
ld->tikiFile.GetToken( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseAnimationCommands
|
|
===============
|
|
*/
|
|
void TIKI_ParseAnimationCommands( dloaddef_t *ld, dloadanim_t *anim )
|
|
{
|
|
const char *token;
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "client" ) )
|
|
{
|
|
TIKI_ParseFrameCommands( ld, anim->loadclientcmds, sizeof( anim->loadclientcmds ) / sizeof( anim->loadclientcmds[ 0 ] ), &anim->num_client_cmds );
|
|
}
|
|
else if( !stricmp( token, "server" ) )
|
|
{
|
|
TIKI_ParseFrameCommands( ld, anim->loadservercmds, sizeof( anim->loadservercmds ) / sizeof( anim->loadservercmds[ 0 ] ), &anim->num_server_cmds );
|
|
}
|
|
else if( !stricmp( token, "}" ) )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseAnimationCommands: unknown anim command '%s' in '%s' on line %d, skipping line.\n", token, ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
token = ld->tikiFile.GetToken( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseAnimationFlags
|
|
===============
|
|
*/
|
|
void TIKI_ParseAnimationFlags( dloaddef_t *ld, dloadanim_t *anim )
|
|
{
|
|
const char *token;
|
|
|
|
anim->weight = 1.0f;
|
|
anim->blendtime = 0.2f;
|
|
anim->flags = 0;
|
|
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
|
|
if( !stricmp( token, "weight" ) )
|
|
{
|
|
anim->weight = ld->tikiFile.GetFloat( false );
|
|
anim->flags |= TAF_RANDOM;
|
|
}
|
|
else if( !stricmp( token, "deltadriven" ) )
|
|
{
|
|
anim->flags |= TAF_DELTADRIVEN;
|
|
}
|
|
else if( !stricmp( token, "default_angles" ) )
|
|
{
|
|
anim->flags |= TAF_DEFAULT_ANGLES;
|
|
}
|
|
else if( !stricmp( token, "notimecheck" ) )
|
|
{
|
|
anim->flags |= TAF_NOTIMECHECK;
|
|
}
|
|
else if( !stricmp( token, "crossblend" ) )
|
|
{
|
|
anim->blendtime = ld->tikiFile.GetFloat( false );
|
|
}
|
|
else if( !stricmp( token, "dontrepeate" ) )
|
|
{
|
|
anim->flags |= TAF_NOREPEAT;
|
|
}
|
|
else if( !stricmp( token, "random" ) )
|
|
{
|
|
anim->flags |= TAF_RANDOM;
|
|
}
|
|
else if( !stricmp( token, "autosteps_run" ) )
|
|
{
|
|
anim->flags |= TAF_AUTOSTEPS_RUN;
|
|
}
|
|
else if( !stricmp( token, "autosteps_walk" ) )
|
|
{
|
|
anim->flags |= TAF_AUTOSTEPS_WALK;
|
|
}
|
|
else if( !stricmp( token, "autosteps_dog" ) )
|
|
{
|
|
anim->flags |= TAF_AUTOSTEPS_DOG;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "Unknown Animation flag %s for anim '%s' in %s\n", token, anim->alias, TikiScript::currentScript->Filename() );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseAnimationsFail
|
|
===============
|
|
*/
|
|
void TIKI_ParseAnimationsFail( dloaddef_t *ld )
|
|
{
|
|
int nestcount = 0;
|
|
const char *token;
|
|
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
{
|
|
ld->tikiFile.GetToken( false );
|
|
}
|
|
|
|
if( !ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( stricmp( token, "{" ) )
|
|
{
|
|
ld->tikiFile.UnGetToken();
|
|
return;
|
|
}
|
|
|
|
ld->tikiFile.UnGetToken();
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "{" ) )
|
|
{
|
|
nestcount++;
|
|
}
|
|
else if( !stricmp( token, "}" ) )
|
|
{
|
|
nestcount--;
|
|
if( !nestcount )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseIncludes
|
|
===============
|
|
*/
|
|
qboolean TIKI_ParseIncludes( dloaddef_t *ld )
|
|
{
|
|
const char* token;
|
|
qboolean b_incl = false;
|
|
const char* mapname;
|
|
const char* servertype;
|
|
int depth = 0;
|
|
|
|
static cvar_t* pServerType = Cvar_Get("g_servertype", "2", 0);
|
|
static cvar_t* pGameType = Cvar_Get("cg_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH);
|
|
|
|
if (pGameType->integer && pServerType->integer == 1) {
|
|
servertype = "spearheadserver";
|
|
}
|
|
else {
|
|
servertype = "breakthroughserver";
|
|
}
|
|
|
|
token = ld->tikiFile.GetToken(true);
|
|
if (sv_mapname)
|
|
{
|
|
mapname = sv_mapname->string;
|
|
}
|
|
else
|
|
{
|
|
mapname = "utils";
|
|
}
|
|
|
|
while (1)
|
|
{
|
|
if (!strncmp(token, mapname, strlen(token))
|
|
|| !strncmp(token, servertype, strlen(token)))
|
|
{
|
|
b_incl = true;
|
|
}
|
|
else if ((!stricmp(token, "{") || !ld->tikiFile.TokenAvailable(true)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
token = ld->tikiFile.GetToken(true);
|
|
}
|
|
|
|
if (b_incl)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
while (ld->tikiFile.TokenAvailable(true))
|
|
{
|
|
token = ld->tikiFile.GetAndIgnoreLine(false);
|
|
if (strstr(token, "{"))
|
|
{
|
|
depth++;
|
|
}
|
|
|
|
if (strstr(token, "}"))
|
|
{
|
|
if (!depth)
|
|
{
|
|
break;
|
|
}
|
|
|
|
depth--;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseAnimations
|
|
===============
|
|
*/
|
|
void TIKI_ParseAnimations( dloaddef_t *ld )
|
|
{
|
|
const char *token;
|
|
dloadanim_t *anim;
|
|
qboolean b_mapspec = false;
|
|
const char *mapname;
|
|
size_t depth = 0;
|
|
|
|
ld->tikiFile.GetToken( true );
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "}" ) )
|
|
{
|
|
return;
|
|
}
|
|
else if( !stricmp( token, "$mapspec" ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( sv_mapname )
|
|
{
|
|
mapname = sv_mapname->string;
|
|
}
|
|
else
|
|
{
|
|
mapname = "utils";
|
|
}
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
if( !strncmp( token, mapname, strlen( token ) ) )
|
|
{
|
|
b_mapspec = true;
|
|
}
|
|
else if( !stricmp(token, "{" ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
token = ld->tikiFile.GetToken( true );
|
|
}
|
|
|
|
if( !b_mapspec )
|
|
{
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( strstr( token, "{" ) )
|
|
{
|
|
depth++;
|
|
}
|
|
|
|
if( strstr( token, "}" ) )
|
|
{
|
|
if( !depth )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
depth--;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( ld->numanims > 4094 )
|
|
{
|
|
TIKI_Error( "TIKI_ParseAnimations: Too many animations in '%s'.\n", ld->path );
|
|
continue;
|
|
}
|
|
|
|
anim = ( dloadanim_t * )TIKI_AllocateLoadData( sizeof( dloadanim_t ) );
|
|
ld->loadanims[ ld->numanims ] = anim;
|
|
if( !anim )
|
|
{
|
|
TIKI_Error( "TIKI_ParseAnimations: Could not allocate storage for anim alias name %s in %s.\n", token, ld->tikiFile.Filename() );
|
|
TIKI_ParseAnimationsFail( ld );
|
|
continue;
|
|
}
|
|
|
|
depth = strlen( token );
|
|
if( depth < 48 )
|
|
{
|
|
anim->alias = ( char * )TIKI_CopyString( token );
|
|
|
|
token = ld->tikiFile.GetToken( false );
|
|
strcpy( anim->name, TikiScript::currentScript->path );
|
|
strcat( anim->name, token );
|
|
|
|
anim->location[ 0 ] = 0;
|
|
if( ld->tikiFile.currentScript )
|
|
{
|
|
sprintf( anim->location, "%s, line: %d", ld->tikiFile.currentScript->Filename(), ld->tikiFile.currentScript->GetLineNumber() );
|
|
}
|
|
|
|
anim->num_client_cmds = 0;
|
|
anim->num_server_cmds = 0;
|
|
TIKI_ParseAnimationFlags( ld, anim );
|
|
ld->numanims++;
|
|
|
|
if( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "{" ) )
|
|
{
|
|
TIKI_ParseAnimationCommands( ld, anim );
|
|
}
|
|
else
|
|
{
|
|
ld->tikiFile.UnGetToken();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseAnimations: Anim alias name %s is too long in %s.\n", token, ld->tikiFile.Filename() );
|
|
TIKI_ParseAnimationsFail( ld );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseSurfaceFlag
|
|
===============
|
|
*/
|
|
int TIKI_ParseSurfaceFlag( const char *token )
|
|
{
|
|
int flags = 0;
|
|
|
|
if( !stricmp( token, "skin1" ) )
|
|
{
|
|
flags = TIKI_SURF_SKIN1;
|
|
}
|
|
else if( !stricmp( token, "skin2" ) )
|
|
{
|
|
flags = TIKI_SURF_SKIN2;
|
|
}
|
|
else if( !stricmp( token, "skin3" ) )
|
|
{
|
|
flags = TIKI_SURF_SKIN3;
|
|
}
|
|
else if( !stricmp( token, "nodraw" ) )
|
|
{
|
|
flags = TIKI_SURF_NODRAW;
|
|
}
|
|
else if( !stricmp( token, "nodamage" ) )
|
|
{
|
|
flags = TIKI_SURF_NODAMAGE;
|
|
}
|
|
else if( !stricmp( token, "crossfade" ) )
|
|
{
|
|
flags = TIKI_SURF_CROSSFADE;
|
|
}
|
|
else if( !stricmp( token, "nomipmaps" ) )
|
|
{
|
|
flags = TIKI_SURF_NOMIPMAPS;
|
|
}
|
|
else if( !stricmp( token, "nopicmip" ) )
|
|
{
|
|
flags = TIKI_SURF_NOPICMIP;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "Unknown surface flag %s\n", token );
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteScale
|
|
===============
|
|
*/
|
|
static void WriteScale( dloaddef_t *ld, float scale )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 0 );
|
|
MSG_WriteFloat( ld->modelBuf, scale );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteLoadScale
|
|
===============
|
|
*/
|
|
static void WriteLoadScale( dloaddef_t *ld, float lod_scale )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 1 );
|
|
MSG_WriteFloat( ld->modelBuf, lod_scale );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteLodBias
|
|
===============
|
|
*/
|
|
static void WriteLodBias( dloaddef_t *ld, float lod_bias )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 2 );
|
|
MSG_WriteFloat( ld->modelBuf, lod_bias );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteSkelmodel
|
|
===============
|
|
*/
|
|
static void WriteSkelmodel( dloaddef_t *ld, const char *name )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 3 );
|
|
MSG_WriteString( ld->modelBuf, name );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteOrigin
|
|
===============
|
|
*/
|
|
static void WriteOrigin( dloaddef_t *ld, float origin_x, float origin_y, float origin_z )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 4 );
|
|
MSG_WriteFloat( ld->modelBuf, origin_x );
|
|
MSG_WriteFloat( ld->modelBuf, origin_y );
|
|
MSG_WriteFloat( ld->modelBuf, origin_z );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteLightOffset
|
|
===============
|
|
*/
|
|
static void WriteLightOffset( dloaddef_t *ld, float light_offset_x, float light_offset_y, float light_offset_z )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 5 );
|
|
MSG_WriteFloat( ld->modelBuf, light_offset_x );
|
|
MSG_WriteFloat( ld->modelBuf, light_offset_y );
|
|
MSG_WriteFloat( ld->modelBuf, light_offset_z );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteRadius
|
|
===============
|
|
*/
|
|
static void WriteRadius( dloaddef_t *ld, float radius )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 6 );
|
|
MSG_WriteFloat( ld->modelBuf, radius );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteSurface
|
|
===============
|
|
*/
|
|
static void WriteSurface( dloaddef_t *ld, const char *surface )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 7 );
|
|
MSG_WriteString( ld->modelBuf, surface );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteFlags
|
|
===============
|
|
*/
|
|
static void WriteFlags( dloaddef_t *ld, int flags )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 8 );
|
|
MSG_WriteLong( ld->modelBuf, flags );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteDamage
|
|
===============
|
|
*/
|
|
static void WriteDamage( dloaddef_t *ld, float damage )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 9 );
|
|
MSG_WriteFloat( ld->modelBuf, damage );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteShader
|
|
===============
|
|
*/
|
|
static void WriteShader( dloaddef_t *ld, const char *shader )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 10 );
|
|
MSG_WriteString( ld->modelBuf, shader );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteBeginCase
|
|
===============
|
|
*/
|
|
static void WriteBeginCase( dloaddef_t *ld )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 13 );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteCaseKey
|
|
===============
|
|
*/
|
|
static void WriteCaseKey( dloaddef_t *ld, const char *key )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 11 );
|
|
MSG_WriteString( ld->modelBuf, key );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteCaseValue
|
|
===============
|
|
*/
|
|
static void WriteCaseValue( dloaddef_t *ld, const char *value )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 12 );
|
|
MSG_WriteString( ld->modelBuf, value );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteBeginCaseBody
|
|
===============
|
|
*/
|
|
static void WriteBeginCaseBody( dloaddef_t *ld )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 14 );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
WriteEndCase
|
|
===============
|
|
*/
|
|
static void WriteEndCase( dloaddef_t *ld )
|
|
{
|
|
MSG_WriteByte( ld->modelBuf, 15 );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_InitSetup
|
|
===============
|
|
*/
|
|
void TIKI_InitSetup( dloaddef_t *ld )
|
|
{
|
|
MSG_Init( ld->modelBuf, ld->modelData, 8192 );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_LoadSetupCaseHeader
|
|
===============
|
|
*/
|
|
qboolean TIKI_LoadSetupCaseHeader( dtiki_t *tiki, const char *filename, dloadsurface_t *loadsurfaces, int *numSurfacesSetUp, msg_t *msg, qboolean skip, con_map<str, str> *keyValues )
|
|
{
|
|
int c = 0;
|
|
str key;
|
|
str *val;
|
|
const char *value;
|
|
qboolean match = false;
|
|
|
|
while( c != 14 )
|
|
{
|
|
c = MSG_ReadByte( msg );
|
|
switch( c )
|
|
{
|
|
case 11:
|
|
value = MSG_ReadString( msg );
|
|
key = value;
|
|
break;
|
|
case 12:
|
|
value = MSG_ReadString( msg );
|
|
if( skip || match || !keyValues )
|
|
break;
|
|
|
|
val = keyValues->find( key );
|
|
if( val && !stricmp( key.c_str(), val->c_str() ) )
|
|
{
|
|
match = true;
|
|
}
|
|
break;
|
|
case 14:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return TIKI_LoadSetupCase( tiki, filename, loadsurfaces, numSurfacesSetUp, msg, skip || !match, keyValues );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_LoadSetupCase
|
|
===============
|
|
*/
|
|
qboolean TIKI_LoadSetupCase( dtiki_t *tiki, const char *filename, dloadsurface_t *loadsurfaces, int *numSurfacesSetUp, msg_t *msg, qboolean skip, con_map<str, str> *keyValues )
|
|
{
|
|
int c;
|
|
const char *name;
|
|
int currentSurface = -1;
|
|
int mesh;
|
|
skelHeaderGame_t *skelmodel;
|
|
float load_scale;
|
|
float lod_scale;
|
|
float lod_bias;
|
|
float load_origin[ 3 ];
|
|
float light_offset[ 3 ];
|
|
float radius;
|
|
int flags;
|
|
float damage_multiplier;
|
|
|
|
while( 1 )
|
|
{
|
|
c = MSG_ReadByte( msg ) + 1;
|
|
switch( c )
|
|
{
|
|
default:
|
|
break;
|
|
case 1:
|
|
load_scale = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
tiki->load_scale = load_scale;
|
|
break;
|
|
case 2:
|
|
lod_scale = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
tiki->lod_scale = lod_scale;
|
|
break;
|
|
case 3:
|
|
lod_bias = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
tiki->lod_bias = lod_bias;
|
|
break;
|
|
case 4:
|
|
name = MSG_ReadString( msg );
|
|
if( skip )
|
|
break;
|
|
|
|
if( tiki->numMeshes >= 12 )
|
|
{
|
|
TIKI_Error( "^~^~^ TIKI_LoadSetup: too many skelmodels in %s.\n", filename );
|
|
return false;
|
|
}
|
|
|
|
mesh = TIKI_RegisterSkel( name, tiki );
|
|
if( mesh < 0 )
|
|
return false;
|
|
|
|
tiki->mesh[ tiki->numMeshes ] = mesh;
|
|
skelmodel = TIKI_GetSkel( mesh );
|
|
tiki->num_surfaces += skelmodel->numSurfaces;
|
|
tiki->numMeshes++;
|
|
break;
|
|
case 5:
|
|
load_origin[ 0 ] = MSG_ReadFloat( msg );
|
|
load_origin[ 1 ] = MSG_ReadFloat( msg );
|
|
load_origin[ 2 ] = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
VectorCopy( load_origin, tiki->load_origin );
|
|
break;
|
|
case 6:
|
|
light_offset[ 0 ] = MSG_ReadFloat( msg );
|
|
light_offset[ 1 ] = MSG_ReadFloat( msg );
|
|
light_offset[ 2 ] = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
VectorCopy( light_offset, tiki->load_origin );
|
|
break;
|
|
case 7:
|
|
radius = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
tiki->radius = radius;
|
|
break;
|
|
case 8:
|
|
name = MSG_ReadString( msg );
|
|
if( skip )
|
|
break;
|
|
|
|
for( currentSurface = 0; currentSurface < *numSurfacesSetUp; currentSurface++ )
|
|
{
|
|
if( !stricmp( loadsurfaces[ currentSurface ].name, name ) )
|
|
break;
|
|
}
|
|
|
|
if( currentSurface == *numSurfacesSetUp )
|
|
{
|
|
loadsurfaces[ currentSurface ].flags = 0;
|
|
( *numSurfacesSetUp )++;
|
|
}
|
|
strcpy( loadsurfaces[ currentSurface ].name, name );
|
|
break;
|
|
case 9:
|
|
flags = MSG_ReadLong( msg );
|
|
if( skip )
|
|
break;
|
|
loadsurfaces[ currentSurface ].flags |= flags;
|
|
break;
|
|
case 10:
|
|
damage_multiplier = MSG_ReadFloat( msg );
|
|
if( skip )
|
|
break;
|
|
loadsurfaces[ currentSurface ].damage_multiplier = damage_multiplier;
|
|
break;
|
|
case 11:
|
|
name = MSG_ReadString( msg );
|
|
if( skip )
|
|
break;
|
|
|
|
if( loadsurfaces[ currentSurface ].numskins > 3 )
|
|
{
|
|
TIKI_Error( "TIKI_ParseSetup: Too many skins defined for surface %s in %s.\n", loadsurfaces[ currentSurface ].name, filename );
|
|
break;
|
|
}
|
|
|
|
strncpy( loadsurfaces[ currentSurface ].shader[ loadsurfaces[ currentSurface ].numskins ], name, sizeof( loadsurfaces[ currentSurface ].shader[ loadsurfaces[ currentSurface ].numskins ] ) );
|
|
loadsurfaces[ currentSurface ].numskins++;
|
|
break;
|
|
case 14:
|
|
if( !TIKI_LoadSetupCaseHeader( tiki, filename, loadsurfaces, numSurfacesSetUp, msg, skip, keyValues ) )
|
|
return false;
|
|
break;
|
|
case 0:
|
|
case 16:
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_LoadSetup
|
|
===============
|
|
*/
|
|
qboolean TIKI_LoadSetup( dtiki_t *tiki, const char *filename, dloadsurface_t *loadsurfaces, int *numSurfacesSetUp, byte *modelData, size_t modelDataSize, con_map<str, str> *keyValues )
|
|
{
|
|
msg_t msg;
|
|
|
|
MSG_Init( &msg, modelData, modelDataSize );
|
|
msg.cursize = modelDataSize;
|
|
MSG_BeginReading( &msg );
|
|
|
|
memset( tiki, 0, sizeof( dtiki_t ) );
|
|
memset( loadsurfaces, 0, sizeof( dloadsurface_t ) * 24 );
|
|
*numSurfacesSetUp = 0;
|
|
|
|
VectorCopy( vec3_origin, tiki->load_origin );
|
|
VectorCopy( vec3_origin, tiki->light_offset );
|
|
tiki->load_scale = 1.0f;
|
|
tiki->lod_scale = 1.0f;
|
|
tiki->lod_bias = 0.0f;
|
|
tiki->numMeshes = 0;
|
|
|
|
return TIKI_LoadSetupCase( tiki, filename, loadsurfaces, numSurfacesSetUp, &msg, false, keyValues );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_strstr
|
|
===============
|
|
*/
|
|
bool TIKI_strstr( const char *s, const char *substring )
|
|
{
|
|
const char *t = strstr( s, substring );
|
|
const char *w;
|
|
|
|
if( !t || ( t != s && *( t - 1 ) != '\n' ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
w = strstr( t, "\n" );
|
|
if( w != ( t + strlen( substring ) ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseSetup
|
|
===============
|
|
*/
|
|
qboolean TIKI_ParseSetup( dloaddef_t *ld )
|
|
{
|
|
const char *token;
|
|
float load_scale;
|
|
float lod_scale;
|
|
float lod_bias;
|
|
float tmpFloat;
|
|
float tmpVec[ 3 ];
|
|
int tmpInt;
|
|
size_t length;
|
|
char name[ 128 ];
|
|
|
|
// Skip the setup token
|
|
ld->tikiFile.GetToken( true );
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
|
|
if( !stricmp( token, "scale" ) )
|
|
{
|
|
load_scale = ld->tikiFile.GetFloat( false );
|
|
WriteScale( ld, load_scale );
|
|
}
|
|
else if( !stricmp( token, "lod_scale" ) )
|
|
{
|
|
lod_scale = ld->tikiFile.GetFloat( false ) / 5.0f;
|
|
WriteLoadScale( ld, lod_scale );
|
|
}
|
|
else if( !stricmp( token, "lod_bias" ) )
|
|
{
|
|
lod_bias = ld->tikiFile.GetFloat( false );
|
|
WriteLodBias( ld, lod_bias );
|
|
}
|
|
else if( !stricmp( token, "skelmodel" ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
strcpy( name, ld->tikiFile.currentScript->path );
|
|
strcat( name, token );
|
|
WriteSkelmodel( ld, name );
|
|
}
|
|
else if( !stricmp( token, "path" ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
strcpy( ld->tikiFile.currentScript->path, token );
|
|
length = strlen( ld->tikiFile.currentScript->path );
|
|
token = ld->tikiFile.currentScript->path + length - 1;
|
|
|
|
if( *token != '/' && *token != '\\' )
|
|
{
|
|
strcat( ld->tikiFile.currentScript->path, "/" );
|
|
}
|
|
}
|
|
else if( !stricmp( token, "orgin" ) )
|
|
{
|
|
tmpVec[ 0 ] = ld->tikiFile.GetFloat( false );
|
|
tmpVec[ 1 ] = ld->tikiFile.GetFloat( false );
|
|
tmpVec[ 2 ] = ld->tikiFile.GetFloat( false );
|
|
WriteOrigin( ld, tmpVec[ 0 ], tmpVec[ 1 ], tmpVec[ 2 ] );
|
|
}
|
|
else if( !stricmp( token, "lightoffset" ) )
|
|
{
|
|
tmpVec[ 0 ] = ld->tikiFile.GetFloat( false );
|
|
tmpVec[ 1 ] = ld->tikiFile.GetFloat( false );
|
|
tmpVec[ 2 ] = ld->tikiFile.GetFloat( false );
|
|
WriteLightOffset( ld, tmpVec[ 0 ], tmpVec[ 1 ], tmpVec[ 2 ] );
|
|
}
|
|
else if( !stricmp( token, "radius" ) )
|
|
{
|
|
tmpFloat = ld->tikiFile.GetFloat( false );
|
|
WriteRadius( ld, tmpFloat );
|
|
}
|
|
else if( !stricmp( token, "surface" ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
WriteSurface( ld, token );
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
if( !stricmp( token, "flags" ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
tmpInt = TIKI_ParseSurfaceFlag( token );
|
|
WriteFlags( ld, tmpInt );
|
|
}
|
|
else if( !stricmp( token, "damage" ) )
|
|
{
|
|
tmpFloat = ld->tikiFile.GetFloat( false );
|
|
WriteDamage( ld, tmpFloat );
|
|
}
|
|
else if( !stricmp( token, "shader" ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
if( strstr( token, "." ) )
|
|
{
|
|
strcpy( name, ld->tikiFile.currentScript->path );
|
|
strcat( name, token );
|
|
WriteShader( ld, name );
|
|
}
|
|
else
|
|
{
|
|
WriteShader( ld, token );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( !stricmp( token, "ischaracter" ) )
|
|
{
|
|
ld->bIsCharacter = true;
|
|
}
|
|
else if( !stricmp( token, "case" ) )
|
|
{
|
|
if( !TIKI_ParseCase( ld ) )
|
|
return false;
|
|
}
|
|
else if( !stricmp( token, "}" ) )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseSetup: unknown setup command '%s' in '%s' on line %d, skipping line.\n", token, ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
ld->tikiFile.GetToken( false );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseInitCommands
|
|
===============
|
|
*/
|
|
void TIKI_ParseInitCommands( dloaddef_t *ld, dloadinitcmd_t **cmdlist, int maxcmds, int *numcmds )
|
|
{
|
|
int i;
|
|
const char *token;
|
|
char *pszArgs[ 256 ];
|
|
dloadinitcmd_t *cmd;
|
|
|
|
// Skip current token
|
|
ld->tikiFile.GetToken( true );
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
|
|
if( !stricmp( token, "}" ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( *numcmds < maxcmds )
|
|
{
|
|
cmd = ( dloadinitcmd_t * )TIKI_AllocateLoadData( sizeof( dloadinitcmd_t ) );
|
|
cmdlist[ *numcmds ] = cmd;
|
|
if( cmd )
|
|
{
|
|
( *numcmds )++;
|
|
|
|
cmd->num_args = 0;
|
|
cmd->args = NULL;
|
|
|
|
ld->tikiFile.UnGetToken();
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( false );
|
|
if( cmd->num_args < 255 )
|
|
{
|
|
pszArgs[ cmd->num_args ] = TIKI_CopyString( token );
|
|
cmd->num_args++;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseInitCommands: too many args in anim commands in %s.\n", ld->tikiFile.Filename() );
|
|
}
|
|
}
|
|
|
|
cmd->args = ( char ** )TIKI_AllocateLoadData( cmd->num_args * sizeof( char * ) );
|
|
for( i = 0; i < cmd->num_args; i++ )
|
|
{
|
|
cmd->args[ i ] = pszArgs[ i ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseInitCommands: could not allocate storage for dloadinitcmd_t in %s on line %d.\n", ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseInit
|
|
===============
|
|
*/
|
|
void TIKI_ParseInit( dloaddef_t *ld )
|
|
{
|
|
const char *token;
|
|
|
|
// Skip the init token
|
|
ld->tikiFile.GetToken( true );
|
|
|
|
while( ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "client" ) )
|
|
{
|
|
TIKI_ParseInitCommands( ld, ld->loadclientinitcmds, 160, &ld->numclientinitcmds );
|
|
}
|
|
else if( !stricmp( token, "server" ) )
|
|
{
|
|
TIKI_ParseInitCommands( ld, ld->loadserverinitcmds, 160, &ld->numserverinitcmds );
|
|
}
|
|
else if( !stricmp( token, "}" ) )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
TIKI_Error( "TIKI_ParseInit: unknown init command %s in %s on line %d, skipping line.\n", token, ld->tikiFile.Filename(), ld->tikiFile.GetLineNumber() );
|
|
|
|
// Skip the current line
|
|
while( ld->tikiFile.TokenAvailable( false ) )
|
|
ld->tikiFile.GetToken( false );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
TIKI_ParseCase
|
|
===============
|
|
*/
|
|
qboolean TIKI_ParseCase( dloaddef_t *ld )
|
|
{
|
|
const char *token;
|
|
bool isheadmodel;
|
|
bool isheadskin;
|
|
|
|
WriteBeginCase( ld );
|
|
|
|
__newcase:
|
|
token = ld->tikiFile.GetToken( false );
|
|
WriteCaseKey( ld, token );
|
|
isheadmodel = ( !stricmp( token, "headmodel" ) ) ? true : false;
|
|
isheadskin = ( !stricmp( token, "headskin" ) ) ? true : false;
|
|
|
|
while( 1 )
|
|
{
|
|
if( !ld->tikiFile.TokenAvailable( true ) )
|
|
{
|
|
TIKI_Error( "TIKI_ParseSetup: unexpected end of file while parsing 'case' switch in %s on line %d.\n", ld->tikiFile.Filename() , ld->tikiFile.GetLineNumber() );
|
|
return 0;
|
|
}
|
|
|
|
token = ld->tikiFile.GetToken( true );
|
|
if( !stricmp( token, "case" ) )
|
|
{
|
|
goto __newcase;
|
|
}
|
|
else if( !stricmp( token, "{" ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
WriteCaseValue( ld, token );
|
|
|
|
if( isheadmodel && TIKI_strstr( ld->headmodels, token ) )
|
|
{
|
|
strcat( ld->headmodels, token );
|
|
strcat( ld->headmodels, "\n" );
|
|
}
|
|
|
|
if( isheadskin && TIKI_strstr( ld->headskins, token ) )
|
|
{
|
|
strcat( ld->headskins, token );
|
|
strcat( ld->headskins, "\n" );
|
|
}
|
|
}
|
|
|
|
WriteBeginCaseBody( ld );
|
|
ld->tikiFile.UnGetToken();
|
|
if( !TIKI_ParseSetup( ld ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
WriteEndCase( ld );
|
|
return true;
|
|
}
|