2022-09-18 15:37:21 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 2000 - 2013 , Raven Software , Inc .
Copyright ( C ) 2001 - 2013 , Activision , Inc .
Copyright ( C ) 2013 - 2015 , OpenJK contributors
This file is part of the OpenJK source code .
OpenJK is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , see < http : //www.gnu.org/licenses/>.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
//NPC_stats.cpp
# include "b_local.h"
# include "b_public.h"
# include "anims.h"
# include "wp_saber.h"
# include "g_vehicles.h"
# include "../cgame/cg_local.h"
2023-06-07 22:33:59 +00:00
extern cvar_t * g_TeamBeefDirectorsCut ;
2022-09-18 15:37:21 +00:00
# if !defined(RUFL_HSTRING_INC)
# include "../Rufl/hstring.h"
# endif
# include "../Ratl/string_vs.h"
# include "../Rufl/hstring.h"
# include "../Ratl/vector_vs.h"
extern void WP_RemoveSaber ( gentity_t * ent , int saberNum ) ;
extern qboolean NPCsPrecached ;
extern vec3_t playerMins ;
extern vec3_t playerMaxs ;
extern stringID_table_t WPTable [ ] ;
# define MAX_MODELS_PER_LEVEL 60
hstring modelsAlreadyDone [ MAX_MODELS_PER_LEVEL ] ;
stringID_table_t animEventTypeTable [ ] =
{
ENUM2STRING ( AEV_SOUND ) , //# animID AEV_SOUND framenum soundpath randomlow randomhi chancetoplay
ENUM2STRING ( AEV_FOOTSTEP ) , //# animID AEV_FOOTSTEP framenum footstepType
ENUM2STRING ( AEV_EFFECT ) , //# animID AEV_EFFECT framenum effectpath boltName
ENUM2STRING ( AEV_FIRE ) , //# animID AEV_FIRE framenum altfire chancetofire
ENUM2STRING ( AEV_MOVE ) , //# animID AEV_MOVE framenum forwardpush rightpush uppush
ENUM2STRING ( AEV_SOUNDCHAN ) , //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay
ENUM2STRING ( AEV_SABER_SWING ) , //# animID AEV_SABER_SWING framenum CHANNEL randomlow randomhi chancetoplay
ENUM2STRING ( AEV_SABER_SPIN ) , //# animID AEV_SABER_SPIN framenum CHANNEL chancetoplay
//must be terminated
{ NULL , - 1 }
} ;
stringID_table_t footstepTypeTable [ ] =
{
ENUM2STRING ( FOOTSTEP_R ) ,
ENUM2STRING ( FOOTSTEP_L ) ,
ENUM2STRING ( FOOTSTEP_HEAVY_R ) ,
ENUM2STRING ( FOOTSTEP_HEAVY_L ) ,
//must be terminated
{ NULL , - 1 }
} ;
stringID_table_t FPTable [ ] =
{
ENUM2STRING ( FP_HEAL ) ,
ENUM2STRING ( FP_LEVITATION ) ,
ENUM2STRING ( FP_SPEED ) ,
ENUM2STRING ( FP_PUSH ) ,
ENUM2STRING ( FP_PULL ) ,
ENUM2STRING ( FP_TELEPATHY ) ,
ENUM2STRING ( FP_GRIP ) ,
ENUM2STRING ( FP_LIGHTNING ) ,
ENUM2STRING ( FP_SABERTHROW ) ,
ENUM2STRING ( FP_SABER_DEFENSE ) ,
ENUM2STRING ( FP_SABER_OFFENSE ) ,
//new Jedi Academy powers
ENUM2STRING ( FP_RAGE ) ,
ENUM2STRING ( FP_PROTECT ) ,
ENUM2STRING ( FP_ABSORB ) ,
ENUM2STRING ( FP_DRAIN ) ,
ENUM2STRING ( FP_SEE ) ,
{ " " , - 1 }
} ;
stringID_table_t TeamTable [ ] =
{
{ " free " , TEAM_FREE } , // caution, some code checks a team_t via "if (!team_t_varname)" so I guess this should stay as entry 0, great or what? -slc
ENUM2STRING ( TEAM_FREE ) , // caution, some code checks a team_t via "if (!team_t_varname)" so I guess this should stay as entry 0, great or what? -slc
{ " player " , TEAM_PLAYER } ,
ENUM2STRING ( TEAM_PLAYER ) ,
{ " enemy " , TEAM_ENEMY } ,
ENUM2STRING ( TEAM_ENEMY ) ,
{ " neutral " , TEAM_NEUTRAL } , // most droids are team_neutral, there are some exceptions like Probe,Seeker,Interrogator
ENUM2STRING ( TEAM_NEUTRAL ) , // most droids are team_neutral, there are some exceptions like Probe,Seeker,Interrogator
{ " " , - 1 }
} ;
// this list was made using the model directories, this MUST be in the same order as the CLASS_ enum in teams.h
stringID_table_t ClassTable [ ] =
{
ENUM2STRING ( CLASS_NONE ) , // hopefully this will never be used by an npc), just covering all bases
ENUM2STRING ( CLASS_ATST ) , // technically droid...
ENUM2STRING ( CLASS_BARTENDER ) ,
ENUM2STRING ( CLASS_BESPIN_COP ) ,
ENUM2STRING ( CLASS_CLAW ) ,
ENUM2STRING ( CLASS_COMMANDO ) ,
ENUM2STRING ( CLASS_DESANN ) ,
ENUM2STRING ( CLASS_FISH ) ,
ENUM2STRING ( CLASS_FLIER2 ) ,
ENUM2STRING ( CLASS_GALAK ) ,
ENUM2STRING ( CLASS_GLIDER ) ,
ENUM2STRING ( CLASS_GONK ) , // droid
ENUM2STRING ( CLASS_GRAN ) ,
ENUM2STRING ( CLASS_HOWLER ) ,
ENUM2STRING ( CLASS_RANCOR ) ,
ENUM2STRING ( CLASS_SAND_CREATURE ) ,
ENUM2STRING ( CLASS_WAMPA ) ,
ENUM2STRING ( CLASS_IMPERIAL ) ,
ENUM2STRING ( CLASS_IMPWORKER ) ,
ENUM2STRING ( CLASS_INTERROGATOR ) , // droid
ENUM2STRING ( CLASS_JAN ) ,
ENUM2STRING ( CLASS_JEDI ) ,
ENUM2STRING ( CLASS_KYLE ) ,
ENUM2STRING ( CLASS_LANDO ) ,
ENUM2STRING ( CLASS_LIZARD ) ,
ENUM2STRING ( CLASS_LUKE ) ,
ENUM2STRING ( CLASS_MARK1 ) , // droid
ENUM2STRING ( CLASS_MARK2 ) , // droid
ENUM2STRING ( CLASS_GALAKMECH ) , // droid
ENUM2STRING ( CLASS_MINEMONSTER ) ,
ENUM2STRING ( CLASS_MONMOTHA ) ,
ENUM2STRING ( CLASS_MORGANKATARN ) ,
ENUM2STRING ( CLASS_MOUSE ) , // droid
ENUM2STRING ( CLASS_MURJJ ) ,
ENUM2STRING ( CLASS_PRISONER ) ,
ENUM2STRING ( CLASS_PROBE ) , // droid
ENUM2STRING ( CLASS_PROTOCOL ) , // droid
ENUM2STRING ( CLASS_R2D2 ) , // droid
ENUM2STRING ( CLASS_R5D2 ) , // droid
ENUM2STRING ( CLASS_REBEL ) ,
ENUM2STRING ( CLASS_REBORN ) ,
ENUM2STRING ( CLASS_REELO ) ,
ENUM2STRING ( CLASS_REMOTE ) ,
ENUM2STRING ( CLASS_RODIAN ) ,
ENUM2STRING ( CLASS_SEEKER ) , // droid
ENUM2STRING ( CLASS_SENTRY ) ,
ENUM2STRING ( CLASS_SHADOWTROOPER ) ,
ENUM2STRING ( CLASS_SABOTEUR ) ,
ENUM2STRING ( CLASS_STORMTROOPER ) ,
ENUM2STRING ( CLASS_SWAMP ) ,
ENUM2STRING ( CLASS_SWAMPTROOPER ) ,
ENUM2STRING ( CLASS_NOGHRI ) ,
ENUM2STRING ( CLASS_TAVION ) ,
ENUM2STRING ( CLASS_ALORA ) ,
ENUM2STRING ( CLASS_TRANDOSHAN ) ,
ENUM2STRING ( CLASS_UGNAUGHT ) ,
ENUM2STRING ( CLASS_JAWA ) ,
ENUM2STRING ( CLASS_WEEQUAY ) ,
ENUM2STRING ( CLASS_TUSKEN ) ,
ENUM2STRING ( CLASS_BOBAFETT ) ,
ENUM2STRING ( CLASS_ROCKETTROOPER ) ,
ENUM2STRING ( CLASS_SABER_DROID ) ,
ENUM2STRING ( CLASS_PLAYER ) ,
ENUM2STRING ( CLASS_ASSASSIN_DROID ) ,
ENUM2STRING ( CLASS_HAZARD_TROOPER ) ,
ENUM2STRING ( CLASS_VEHICLE ) ,
{ " " , - 1 }
} ;
/*
NPC_ReactionTime
*/
//FIXME use grandom in here
int NPC_ReactionTime ( void )
{
return 200 * ( 6 - NPCInfo - > stats . reactions ) ;
}
//
// parse support routines
//
qboolean G_ParseLiteral ( const char * * data , const char * string )
{
const char * token ;
token = COM_ParseExt ( data , qtrue ) ;
if ( token [ 0 ] = = 0 )
{
gi . Printf ( " unexpected EOF \n " ) ;
return qtrue ;
}
if ( Q_stricmp ( token , string ) )
{
gi . Printf ( " required string '%s' missing \n " , string ) ;
return qtrue ;
}
return qfalse ;
}
//
// NPC parameters file : ext_data/NPCs/*.npc*
//
# define MAX_NPC_DATA_SIZE 0x80000
char NPCParms [ MAX_NPC_DATA_SIZE ] ;
/*
static rank_t TranslateRankName ( const char * name )
Should be used to determine pip bolt - ons
*/
static rank_t TranslateRankName ( const char * name )
{
if ( ! Q_stricmp ( name , " civilian " ) )
{
return RANK_CIVILIAN ;
}
if ( ! Q_stricmp ( name , " crewman " ) )
{
return RANK_CREWMAN ;
}
if ( ! Q_stricmp ( name , " ensign " ) )
{
return RANK_ENSIGN ;
}
if ( ! Q_stricmp ( name , " ltjg " ) )
{
return RANK_LT_JG ;
}
if ( ! Q_stricmp ( name , " lt " ) )
{
return RANK_LT ;
}
if ( ! Q_stricmp ( name , " ltcomm " ) )
{
return RANK_LT_COMM ;
}
if ( ! Q_stricmp ( name , " commander " ) )
{
return RANK_COMMANDER ;
}
if ( ! Q_stricmp ( name , " captain " ) )
{
return RANK_CAPTAIN ;
}
return RANK_CIVILIAN ;
}
saber_colors_t TranslateSaberColor ( const char * name )
{
if ( ! Q_stricmp ( name , " red " ) )
{
return SABER_RED ;
}
if ( ! Q_stricmp ( name , " orange " ) )
{
return SABER_ORANGE ;
}
if ( ! Q_stricmp ( name , " yellow " ) )
{
return SABER_YELLOW ;
}
if ( ! Q_stricmp ( name , " green " ) )
{
return SABER_GREEN ;
}
if ( ! Q_stricmp ( name , " blue " ) )
{
return SABER_BLUE ;
}
if ( ! Q_stricmp ( name , " purple " ) )
{
return SABER_PURPLE ;
}
if ( ! Q_stricmp ( name , " random " ) )
{
return ( ( saber_colors_t ) ( Q_irand ( SABER_ORANGE , SABER_PURPLE ) ) ) ;
}
return SABER_BLUE ;
}
/* static int MethodNameToNumber( const char *name ) {
if ( ! Q_stricmp ( name , " EXPONENTIAL " ) ) {
return METHOD_EXPONENTIAL ;
}
if ( ! Q_stricmp ( name , " LINEAR " ) ) {
return METHOD_LINEAR ;
}
if ( ! Q_stricmp ( name , " LOGRITHMIC " ) ) {
return METHOD_LOGRITHMIC ;
}
if ( ! Q_stricmp ( name , " ALWAYS " ) ) {
return METHOD_ALWAYS ;
}
if ( ! Q_stricmp ( name , " NEVER " ) ) {
return METHOD_NEVER ;
}
return - 1 ;
}
static int ItemNameToNumber ( const char * name , int itemType ) {
// int n;
for ( n = 0 ; n < bg_numItems ; n + + ) {
if ( bg_itemlist [ n ] . type ! = itemType ) {
continue ;
}
if ( Q_stricmp ( bg_itemlist [ n ] . classname , name ) = = 0 ) {
return bg_itemlist [ n ] . tag ;
}
}
return - 1 ;
}
*/
static int MoveTypeNameToEnum ( const char * name )
{
if ( ! Q_stricmp ( " runjump " , name ) )
{
return MT_RUNJUMP ;
}
else if ( ! Q_stricmp ( " walk " , name ) )
{
return MT_WALK ;
}
else if ( ! Q_stricmp ( " flyswim " , name ) )
{
return MT_FLYSWIM ;
}
else if ( ! Q_stricmp ( " static " , name ) )
{
return MT_STATIC ;
}
return MT_STATIC ;
}
extern void CG_RegisterClientRenderInfo ( clientInfo_t * ci , renderInfo_t * ri ) ;
extern void CG_RegisterClientModels ( int entityNum ) ;
extern void CG_RegisterNPCCustomSounds ( clientInfo_t * ci ) ;
//#define CONVENIENT_ANIMATION_FILE_DEBUG_THING
# ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
void SpewDebugStuffToFile ( animation_t * bgGlobalAnimations )
{
char BGPAFtext [ 40000 ] ;
fileHandle_t f ;
int i = 0 ;
gi . FS_FOpenFile ( " file_of_debug_stuff_SP.txt " , & f , FS_WRITE ) ;
if ( ! f )
{
return ;
}
BGPAFtext [ 0 ] = 0 ;
while ( i < MAX_ANIMATIONS )
{
strcat ( BGPAFtext , va ( " %i %i \n " , i , bgGlobalAnimations [ i ] . frameLerp ) ) ;
i + + ;
}
gi . FS_Write ( BGPAFtext , strlen ( BGPAFtext ) , f ) ;
gi . FS_FCloseFile ( f ) ;
}
# endif
int CG_CheckAnimFrameForEventType ( animevent_t * animEvents , int keyFrame , animEventType_t eventType , unsigned short modelIndex )
{
for ( int i = 0 ; i < MAX_ANIM_EVENTS ; i + + )
{
if ( animEvents [ i ] . keyFrame = = keyFrame )
{ //there is an animevent on this frame already
if ( animEvents [ i ] . eventType = = eventType )
{ //and it is of the same type
if ( animEvents [ i ] . modelOnly = = modelIndex )
{ //and it is for the same model
return i ;
}
}
}
}
//nope
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
ParseAnimationEvtBlock
= = = = = = = = = = = = = = = = = = = = = =
*/
static void ParseAnimationEvtBlock ( int glaIndex , unsigned short modelIndex , const char * aeb_filename , animevent_t * animEvents , animation_t * animations , unsigned char & lastAnimEvent , const char * * text_p , bool bIsFrameSkipped )
{
const char * token ;
int num , n , animNum , keyFrame , lowestVal , highestVal , curAnimEvent = 0 ;
animEventType_t eventType ;
char stringData [ MAX_QPATH ] ;
// get past starting bracket
while ( 1 )
{
token = COM_Parse ( text_p ) ;
if ( ! Q_stricmp ( token , " { " ) )
{
break ;
}
}
//NOTE: instead of a blind increment, increase the index
// this way if we have an event on an anim that already
// has an event of that type, it stomps it
// read information for each frame
while ( 1 )
{
// Get base frame of sequence
token = COM_Parse ( text_p ) ;
if ( ! token | | ! token [ 0 ] )
{
break ;
}
if ( ! Q_stricmp ( token , " } " ) ) // At end of block
{
break ;
}
//Compare to same table as animations used
// so we don't have to use actual numbers for animation first frames,
// just need offsets.
//This way when animation numbers change, this table won't have to be updated,
// at least not much.
animNum = GetIDForString ( animTable , token ) ;
if ( animNum = = - 1 )
{ //Unrecognized ANIM ENUM name,
Com_Printf ( S_COLOR_YELLOW " WARNING: Unknown ANIM %s in file %s \n " , token , aeb_filename ) ;
//skip this entry
SkipRestOfLine ( text_p ) ;
continue ;
}
if ( animations [ animNum ] . numFrames = = 0 )
{ //we don't use this anim
# ifndef FINAL_BUILD
Com_Printf ( S_COLOR_YELLOW " WARNING: %s: anim %s not used by this model \n " , aeb_filename , token ) ;
# endif
//skip this entry
SkipRestOfLine ( text_p ) ;
continue ;
}
token = COM_Parse ( text_p ) ;
eventType = ( animEventType_t ) GetIDForString ( animEventTypeTable , token ) ;
if ( eventType = = AEV_NONE | | eventType = = ( animEventType_t ) - 1 )
{ //Unrecognized ANIM EVENT TYPE
Com_Printf ( S_COLOR_RED " ERROR: Unknown EVENT %s in animEvent file %s \n " , token , aeb_filename ) ;
continue ;
}
// Get offset to frame within sequence
token = COM_Parse ( text_p ) ;
if ( ! token )
{
break ;
}
keyFrame = atoi ( token ) ;
if ( bIsFrameSkipped & &
( animations [ animNum ] . numFrames > 2 ) // important, else frame 1 gets divided down and becomes frame 0. Carcass & Assimilate also work this way
)
{
keyFrame / = 2 ; // if we ever use any other value in frame-skipping we'll have to figure out some way of reading it, since it's not stored anywhere
}
if ( keyFrame > = animations [ animNum ] . numFrames )
{
Com_Printf ( S_COLOR_YELLOW " WARNING: Event out of range on %s in %s \n " , GetStringForID ( animTable , animNum ) , aeb_filename ) ;
assert ( keyFrame < animations [ animNum ] . numFrames ) ;
keyFrame = animations [ animNum ] . numFrames - 1 ; //clamp it
}
//set our start frame
keyFrame + = animations [ animNum ] . firstFrame ;
//see if this frame already has an event of this type on it, if so, overwrite it
curAnimEvent = CG_CheckAnimFrameForEventType ( animEvents , keyFrame , eventType , modelIndex ) ;
if ( curAnimEvent = = - 1 )
{ //this anim frame doesn't already have an event of this type on it
curAnimEvent = lastAnimEvent ;
}
//now that we know which event index we're going to plug the data into, start doing it
animEvents [ curAnimEvent ] . eventType = eventType ;
assert ( keyFrame > = 0 & & keyFrame < 65535 ) ; //
animEvents [ curAnimEvent ] . keyFrame = keyFrame ;
animEvents [ curAnimEvent ] . glaIndex = glaIndex ;
animEvents [ curAnimEvent ] . modelOnly = modelIndex ;
int tempVal ;
//now read out the proper data based on the type
switch ( animEvents [ curAnimEvent ] . eventType )
{
case AEV_SOUNDCHAN : //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay
token = COM_Parse ( text_p ) ;
if ( ! token )
{
break ;
}
if ( Q_stricmp ( token , " CHAN_VOICE_ATTEN " ) = = 0 )
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_VOICE_ATTEN ;
}
else if ( Q_stricmp ( token , " CHAN_VOICE_GLOBAL " ) = = 0 )
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_VOICE_GLOBAL ;
}
else if ( Q_stricmp ( token , " CHAN_ANNOUNCER " ) = = 0 )
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_ANNOUNCER ;
}
else if ( Q_stricmp ( token , " CHAN_BODY " ) = = 0 )
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_BODY ;
}
else if ( Q_stricmp ( token , " CHAN_WEAPON " ) = = 0 )
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_WEAPON ;
}
else if ( Q_stricmp ( token , " CHAN_VOICE " ) = = 0 )
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_VOICE ;
}
else
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDCHANNEL ] = CHAN_AUTO ;
}
//fall through to normal sound
case AEV_SOUND : //# animID AEV_SOUND framenum soundpath randomlow randomhi chancetoplay
//get soundstring
token = COM_Parse ( text_p ) ;
if ( ! token )
{
break ;
}
strcpy ( stringData , token ) ;
//get lowest value
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
lowestVal = atoi ( token ) ;
//get highest value
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
highestVal = atoi ( token ) ;
//Now precache all the sounds
//NOTE: If we can be assured sequential handles, we can store the first sound index and count
// unfortunately, if these sounds were previously registered, we cannot be guaranteed sequential indices. Thus an array
if ( lowestVal & & highestVal )
{
assert ( highestVal - lowestVal < MAX_RANDOM_ANIM_SOUNDS ) ;
for ( n = lowestVal , num = AED_SOUNDINDEX_START ; n < = highestVal & & num < = AED_SOUNDINDEX_END ; n + + , num + + )
{
animEvents [ curAnimEvent ] . eventData [ num ] = G_SoundIndex ( va ( stringData , n ) ) ; //cgi_S_RegisterSound
}
animEvents [ curAnimEvent ] . eventData [ AED_SOUND_NUMRANDOMSNDS ] = num - 1 ;
}
else
{
animEvents [ curAnimEvent ] . eventData [ AED_SOUNDINDEX_START ] = G_SoundIndex ( stringData ) ; //cgi_S_RegisterSound
#if 0 //#ifndef FINAL_BUILD (only meaningfull if using S_RegisterSound
if ( ! animEvents [ curAnimEvent ] . eventData [ AED_SOUNDINDEX_START ] )
{ //couldn't register it - file not found
Com_Printf ( S_COLOR_RED " ParseAnimationSndBlock: sound %s does not exist (%s)! \n " , stringData , * aeb_filename ) ;
}
# endif
animEvents [ curAnimEvent ] . eventData [ AED_SOUND_NUMRANDOMSNDS ] = 0 ;
}
//get probability
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
animEvents [ curAnimEvent ] . eventData [ AED_SOUND_PROBABILITY ] = atoi ( token ) ;
//last part - cheat and check and see if it's a special overridable saber sound we know of...
if ( ! Q_stricmpn ( " sound/weapons/saber/saberhup " , stringData , 28 ) )
{ //a saber swing
animEvents [ curAnimEvent ] . eventType = AEV_SABER_SWING ;
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SWING_SABERNUM ] = 0 ; //since we don't know which one they meant if we're hacking this, always use first saber
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SWING_PROBABILITY ] = animEvents [ curAnimEvent ] . eventData [ AED_SOUND_PROBABILITY ] ;
if ( lowestVal < 4 )
{ //fast swing
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SWING_TYPE ] = SWING_FAST ;
}
else if ( lowestVal < 7 )
{ //medium swing
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SWING_TYPE ] = SWING_MEDIUM ;
}
else
{ //strong swing
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SWING_TYPE ] = SWING_STRONG ;
}
}
else if ( ! Q_stricmpn ( " sound/weapons/saber/saberspin " , stringData , 29 ) )
{ //a saber spin
animEvents [ curAnimEvent ] . eventType = AEV_SABER_SPIN ;
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_SABERNUM ] = 0 ; //since we don't know which one they meant if we're hacking this, always use first saber
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_PROBABILITY ] = animEvents [ curAnimEvent ] . eventData [ AED_SOUND_PROBABILITY ] ;
if ( stringData [ 29 ] = = ' o ' )
{ //saberspinoff
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_TYPE ] = 0 ;
}
else if ( stringData [ 29 ] = = ' 1 ' )
{ //saberspin1
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_TYPE ] = 2 ;
}
else if ( stringData [ 29 ] = = ' 2 ' )
{ //saberspin2
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_TYPE ] = 3 ;
}
else if ( stringData [ 29 ] = = ' 3 ' )
{ //saberspin3
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_TYPE ] = 4 ;
}
else if ( stringData [ 29 ] = = ' % ' )
{ //saberspin%d
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_TYPE ] = 5 ;
}
else
{ //just plain saberspin
animEvents [ curAnimEvent ] . eventData [ AED_SABER_SPIN_TYPE ] = 1 ;
}
}
break ;
case AEV_FOOTSTEP : //# animID AEV_FOOTSTEP framenum footstepType
//get footstep type
token = COM_Parse ( text_p ) ;
if ( ! token )
{
break ;
}
animEvents [ curAnimEvent ] . eventData [ AED_FOOTSTEP_TYPE ] = GetIDForString ( footstepTypeTable , token ) ;
//get probability
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
animEvents [ curAnimEvent ] . eventData [ AED_FOOTSTEP_PROBABILITY ] = atoi ( token ) ;
break ;
case AEV_EFFECT : //# animID AEV_EFFECT framenum effectpath boltName
//get effect index
token = COM_Parse ( text_p ) ;
if ( ! token )
{
break ;
}
if ( token [ 0 ] & & Q_stricmp ( " special " , token ) = = 0 )
{ //special hard-coded effects
//let cgame know it's not a real effect
animEvents [ curAnimEvent ] . eventData [ AED_EFFECTINDEX ] = - 1 ;
//get the name of it
token = COM_Parse ( text_p ) ;
animEvents [ curAnimEvent ] . stringData = G_NewString ( token ) ;
}
else
{ //regular effect
tempVal = G_EffectIndex ( token ) ;
assert ( tempVal > - 32767 & & tempVal < 32767 ) ;
animEvents [ curAnimEvent ] . eventData [ AED_EFFECTINDEX ] = tempVal ;
//get bolt index
token = COM_Parse ( text_p ) ;
if ( ! token )
{
break ;
}
if ( Q_stricmp ( " none " , token ) ! = 0 & & Q_stricmp ( " NULL " , token ) ! = 0 )
{ //actually are specifying a bolt to use
animEvents [ curAnimEvent ] . stringData = G_NewString ( token ) ;
}
}
//NOTE: this string will later be used to add a bolt and store the index, as below:
//animEvent->eventData[AED_BOLTINDEX] = gi.G2API_AddBolt( ¢->gent->ghoul2[cent->gent->playerModel], animEvent->stringData );
//get probability
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
animEvents [ curAnimEvent ] . eventData [ AED_EFFECT_PROBABILITY ] = atoi ( token ) ;
break ;
case AEV_FIRE : //# animID AEV_FIRE framenum altfire chancetofire
//get altfire
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
animEvents [ curAnimEvent ] . eventData [ AED_FIRE_ALT ] = atoi ( token ) ;
//get probability
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
animEvents [ curAnimEvent ] . eventData [ AED_FIRE_PROBABILITY ] = atoi ( token ) ;
break ;
case AEV_MOVE : //# animID AEV_MOVE framenum forwardpush rightpush uppush
//get forward push
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
tempVal = atoi ( token ) ;
assert ( tempVal > - 32767 & & tempVal < 32767 ) ;
animEvents [ curAnimEvent ] . eventData [ AED_MOVE_FWD ] = tempVal ;
//get right push
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
tempVal = atoi ( token ) ;
assert ( tempVal > - 32767 & & tempVal < 32767 ) ;
animEvents [ curAnimEvent ] . eventData [ AED_MOVE_RT ] = tempVal ;
//get upwards push
token = COM_Parse ( text_p ) ;
if ( ! token )
{ //WARNING! BAD TABLE!
break ;
}
tempVal = atoi ( token ) ;
assert ( tempVal > - 32767 & & tempVal < 32767 ) ;
animEvents [ curAnimEvent ] . eventData [ AED_MOVE_UP ] = tempVal ;
break ;
default : //unknown?
SkipRestOfLine ( text_p ) ;
continue ;
break ;
}
if ( curAnimEvent = = lastAnimEvent )
{
lastAnimEvent + + ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = =
G_ParseAnimationEvtFile
Read a configuration file containing animation events
models / players / kyle / animevents . cfg , etc
This file ' s presence is not required
= = = = = = = = = = = = = = = = = = = = = =
*/
static
void G_ParseAnimationEvtFile ( int glaIndex , const char * eventsDirectory , int fileIndex , int iRealGLAIndex = - 1 , bool modelSpecific = false )
{
int len ;
const char * token ;
char text [ 80000 ] ;
const char * text_p = text ;
fileHandle_t f ;
char eventsPath [ MAX_QPATH ] ;
int modelIndex = 0 ;
assert ( fileIndex > = 0 & & fileIndex < MAX_ANIM_FILES ) ;
const char * psAnimFileInternalName = ( iRealGLAIndex = = - 1 ? NULL : gi . G2API_GetAnimFileInternalNameIndex ( iRealGLAIndex ) ) ;
bool bIsFrameSkipped = ( psAnimFileInternalName & & strlen ( psAnimFileInternalName ) > 5 & & ! Q_stricmp ( & psAnimFileInternalName [ strlen ( psAnimFileInternalName ) - 5 ] , " _skip " ) ) ;
// Open The File, Make Sure It Is Safe
//-------------------------------------
Com_sprintf ( eventsPath , MAX_QPATH , " models/players/%s/animevents.cfg " , eventsDirectory ) ;
len = cgi_FS_FOpenFile ( eventsPath , & f , FS_READ ) ;
if ( len < = 0 )
{ //no file
return ;
}
if ( len > = ( int ) ( sizeof ( text ) - 1 ) )
{
cgi_FS_FCloseFile ( f ) ;
CG_Printf ( " File %s too long \n " , eventsPath ) ;
return ;
}
// Read It To The Buffer, Close The File
//---------------------------------------
cgi_FS_Read ( text , len , f ) ;
text [ len ] = 0 ;
cgi_FS_FCloseFile ( f ) ;
// Get The Pointers To The Anim Event Arrays
//-------------------------------------------
animFileSet_t & afileset = level . knownAnimFileSets [ fileIndex ] ;
animevent_t * legsAnimEvents = afileset . legsAnimEvents ;
animevent_t * torsoAnimEvents = afileset . torsoAnimEvents ;
animation_t * animations = afileset . animations ;
if ( modelSpecific )
{
hstring modelName ( eventsDirectory ) ;
modelIndex = modelName . handle ( ) ;
}
// read information for batches of sounds (UPPER or LOWER)
COM_BeginParseSession ( ) ;
while ( 1 )
{
// Get base frame of sequence
token = COM_Parse ( & text_p ) ;
if ( ! token | | ! token [ 0 ] )
{
break ;
}
//these stomp anything set in the include file (if it's an event of the same type on the same frame)!
if ( ! Q_stricmp ( token , " UPPEREVENTS " ) ) // A batch of upper events
{
ParseAnimationEvtBlock ( glaIndex , modelIndex , eventsPath , torsoAnimEvents , animations , afileset . torsoAnimEventCount , & text_p , bIsFrameSkipped ) ;
}
else if ( ! Q_stricmp ( token , " LOWEREVENTS " ) ) // A batch of lower events
{
ParseAnimationEvtBlock ( glaIndex , modelIndex , eventsPath , legsAnimEvents , animations , afileset . legsAnimEventCount , & text_p , bIsFrameSkipped ) ;
}
}
COM_EndParseSession ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
G_ParseAnimationFile
Read a configuration file containing animation coutns and rates
models / players / visor / animation . cfg , etc
= = = = = = = = = = = = = = = = = = = = = =
*/
qboolean G_ParseAnimationFile ( int glaIndex , const char * skeletonName , int fileIndex )
{
char text [ 80000 ] ;
int len = 0 ;
const char * token = 0 ;
float fps = 0 ;
const char * text_p = text ;
int animNum = 0 ;
animation_t * animations = level . knownAnimFileSets [ fileIndex ] . animations ;
char skeletonPath [ MAX_QPATH ] ;
// Read In The File To The Text Buffer, Make Sure Everything Is Safe To Continue
//-------------------------------------------------------------------------------
Com_sprintf ( skeletonPath , MAX_QPATH , " models/players/%s/%s.cfg " , skeletonName , skeletonName ) ;
len = gi . RE_GetAnimationCFG ( skeletonPath , text , sizeof ( text ) ) ;
if ( len < = 0 )
{
Com_sprintf ( skeletonPath , MAX_QPATH , " models/players/%s/animation.cfg " , skeletonName ) ;
len = gi . RE_GetAnimationCFG ( skeletonPath , text , sizeof ( text ) ) ;
if ( len < = 0 )
{
return qfalse ;
}
}
if ( len > = ( int ) ( sizeof ( text ) - 1 ) )
{
G_Error ( " G_ParseAnimationFile: File %s too long \n (%d > %d) " , skeletonName , len , sizeof ( text ) - 1 ) ;
return qfalse ;
}
// Read In Each Token
//--------------------
COM_BeginParseSession ( ) ;
while ( 1 )
{
token = COM_Parse ( & text_p ) ;
// If No Token, We've Reached The End Of The File
//------------------------------------------------
if ( ! token | | ! token [ 0 ] )
{
break ;
}
// Get The Anim Number Converted From The First Token
//----------------------------------------------------
animNum = GetIDForString ( animTable , token ) ;
if ( animNum = = - 1 )
{
# ifndef FINAL_BUILD
if ( strcmp ( token , " ROOT " ) )
{
Com_Printf ( S_COLOR_RED " WARNING: Unknown token %s in %s \n " , token , skeletonPath ) ;
}
# endif
//unrecognized animation so skip to end of line,
while ( token [ 0 ] )
{
token = COM_ParseExt ( & text_p , qfalse ) ; //returns empty string when next token is EOL
}
continue ;
}
// GLAIndex
//----------
animations [ animNum ] . glaIndex = glaIndex ; // Passed Into This Func
// First Frame
//-------------
token = COM_Parse ( & text_p ) ;
if ( ! token )
{
break ;
}
assert ( atoi ( token ) > = 0 & & atoi ( token ) < 65536 ) ;
animations [ animNum ] . firstFrame = atoi ( token ) ;
// Num Frames
//------------
token = COM_Parse ( & text_p ) ;
if ( ! token )
{
break ;
}
assert ( atoi ( token ) > = 0 & & atoi ( token ) < 65536 ) ;
animations [ animNum ] . numFrames = atoi ( token ) ;
// Loop Frames
//-------------
token = COM_Parse ( & text_p ) ;
if ( ! token )
{
break ;
}
assert ( atoi ( token ) > = - 1 & & atoi ( token ) < 128 ) ;
animations [ animNum ] . loopFrames = atoi ( token ) ;
// FPS
//-----
token = COM_Parse ( & text_p ) ;
if ( ! token )
{
break ;
}
fps = atof ( token ) ;
if ( fps = = 0 )
{
fps = 1 ; //Don't allow divide by zero error
}
// Calculate Frame Lerp
//----------------------
int lerp ;
if ( fps < 0 )
{ //backwards
lerp = floor ( 1000.0f / fps ) ;
assert ( lerp > - 32767 & & lerp < 32767 ) ;
animations [ animNum ] . frameLerp = lerp ;
assert ( animations [ animNum ] . frameLerp < = 1 ) ;
}
else
{
lerp = ceil ( 1000.0f / fps ) ;
assert ( lerp > - 32767 & & lerp < 32767 ) ;
animations [ animNum ] . frameLerp = lerp ;
assert ( animations [ animNum ] . frameLerp > = 1 ) ;
}
/* lerp = ceil(1000.0f / Q_fabs(fps));
assert ( lerp > - 32767 & & lerp < 32767 ) ;
animations [ animNum ] . initialLerp = lerp ;
*/
}
COM_EndParseSession ( ) ;
# ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
if ( strstr ( af_filename , " humanoid " ) )
{
SpewDebugStuffToFile ( animations ) ;
}
# endif
return qtrue ;
}
////////////////////////////////////////////////////////////////////////
// G_ParseAnimFileSet
//
// This function is responsible for building the animation file and
// the animation event file.
//
////////////////////////////////////////////////////////////////////////
int G_ParseAnimFileSet ( const char * skeletonName , const char * modelName = 0 )
{
int fileIndex = 0 ;
// Try To Find An Existing Skeleton File For This Animation Set
//--------------------------------------------------------------
for ( fileIndex = 0 ; fileIndex < level . numKnownAnimFileSets ; fileIndex + + )
{
if ( Q_stricmp ( level . knownAnimFileSets [ fileIndex ] . filename , skeletonName ) = = 0 )
{
break ;
}
}
// Ok, We Don't Already Have One, So Time To Create A New One And Initialize It
//------------------------------------------------------------------------------
if ( fileIndex > = level . numKnownAnimFileSets )
{
if ( level . numKnownAnimFileSets = = MAX_ANIM_FILES )
{
G_Error ( " G_ParseAnimFileSet: MAX_ANIM_FILES " ) ;
return - 1 ;
}
// Allocate A new File Set, And Get Some Shortcut Pointers
//---------------------------------------------------------
fileIndex = level . numKnownAnimFileSets ;
level . numKnownAnimFileSets + + ;
strcpy ( level . knownAnimFileSets [ fileIndex ] . filename , skeletonName ) ;
level . knownAnimFileSets [ fileIndex ] . torsoAnimEventCount = 0 ;
level . knownAnimFileSets [ fileIndex ] . legsAnimEventCount = 0 ;
animation_t * animations = level . knownAnimFileSets [ fileIndex ] . animations ;
animevent_t * legsAnimEvents = level . knownAnimFileSets [ fileIndex ] . legsAnimEvents ;
animevent_t * torsoAnimEvents = level . knownAnimFileSets [ fileIndex ] . torsoAnimEvents ;
int i , j ;
// Initialize The Frames Information
//-----------------------------------
for ( i = 0 ; i < MAX_ANIMATIONS ; i + + )
{
animations [ i ] . firstFrame = 0 ;
animations [ i ] . numFrames = 0 ;
animations [ i ] . loopFrames = - 1 ;
animations [ i ] . frameLerp = 100 ;
// animations[i].initialLerp = 100;
animations [ i ] . glaIndex = 0 ;
}
// Initialize Animation Event Array
//----------------------------------
for ( i = 0 ; i < MAX_ANIM_EVENTS ; i + + )
{
torsoAnimEvents [ i ] . eventType = AEV_NONE ; //Type of event
legsAnimEvents [ i ] . eventType = AEV_NONE ;
torsoAnimEvents [ i ] . keyFrame = ( unsigned short ) - 1 ; //65535 should never be a valid frame... :)
legsAnimEvents [ i ] . keyFrame = ( unsigned short ) - 1 ; //Frame to play event on
torsoAnimEvents [ i ] . stringData = NULL ; //we allow storage of one string, temporarily (in case we have to look up an index later,
legsAnimEvents [ i ] . stringData = NULL ; //then make sure to set stringData to NULL so we only do the look-up once)
torsoAnimEvents [ i ] . modelOnly = 0 ;
legsAnimEvents [ i ] . modelOnly = 0 ;
torsoAnimEvents [ i ] . glaIndex = 0 ;
legsAnimEvents [ i ] . glaIndex = 0 ;
for ( j = 0 ; j < AED_ARRAY_SIZE ; j + + ) //Unique IDs, can be soundIndex of sound file to play OR effect index or footstep type, etc.
{
torsoAnimEvents [ i ] . eventData [ j ] = - 1 ;
legsAnimEvents [ i ] . eventData [ j ] = - 1 ;
}
}
// Get The Cinematic GLA Name
//----------------------------
if ( Q_stricmp ( skeletonName , " _humanoid " ) = = 0 )
{
const char * mapName = strrchr ( level . mapname , ' / ' ) ;
if ( mapName )
{
mapName + + ;
}
else
{
mapName = level . mapname ;
}
char skeletonMapName [ MAX_QPATH ] ;
Com_sprintf ( skeletonMapName , MAX_QPATH , " _humanoid_%s " , mapName ) ;
const int normalGLAIndex = gi . G2API_PrecacheGhoul2Model ( " models/players/_humanoid/_humanoid.gla " ) ; //double check this always comes first!
// Make Sure To Precache The GLAs (both regular and cinematic), And Remember Their Indicies
//------------------------------------------------------------------------------------------
G_ParseAnimationFile ( 0 , skeletonName , fileIndex ) ;
G_ParseAnimationEvtFile ( 0 , skeletonName , fileIndex , normalGLAIndex , false /*flag for model specific*/ ) ;
const int cineGLAIndex = gi . G2API_PrecacheGhoul2Model ( va ( " models/players/%s/%s.gla " , skeletonMapName , skeletonMapName ) ) ;
if ( cineGLAIndex )
{
assert ( cineGLAIndex = = normalGLAIndex + 1 ) ;
if ( cineGLAIndex ! = normalGLAIndex + 1 )
{
Com_Error ( ERR_DROP , " Cinematic GLA was not loaded after the normal GLA. Cannot continue safely. " ) ;
}
G_ParseAnimationFile ( 1 , skeletonMapName , fileIndex ) ;
G_ParseAnimationEvtFile ( 1 , skeletonMapName , fileIndex , cineGLAIndex , false /*flag for model specific*/ ) ;
}
}
else
{
// non-humanoid...
//
// Make Sure To Precache The GLAs (both regular and cinematic), And Remember Their Indicies
//------------------------------------------------------------------------------------------
G_ParseAnimationFile ( 0 , skeletonName , fileIndex ) ;
G_ParseAnimationEvtFile ( 0 , skeletonName , fileIndex ) ;
}
}
// Tack Any Additional Per Model Events
//--------------------------------------
if ( modelName )
{
// Quick Search To See If We've Already Loaded This Model
//--------------------------------------------------------
int curModel = 0 ;
hstring curModelName ( modelName ) ;
while ( curModel < MAX_MODELS_PER_LEVEL & & ! modelsAlreadyDone [ curModel ] . empty ( ) )
{
if ( modelsAlreadyDone [ curModel ] = = curModelName )
{
return fileIndex ;
}
curModel + + ;
}
if ( curModel = = MAX_MODELS_PER_LEVEL )
{
Com_Error ( ERR_DROP , " About to overflow modelsAlreadyDone, increase MAX_MODELS_PER_LEVEL \n " ) ;
}
// Nope, Ok, Record The Model As Found And Parse It's Event File
//---------------------------------------------------------------
modelsAlreadyDone [ curModel ] = curModelName ;
// Only Do The Event File If The Model Is Not The Same As The Skeleton
//---------------------------------------------------------------------
if ( Q_stricmp ( skeletonName , modelName ) ! = 0 )
{
const int iGLAIndexToCheckForSkip = ( Q_stricmp ( skeletonName , " _humanoid " ) ? - 1 : gi . G2API_PrecacheGhoul2Model ( " models/players/_humanoid/_humanoid.gla " ) ) ; // ;-)
G_ParseAnimationEvtFile ( 0 , modelName , fileIndex , iGLAIndexToCheckForSkip , true ) ;
}
}
return fileIndex ;
}
extern cvar_t * g_char_model ;
void G_LoadAnimFileSet ( gentity_t * ent , const char * pModelName )
{
//load its animation config
char animName [ MAX_QPATH ] ;
char * GLAName , * modelName ;
char * slash = NULL ;
char * strippedName ;
if ( ent - > playerModel = = - 1 )
{
return ;
}
if ( Q_stricmp ( " player " , pModelName ) = = 0 )
{ //model is actually stored on console
modelName = g_char_model - > string ;
}
else
{
modelName = ( char * ) pModelName ;
}
//get the location of the animation.cfg
GLAName = gi . G2API_GetGLAName ( & ent - > ghoul2 [ ent - > playerModel ] ) ;
//now load and parse the animation.cfg, animevents.cfg and set the animFileIndex
if ( ! GLAName )
{
Com_Printf ( S_COLOR_RED " Failed find animation file name models/players/%s \n " , modelName ) ;
strippedName = " _humanoid " ; //take a guess, maybe it's right?
}
else
{
Q_strncpyz ( animName , GLAName , sizeof ( animName ) ) ;
slash = strrchr ( animName , ' / ' ) ;
if ( slash )
{
* slash = 0 ;
}
strippedName = COM_SkipPath ( animName ) ;
}
//now load and parse the animation.cfg, animevents.cfg and set the animFileIndex
ent - > client - > clientInfo . animFileIndex = G_ParseAnimFileSet ( strippedName , modelName ) ;
if ( ent - > client - > clientInfo . animFileIndex < 0 )
{
Com_Printf ( S_COLOR_RED " Failed to load animation file set models/players/%s/animation.cfg \n " , modelName ) ;
# ifndef FINAL_BUILD
Com_Error ( ERR_FATAL , " Failed to load animation file set models/players/%s/animation.cfg \n " , modelName ) ;
# endif
}
}
void NPC_PrecacheAnimationCFG ( const char * NPC_type )
{
char filename [ MAX_QPATH ] ;
const char * token ;
const char * value ;
const char * p ;
if ( ! Q_stricmp ( " random " , NPC_type ) )
{ //sorry, can't precache a random just yet
return ;
}
p = NPCParms ;
COM_BeginParseSession ( ) ;
// look for the right NPC
while ( p )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( token [ 0 ] = = 0 )
{
COM_EndParseSession ( ) ;
return ;
}
if ( ! Q_stricmp ( token , NPC_type ) )
{
break ;
}
SkipBracedSection ( & p ) ;
}
if ( ! p )
{
COM_EndParseSession ( ) ;
return ;
}
if ( G_ParseLiteral ( & p , " { " ) )
{
COM_EndParseSession ( ) ;
return ;
}
// parse the NPC info block
while ( 1 )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( ! token [ 0 ] )
{
gi . Printf ( S_COLOR_RED " ERROR: unexpected EOF while parsing '%s' \n " , NPC_type ) ;
COM_EndParseSession ( ) ;
return ;
}
if ( ! Q_stricmp ( token , " } " ) )
{
break ;
}
// legsmodel
if ( ! Q_stricmp ( token , " legsmodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
//must copy data out of this pointer into a different part of memory because the funcs we're about to call will call COM_ParseExt
Q_strncpyz ( filename , value , sizeof ( filename ) ) ;
G_ParseAnimFileSet ( filename ) ;
COM_EndParseSession ( ) ;
return ;
}
// playerModel
if ( ! Q_stricmp ( token , " playerModel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
char animName [ MAX_QPATH ] ;
char * GLAName ;
char * slash = NULL ;
char * strippedName ;
int handle = gi . G2API_PrecacheGhoul2Model ( va ( " models/players/%s/model.glm " , value ) ) ;
if ( handle > 0 ) //FIXME: isn't 0 a valid handle?
{
GLAName = gi . G2API_GetAnimFileNameIndex ( handle ) ;
if ( GLAName )
{
Q_strncpyz ( animName , GLAName , sizeof ( animName ) ) ;
slash = strrchr ( animName , ' / ' ) ;
if ( slash )
{
* slash = 0 ;
}
strippedName = COM_SkipPath ( animName ) ;
//must copy data out of this pointer into a different part of memory because the funcs we're about to call will call COM_ParseExt
Q_strncpyz ( filename , value , sizeof ( filename ) ) ;
G_ParseAnimFileSet ( strippedName , filename ) ;
COM_EndParseSession ( ) ;
return ;
}
}
}
}
COM_EndParseSession ( ) ;
}
extern int NPC_WeaponsForTeam ( team_t team , int spawnflags , const char * NPC_type ) ;
void NPC_PrecacheWeapons ( team_t playerTeam , int spawnflags , char * NPCtype )
{
int weapons = NPC_WeaponsForTeam ( playerTeam , spawnflags , NPCtype ) ;
gitem_t * item ;
for ( int curWeap = WP_SABER ; curWeap < WP_NUM_WEAPONS ; curWeap + + )
{
if ( ( weapons & ( 1 < < curWeap ) ) )
{
item = FindItemForWeapon ( ( ( weapon_t ) ( curWeap ) ) ) ; //precache the weapon
CG_RegisterItemSounds ( ( item - bg_itemlist ) ) ;
CG_RegisterItemVisuals ( ( item - bg_itemlist ) ) ;
//precache the in-hand/in-world ghoul2 weapon model
char weaponModel [ 64 ] ;
strcpy ( weaponModel , weaponData [ curWeap ] . weaponMdl ) ;
if ( char * spot = strstr ( weaponModel , " .md3 " ) ) {
* spot = 0 ;
spot = strstr ( weaponModel , " _w " ) ; //i'm using the in view weapon array instead of scanning the item list, so put the _w back on
if ( ! spot ) {
strcat ( weaponModel , " _w " ) ;
}
strcat ( weaponModel , " .glm " ) ; //and change to ghoul2
}
gi . G2API_PrecacheGhoul2Model ( weaponModel ) ; // correct way is item->world_model
}
}
}
/*
void NPC_PrecacheByClassName ( char * NPCName )
This runs all the class specific precache functions
*/
extern void NPC_ShadowTrooper_Precache ( void ) ;
extern void NPC_Gonk_Precache ( void ) ;
extern void NPC_Mouse_Precache ( void ) ;
extern void NPC_Seeker_Precache ( void ) ;
extern void NPC_Remote_Precache ( void ) ;
extern void NPC_R2D2_Precache ( void ) ;
extern void NPC_R5D2_Precache ( void ) ;
extern void NPC_Probe_Precache ( void ) ;
extern void NPC_Interrogator_Precache ( gentity_t * self ) ;
extern void NPC_MineMonster_Precache ( void ) ;
extern void NPC_Howler_Precache ( void ) ;
extern void NPC_Rancor_Precache ( void ) ;
extern void NPC_MutantRancor_Precache ( void ) ;
extern void NPC_Wampa_Precache ( void ) ;
extern void NPC_ATST_Precache ( void ) ;
extern void NPC_Sentry_Precache ( void ) ;
extern void NPC_Mark1_Precache ( void ) ;
extern void NPC_Mark2_Precache ( void ) ;
extern void NPC_Protocol_Precache ( void ) ;
extern void Boba_Precache ( void ) ;
extern void RT_Precache ( void ) ;
extern void SandCreature_Precache ( void ) ;
extern void NPC_TavionScepter_Precache ( void ) ;
extern void NPC_TavionSithSword_Precache ( void ) ;
extern void NPC_Rosh_Dark_Precache ( void ) ;
extern void NPC_Tusken_Precache ( void ) ;
extern void NPC_Saboteur_Precache ( void ) ;
extern void NPC_CultistDestroyer_Precache ( void ) ;
void NPC_Jawa_Precache ( void )
{
for ( int i = 1 ; i < 7 ; i + + )
{
G_SoundIndex ( va ( " sound/chars/jawa/misc/chatter%d.wav " , i ) ) ;
}
G_SoundIndex ( " sound/chars/jawa/misc/ooh-tee-nee.wav " ) ;
}
void NPC_PrecacheByClassName ( const char * type )
{
if ( ! type | | ! type [ 0 ] )
{
return ;
}
if ( ! Q_stricmp ( " gonk " , type ) )
{
NPC_Gonk_Precache ( ) ;
}
else if ( ! Q_stricmp ( " mouse " , type ) )
{
NPC_Mouse_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " r2d2 " , type , 4 ) )
{
NPC_R2D2_Precache ( ) ;
}
else if ( ! Q_stricmp ( " atst " , type ) )
{
NPC_ATST_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " r5d2 " , type , 4 ) )
{
NPC_R5D2_Precache ( ) ;
}
else if ( ! Q_stricmp ( " mark1 " , type ) )
{
NPC_Mark1_Precache ( ) ;
}
else if ( ! Q_stricmp ( " mark2 " , type ) )
{
NPC_Mark2_Precache ( ) ;
}
else if ( ! Q_stricmp ( " interrogator " , type ) )
{
NPC_Interrogator_Precache ( NULL ) ;
}
else if ( ! Q_stricmp ( " probe " , type ) )
{
NPC_Probe_Precache ( ) ;
}
else if ( ! Q_stricmp ( " seeker " , type ) )
{
NPC_Seeker_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " remote " , type , 6 ) )
{
NPC_Remote_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " shadowtrooper " , type , 13 ) )
{
NPC_ShadowTrooper_Precache ( ) ;
}
else if ( ! Q_stricmp ( " minemonster " , type ) )
{
NPC_MineMonster_Precache ( ) ;
}
else if ( ! Q_stricmp ( " howler " , type ) )
{
NPC_Howler_Precache ( ) ;
}
else if ( ! Q_stricmp ( " rancor " , type ) )
{
NPC_Rancor_Precache ( ) ;
}
else if ( ! Q_stricmp ( " mutant_rancor " , type ) )
{
NPC_Rancor_Precache ( ) ;
NPC_MutantRancor_Precache ( ) ;
}
else if ( ! Q_stricmp ( " wampa " , type ) )
{
NPC_Wampa_Precache ( ) ;
}
else if ( ! Q_stricmp ( " sand_creature " , type ) )
{
SandCreature_Precache ( ) ;
}
else if ( ! Q_stricmp ( " sentry " , type ) )
{
NPC_Sentry_Precache ( ) ;
}
else if ( ! Q_stricmp ( " protocol " , type ) )
{
NPC_Protocol_Precache ( ) ;
}
else if ( ! Q_stricmp ( " boba_fett " , type ) )
{
Boba_Precache ( ) ;
}
else if ( ! Q_stricmp ( " rockettrooper2 " , type ) )
{
RT_Precache ( ) ;
}
else if ( ! Q_stricmp ( " rockettrooper2Officer " , type ) )
{
RT_Precache ( ) ;
}
else if ( ! Q_stricmp ( " tavion_scepter " , type ) )
{
NPC_TavionScepter_Precache ( ) ;
}
else if ( ! Q_stricmp ( " tavion_sith_sword " , type ) )
{
NPC_TavionSithSword_Precache ( ) ;
}
else if ( ! Q_stricmp ( " rosh_dark " , type ) )
{
NPC_Rosh_Dark_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " tusken " , type , 6 ) )
{
NPC_Tusken_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " saboteur " , type , 8 ) )
{
NPC_Saboteur_Precache ( ) ;
}
else if ( ! Q_stricmp ( " cultist_destroyer " , type ) )
{
NPC_CultistDestroyer_Precache ( ) ;
}
else if ( ! Q_stricmpn ( " jawa " , type , 4 ) )
{
NPC_Jawa_Precache ( ) ;
}
}
/*
void NPC_Precache ( char * NPCName )
Precaches NPC skins , tgas and md3s .
*/
void CG_NPC_Precache ( gentity_t * spawner )
{
clientInfo_t ci = { } ;
renderInfo_t ri = { } ;
team_t playerTeam = TEAM_FREE ;
const char * token ;
const char * value ;
const char * p ;
char * patch ;
char sound [ MAX_QPATH ] ;
qboolean md3Model = qfalse ;
char playerModel [ MAX_QPATH ] = { 0 } ;
char customSkin [ MAX_QPATH ] ;
if ( ! Q_stricmp ( " random " , spawner - > NPC_type ) )
{ //sorry, can't precache a random just yet
return ;
}
strcpy ( customSkin , " default " ) ;
p = NPCParms ;
COM_BeginParseSession ( ) ;
// look for the right NPC
while ( p )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( token [ 0 ] = = 0 )
{
COM_EndParseSession ( ) ;
return ;
}
if ( ! Q_stricmp ( token , spawner - > NPC_type ) )
{
break ;
}
SkipBracedSection ( & p ) ;
}
if ( ! p )
{
COM_EndParseSession ( ) ;
return ;
}
if ( G_ParseLiteral ( & p , " { " ) )
{
COM_EndParseSession ( ) ;
return ;
}
// parse the NPC info block
while ( 1 )
{
COM_EndParseSession ( ) ; // if still in session (or using continue;)
COM_BeginParseSession ( ) ;
token = COM_ParseExt ( & p , qtrue ) ;
if ( ! token [ 0 ] )
{
gi . Printf ( S_COLOR_RED " ERROR: unexpected EOF while parsing '%s' \n " , spawner - > NPC_type ) ;
COM_EndParseSession ( ) ;
return ;
}
if ( ! Q_stricmp ( token , " } " ) )
{
break ;
}
// headmodel
if ( ! Q_stricmp ( token , " headmodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! Q_stricmp ( " none " , value ) )
{
}
else
{
Q_strncpyz ( ri . headModelName , value , sizeof ( ri . headModelName ) ) ;
}
md3Model = qtrue ;
continue ;
}
// torsomodel
if ( ! Q_stricmp ( token , " torsomodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! Q_stricmp ( " none " , value ) )
{
}
else
{
Q_strncpyz ( ri . torsoModelName , value , sizeof ( ri . torsoModelName ) ) ;
}
md3Model = qtrue ;
continue ;
}
// legsmodel
if ( ! Q_stricmp ( token , " legsmodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
Q_strncpyz ( ri . legsModelName , value , sizeof ( ri . legsModelName ) ) ;
md3Model = qtrue ;
continue ;
}
// playerModel
if ( ! Q_stricmp ( token , " playerModel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
Q_strncpyz ( playerModel , value , sizeof ( playerModel ) ) ;
md3Model = qfalse ;
continue ;
}
// customSkin
if ( ! Q_stricmp ( token , " customSkin " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
Q_strncpyz ( customSkin , value , sizeof ( customSkin ) ) ;
continue ;
}
// playerTeam
if ( ! Q_stricmp ( token , " playerTeam " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
playerTeam = ( team_t ) GetIDForString ( TeamTable , token ) ;
continue ;
}
// snd
if ( ! Q_stricmp ( token , " snd " ) ) {
if ( COM_ParseString ( & p , & value ) ) {
continue ;
}
if ( ! ( spawner - > svFlags & SVF_NO_BASIC_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci . customBasicSoundDir = G_NewString ( sound ) ;
}
continue ;
}
// sndcombat
if ( ! Q_stricmp ( token , " sndcombat " ) ) {
if ( COM_ParseString ( & p , & value ) ) {
continue ;
}
if ( ! ( spawner - > svFlags & SVF_NO_COMBAT_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci . customCombatSoundDir = G_NewString ( sound ) ;
}
continue ;
}
// sndextra
if ( ! Q_stricmp ( token , " sndextra " ) ) {
if ( COM_ParseString ( & p , & value ) ) {
continue ;
}
if ( ! ( spawner - > svFlags & SVF_NO_EXTRA_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci . customExtraSoundDir = G_NewString ( sound ) ;
}
continue ;
}
// sndjedi
if ( ! Q_stricmp ( token , " sndjedi " ) ) {
if ( COM_ParseString ( & p , & value ) ) {
continue ;
}
if ( ! ( spawner - > svFlags & SVF_NO_EXTRA_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci . customJediSoundDir = G_NewString ( sound ) ;
}
continue ;
}
//cache weapons
if ( ! Q_stricmp ( token , " weapon " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
int weap = GetIDForString ( WPTable , value ) ;
if ( weap > = WP_NONE & & weap < WP_NUM_WEAPONS )
{
if ( weap > WP_NONE )
{
RegisterItem ( FindItemForWeapon ( ( weapon_t ) ( weap ) ) ) ; //precache the weapon
}
}
continue ;
}
//cache sabers
//saber name
if ( ! Q_stricmp ( token , " saber " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
char * saberName = G_NewString ( value ) ;
saberInfo_t saber ;
WP_SaberParseParms ( saberName , & saber ) ;
if ( saber . model & & saber . model [ 0 ] )
{
G_ModelIndex ( saber . model ) ;
}
if ( saber . skin & & saber . skin [ 0 ] )
{
gi . RE_RegisterSkin ( saber . skin ) ;
G_SkinIndex ( saber . skin ) ;
}
if ( saber . g2MarksShader [ 0 ] )
{
cgi_R_RegisterShader ( saber . g2MarksShader ) ;
}
if ( saber . g2MarksShader2 [ 0 ] )
{
cgi_R_RegisterShader ( saber . g2MarksShader2 ) ;
}
if ( saber . g2WeaponMarkShader [ 0 ] )
{
cgi_R_RegisterShader ( saber . g2WeaponMarkShader ) ;
}
if ( saber . g2WeaponMarkShader2 [ 0 ] )
{
cgi_R_RegisterShader ( saber . g2WeaponMarkShader2 ) ;
}
continue ;
}
//second saber name
if ( ! Q_stricmp ( token , " saber2 " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
char * saberName = G_NewString ( value ) ;
saberInfo_t saber ;
WP_SaberParseParms ( saberName , & saber ) ;
if ( saber . model & & saber . model [ 0 ] )
{
G_ModelIndex ( saber . model ) ;
}
if ( saber . skin & & saber . skin [ 0 ] )
{
gi . RE_RegisterSkin ( saber . skin ) ;
G_SkinIndex ( saber . skin ) ;
}
continue ;
}
}
COM_EndParseSession ( ) ;
if ( md3Model )
{
CG_RegisterClientRenderInfo ( & ci , & ri ) ;
}
else
{
char skinName [ MAX_QPATH ] ;
//precache ghoul2 model
gi . G2API_PrecacheGhoul2Model ( va ( " models/players/%s/model.glm " , playerModel ) ) ;
//precache skin
if ( strchr ( customSkin , ' | ' ) )
{ //three part skin
Com_sprintf ( skinName , sizeof ( skinName ) , " models/players/%s/|%s " , playerModel , customSkin ) ;
}
else
{ //standard skin
Com_sprintf ( skinName , sizeof ( skinName ) , " models/players/%s/model_%s.skin " , playerModel , customSkin ) ;
}
// lets see if it's out there
gi . RE_RegisterSkin ( skinName ) ;
}
//precache this NPC's possible weapons
NPC_PrecacheWeapons ( playerTeam , spawner - > spawnflags , spawner - > NPC_type ) ;
// Anything else special about them
NPC_PrecacheByClassName ( spawner - > NPC_type ) ;
CG_RegisterNPCCustomSounds ( & ci ) ;
//CG_RegisterNPCEffects( playerTeam );
//FIXME: Look for a "sounds" directory and precache death, pain, alert sounds
}
void NPC_BuildRandom ( gentity_t * NPC )
{
}
extern void G_MatchPlayerWeapon ( gentity_t * ent ) ;
extern void G_InitPlayerFromCvars ( gentity_t * ent ) ;
extern void G_SetG2PlayerModel ( gentity_t * const ent , const char * modelName , const char * customSkin , const char * surfOff , const char * surfOn ) ;
qboolean NPC_ParseParms ( const char * NPCName , gentity_t * NPC )
{
const char * token ;
const char * value ;
const char * p ;
int n ;
float f ;
char * patch ;
char sound [ MAX_QPATH ] ;
char playerModel [ MAX_QPATH ] ;
char customSkin [ MAX_QPATH ] ;
clientInfo_t * ci = & NPC - > client - > clientInfo ;
renderInfo_t * ri = & NPC - > client - > renderInfo ;
gNPCstats_t * stats = NULL ;
qboolean md3Model = qtrue ;
char surfOff [ 1024 ] = { 0 } ;
char surfOn [ 1024 ] = { 0 } ;
qboolean parsingPlayer = qfalse ;
strcpy ( customSkin , " default " ) ;
if ( ! NPCName | | ! NPCName [ 0 ] )
{
NPCName = " Player " ;
}
if ( ! NPC - > s . number & & NPC - > client ! = NULL )
{ //player, only want certain data
parsingPlayer = qtrue ;
}
if ( NPC - > NPC )
{
stats = & NPC - > NPC - > stats ;
/*
NPC - > NPC - > allWeaponOrder [ 0 ] = WP_BRYAR_PISTOL ;
NPC - > NPC - > allWeaponOrder [ 1 ] = WP_SABER ;
NPC - > NPC - > allWeaponOrder [ 2 ] = WP_IMOD ;
NPC - > NPC - > allWeaponOrder [ 3 ] = WP_SCAVENGER_RIFLE ;
NPC - > NPC - > allWeaponOrder [ 4 ] = WP_TRICORDER ;
NPC - > NPC - > allWeaponOrder [ 6 ] = WP_NONE ;
NPC - > NPC - > allWeaponOrder [ 6 ] = WP_NONE ;
NPC - > NPC - > allWeaponOrder [ 7 ] = WP_NONE ;
*/
// fill in defaults
stats - > sex = SEX_MALE ;
stats - > aggression = 3 ;
stats - > aim = 3 ;
stats - > earshot = 1024 ;
stats - > evasion = 3 ;
stats - > hfov = 90 ;
stats - > intelligence = 3 ;
stats - > move = 3 ;
stats - > reactions = 3 ;
stats - > vfov = 60 ;
stats - > vigilance = 0.1f ;
stats - > visrange = 1024 ;
if ( g_entities [ ENTITYNUM_WORLD ] . max_health & & stats - > visrange > g_entities [ ENTITYNUM_WORLD ] . max_health )
{
stats - > visrange = g_entities [ ENTITYNUM_WORLD ] . max_health ;
}
stats - > health = 0 ;
stats - > yawSpeed = 90 ;
stats - > walkSpeed = 90 ;
stats - > runSpeed = 300 ;
stats - > acceleration = 15 ; //Increase/descrease speed this much per frame (20fps)
}
else
{
stats = NULL ;
}
Q_strncpyz ( ci - > name , NPCName , sizeof ( ci - > name ) ) ;
NPC - > playerModel = - 1 ;
//Set defaults
//FIXME: should probably put default torso and head models, but what about enemies
//that don't have any- like Stasis?
//Q_strncpyz( ri->headModelName, DEFAULT_HEADMODEL, sizeof(ri->headModelName), qtrue);
//Q_strncpyz( ri->torsoModelName, DEFAULT_TORSOMODEL, sizeof(ri->torsoModelName), qtrue);
//Q_strncpyz( ri->legsModelName, DEFAULT_LEGSMODEL, sizeof(ri->legsModelName), qtrue);
ri - > headModelName [ 0 ] = 0 ;
ri - > torsoModelName [ 0 ] = 0 ;
ri - > legsModelName [ 0 ] = 0 ;
ri - > headYawRangeLeft = 80 ;
ri - > headYawRangeRight = 80 ;
ri - > headPitchRangeUp = 45 ;
ri - > headPitchRangeDown = 45 ;
ri - > torsoYawRangeLeft = 60 ;
ri - > torsoYawRangeRight = 60 ;
ri - > torsoPitchRangeUp = 30 ;
ri - > torsoPitchRangeDown = 50 ;
VectorCopy ( playerMins , NPC - > mins ) ;
VectorCopy ( playerMaxs , NPC - > maxs ) ;
NPC - > client - > crouchheight = CROUCH_MAXS_2 ;
NPC - > client - > standheight = DEFAULT_MAXS_2 ;
NPC - > client - > moveType = MT_RUNJUMP ;
NPC - > client - > dismemberProbHead = 100 ;
NPC - > client - > dismemberProbArms = 100 ;
NPC - > client - > dismemberProbHands = 100 ;
NPC - > client - > dismemberProbWaist = 100 ;
NPC - > client - > dismemberProbLegs = 100 ;
NPC - > s . modelScale [ 0 ] = NPC - > s . modelScale [ 1 ] = NPC - > s . modelScale [ 2 ] = 1.0f ;
ri - > customRGBA [ 0 ] = ri - > customRGBA [ 1 ] = ri - > customRGBA [ 2 ] = ri - > customRGBA [ 3 ] = 0xFFu ;
if ( ! Q_stricmp ( " random " , NPCName ) )
{ //Randomly assemble an NPC
NPC_BuildRandom ( NPC ) ;
}
else
{
p = NPCParms ;
COM_BeginParseSession ( ) ;
# ifdef _WIN32
# pragma region(NPC Stats)
# endif
// look for the right NPC
while ( p )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( token [ 0 ] = = 0 )
{
COM_EndParseSession ( ) ;
return qfalse ;
}
if ( ! Q_stricmp ( token , NPCName ) )
{
break ;
}
SkipBracedSection ( & p ) ;
}
if ( ! p )
{
COM_EndParseSession ( ) ;
return qfalse ;
}
if ( G_ParseLiteral ( & p , " { " ) )
{
COM_EndParseSession ( ) ;
return qfalse ;
}
// parse the NPC info block
while ( 1 )
{
token = COM_ParseExt ( & p , qtrue ) ;
if ( ! token [ 0 ] )
{
gi . Printf ( S_COLOR_RED " ERROR: unexpected EOF while parsing '%s' \n " , NPCName ) ;
COM_EndParseSession ( ) ;
return qfalse ;
}
if ( ! Q_stricmp ( token , " } " ) )
{
break ;
}
//===MODEL PROPERTIES===========================================================
// custom color
if ( ! Q_stricmp ( token , " customRGBA " ) )
{
// eezstreet TODO: Put these into functions, damn it! They're too big!
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! Q_stricmp ( value , " random " ) )
{
ri - > customRGBA [ 0 ] = Q_irand ( 0 , 255 ) ;
ri - > customRGBA [ 1 ] = Q_irand ( 0 , 255 ) ;
ri - > customRGBA [ 2 ] = Q_irand ( 0 , 255 ) ;
ri - > customRGBA [ 3 ] = 255 ;
}
else if ( ! Q_stricmp ( value , " random1 " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 5 ) )
{
default :
case 0 :
ri - > customRGBA [ 0 ] = 127 ;
ri - > customRGBA [ 1 ] = 153 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 1 :
ri - > customRGBA [ 0 ] = 177 ;
ri - > customRGBA [ 1 ] = 29 ;
ri - > customRGBA [ 2 ] = 13 ;
break ;
case 2 :
ri - > customRGBA [ 0 ] = 47 ;
ri - > customRGBA [ 1 ] = 90 ;
ri - > customRGBA [ 2 ] = 40 ;
break ;
case 3 :
ri - > customRGBA [ 0 ] = 181 ;
ri - > customRGBA [ 1 ] = 207 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 4 :
ri - > customRGBA [ 0 ] = 138 ;
ri - > customRGBA [ 1 ] = 83 ;
ri - > customRGBA [ 2 ] = 0 ;
break ;
case 5 :
ri - > customRGBA [ 0 ] = 254 ;
ri - > customRGBA [ 1 ] = 199 ;
ri - > customRGBA [ 2 ] = 14 ;
break ;
}
}
else if ( ! Q_stricmp ( value , " jedi_hf " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 7 ) )
{
default :
case 0 : //red1
ri - > customRGBA [ 0 ] = 165 ;
ri - > customRGBA [ 1 ] = 48 ;
ri - > customRGBA [ 2 ] = 21 ;
break ;
case 1 : //yellow1
ri - > customRGBA [ 0 ] = 254 ;
ri - > customRGBA [ 1 ] = 230 ;
ri - > customRGBA [ 2 ] = 132 ;
break ;
case 2 : //bluegray
ri - > customRGBA [ 0 ] = 181 ;
ri - > customRGBA [ 1 ] = 207 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 3 : //pink
ri - > customRGBA [ 0 ] = 233 ;
ri - > customRGBA [ 1 ] = 183 ;
ri - > customRGBA [ 2 ] = 208 ;
break ;
case 4 : //lt blue
ri - > customRGBA [ 0 ] = 161 ;
ri - > customRGBA [ 1 ] = 226 ;
ri - > customRGBA [ 2 ] = 240 ;
break ;
case 5 : //blue
ri - > customRGBA [ 0 ] = 101 ;
ri - > customRGBA [ 1 ] = 159 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 6 : //orange
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 157 ;
ri - > customRGBA [ 2 ] = 114 ;
break ;
case 7 : //violet
ri - > customRGBA [ 0 ] = 216 ;
ri - > customRGBA [ 1 ] = 160 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
}
}
else if ( ! Q_stricmp ( value , " jedi_hm " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 7 ) )
{
default :
case 0 : //yellow
ri - > customRGBA [ 0 ] = 252 ;
ri - > customRGBA [ 1 ] = 243 ;
ri - > customRGBA [ 2 ] = 180 ;
break ;
case 1 : //blue
ri - > customRGBA [ 0 ] = 69 ;
ri - > customRGBA [ 1 ] = 109 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 2 : //gold
ri - > customRGBA [ 0 ] = 254 ;
ri - > customRGBA [ 1 ] = 197 ;
ri - > customRGBA [ 2 ] = 73 ;
break ;
case 3 : //orange
ri - > customRGBA [ 0 ] = 178 ;
ri - > customRGBA [ 1 ] = 78 ;
ri - > customRGBA [ 2 ] = 18 ;
break ;
case 4 : //bluegreen
ri - > customRGBA [ 0 ] = 112 ;
ri - > customRGBA [ 1 ] = 153 ;
ri - > customRGBA [ 2 ] = 161 ;
break ;
case 5 : //blue2
ri - > customRGBA [ 0 ] = 123 ;
ri - > customRGBA [ 1 ] = 182 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 6 : //green2
ri - > customRGBA [ 0 ] = 0 ;
ri - > customRGBA [ 1 ] = 88 ;
ri - > customRGBA [ 2 ] = 105 ;
break ;
case 7 : //violet
ri - > customRGBA [ 0 ] = 138 ;
ri - > customRGBA [ 1 ] = 0 ;
ri - > customRGBA [ 2 ] = 0 ;
break ;
}
}
else if ( ! Q_stricmp ( value , " jedi_kdm " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 8 ) )
{
default :
case 0 : //blue
ri - > customRGBA [ 0 ] = 85 ;
ri - > customRGBA [ 1 ] = 120 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 1 : //violet
ri - > customRGBA [ 0 ] = 173 ;
ri - > customRGBA [ 1 ] = 142 ;
ri - > customRGBA [ 2 ] = 219 ;
break ;
case 2 : //brown1
ri - > customRGBA [ 0 ] = 254 ;
ri - > customRGBA [ 1 ] = 197 ;
ri - > customRGBA [ 2 ] = 73 ;
break ;
case 3 : //orange
ri - > customRGBA [ 0 ] = 138 ;
ri - > customRGBA [ 1 ] = 83 ;
ri - > customRGBA [ 2 ] = 0 ;
break ;
case 4 : //gold
ri - > customRGBA [ 0 ] = 254 ;
ri - > customRGBA [ 1 ] = 199 ;
ri - > customRGBA [ 2 ] = 14 ;
break ;
case 5 : //blue2
ri - > customRGBA [ 0 ] = 68 ;
ri - > customRGBA [ 1 ] = 194 ;
ri - > customRGBA [ 2 ] = 217 ;
break ;
case 6 : //red1
ri - > customRGBA [ 0 ] = 170 ;
ri - > customRGBA [ 1 ] = 3 ;
ri - > customRGBA [ 2 ] = 30 ;
break ;
case 7 : //yellow1
ri - > customRGBA [ 0 ] = 225 ;
ri - > customRGBA [ 1 ] = 226 ;
ri - > customRGBA [ 2 ] = 144 ;
break ;
case 8 : //violet2
ri - > customRGBA [ 0 ] = 167 ;
ri - > customRGBA [ 1 ] = 202 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
}
}
else if ( ! Q_stricmp ( value , " jedi_rm " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 8 ) )
{
default :
case 0 : //blue
ri - > customRGBA [ 0 ] = 127 ;
ri - > customRGBA [ 1 ] = 153 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 1 : //green1
ri - > customRGBA [ 0 ] = 208 ;
ri - > customRGBA [ 1 ] = 249 ;
ri - > customRGBA [ 2 ] = 85 ;
break ;
case 2 : //blue2
ri - > customRGBA [ 0 ] = 181 ;
ri - > customRGBA [ 1 ] = 207 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 3 : //gold
ri - > customRGBA [ 0 ] = 138 ;
ri - > customRGBA [ 1 ] = 83 ;
ri - > customRGBA [ 2 ] = 0 ;
break ;
case 4 : //gold
ri - > customRGBA [ 0 ] = 224 ;
ri - > customRGBA [ 1 ] = 171 ;
ri - > customRGBA [ 2 ] = 44 ;
break ;
case 5 : //green2
ri - > customRGBA [ 0 ] = 49 ;
ri - > customRGBA [ 1 ] = 155 ;
ri - > customRGBA [ 2 ] = 131 ;
break ;
case 6 : //red1
ri - > customRGBA [ 0 ] = 163 ;
ri - > customRGBA [ 1 ] = 79 ;
ri - > customRGBA [ 2 ] = 17 ;
break ;
case 7 : //violet2
ri - > customRGBA [ 0 ] = 148 ;
ri - > customRGBA [ 1 ] = 104 ;
ri - > customRGBA [ 2 ] = 228 ;
break ;
case 8 : //green3
ri - > customRGBA [ 0 ] = 138 ;
ri - > customRGBA [ 1 ] = 136 ;
ri - > customRGBA [ 2 ] = 0 ;
break ;
}
}
else if ( ! Q_stricmp ( value , " jedi_tf " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 5 ) )
{
default :
case 0 : //green1
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 235 ;
ri - > customRGBA [ 2 ] = 100 ;
break ;
case 1 : //blue1
ri - > customRGBA [ 0 ] = 62 ;
ri - > customRGBA [ 1 ] = 155 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 2 : //red1
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 110 ;
ri - > customRGBA [ 2 ] = 120 ;
break ;
case 3 : //purple
ri - > customRGBA [ 0 ] = 180 ;
ri - > customRGBA [ 1 ] = 150 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 4 : //flesh
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 200 ;
ri - > customRGBA [ 2 ] = 212 ;
break ;
case 5 : //base
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 255 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
}
}
else if ( ! Q_stricmp ( value , " jedi_zf " ) )
{
ri - > customRGBA [ 3 ] = 255 ;
switch ( Q_irand ( 0 , 7 ) )
{
default :
case 0 : //red1
ri - > customRGBA [ 0 ] = 204 ;
ri - > customRGBA [ 1 ] = 19 ;
ri - > customRGBA [ 2 ] = 21 ;
break ;
case 1 : //orange1
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 107 ;
ri - > customRGBA [ 2 ] = 40 ;
break ;
case 2 : //pink1
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 148 ;
ri - > customRGBA [ 2 ] = 155 ;
break ;
case 3 : //gold
ri - > customRGBA [ 0 ] = 255 ;
ri - > customRGBA [ 1 ] = 164 ;
ri - > customRGBA [ 2 ] = 59 ;
break ;
case 4 : //violet1
ri - > customRGBA [ 0 ] = 216 ;
ri - > customRGBA [ 1 ] = 160 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 5 : //blue1
ri - > customRGBA [ 0 ] = 101 ;
ri - > customRGBA [ 1 ] = 159 ;
ri - > customRGBA [ 2 ] = 255 ;
break ;
case 6 : //blue2
ri - > customRGBA [ 0 ] = 161 ;
ri - > customRGBA [ 1 ] = 226 ;
ri - > customRGBA [ 2 ] = 240 ;
break ;
case 7 : //blue3
ri - > customRGBA [ 0 ] = 37 ;
ri - > customRGBA [ 1 ] = 155 ;
ri - > customRGBA [ 2 ] = 181 ;
break ;
}
}
else
{
ri - > customRGBA [ 0 ] = atoi ( value ) ;
if ( COM_ParseInt ( & p , & n ) )
{
continue ;
}
ri - > customRGBA [ 1 ] = n ;
if ( COM_ParseInt ( & p , & n ) )
{
continue ;
}
ri - > customRGBA [ 2 ] = n ;
if ( COM_ParseInt ( & p , & n ) )
{
continue ;
}
ri - > customRGBA [ 3 ] = n ;
}
continue ;
}
// headmodel
if ( ! Q_stricmp ( token , " headmodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! Q_stricmp ( " none " , value ) )
{
ri - > headModelName [ 0 ] = ' \0 ' ;
//Zero the head clamp range so the torso & legs don't lag behind
ri - > headYawRangeLeft =
ri - > headYawRangeRight =
ri - > headPitchRangeUp =
ri - > headPitchRangeDown = 0 ;
}
else
{
Q_strncpyz ( ri - > headModelName , value , sizeof ( ri - > headModelName ) ) ;
}
continue ;
}
// torsomodel
if ( ! Q_stricmp ( token , " torsomodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! Q_stricmp ( " none " , value ) )
{
ri - > torsoModelName [ 0 ] = ' \0 ' ;
//Zero the torso clamp range so the legs don't lag behind
ri - > torsoYawRangeLeft =
ri - > torsoYawRangeRight =
ri - > torsoPitchRangeUp =
ri - > torsoPitchRangeDown = 0 ;
}
else
{
Q_strncpyz ( ri - > torsoModelName , value , sizeof ( ri - > torsoModelName ) ) ;
}
continue ;
}
// legsmodel
if ( ! Q_stricmp ( token , " legsmodel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
Q_strncpyz ( ri - > legsModelName , value , sizeof ( ri - > legsModelName ) ) ;
//Need to do this here to get the right index
ci - > animFileIndex = G_ParseAnimFileSet ( ri - > legsModelName ) ;
continue ;
}
// playerModel
if ( ! Q_stricmp ( token , " playerModel " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
Q_strncpyz ( playerModel , value , sizeof ( playerModel ) ) ;
md3Model = qfalse ;
continue ;
}
// customSkin
if ( ! Q_stricmp ( token , " customSkin " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
Q_strncpyz ( customSkin , value , sizeof ( customSkin ) ) ;
continue ;
}
// surfOff
if ( ! Q_stricmp ( token , " surfOff " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( surfOff [ 0 ] )
{
Q_strcat ( surfOff , sizeof ( surfOff ) , " , " ) ;
Q_strcat ( surfOff , sizeof ( surfOff ) , value ) ;
}
else
{
Q_strncpyz ( surfOff , value , sizeof ( surfOff ) ) ;
}
continue ;
}
// surfOn
if ( ! Q_stricmp ( token , " surfOn " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( surfOn [ 0 ] )
{
Q_strcat ( surfOn , sizeof ( surfOn ) , " , " ) ;
Q_strcat ( surfOn , sizeof ( surfOn ) , value ) ;
}
else
{
Q_strncpyz ( surfOn , value , sizeof ( surfOn ) ) ;
}
continue ;
}
//headYawRangeLeft
if ( ! Q_stricmp ( token , " headYawRangeLeft " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > headYawRangeLeft = n ;
continue ;
}
//headYawRangeRight
if ( ! Q_stricmp ( token , " headYawRangeRight " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > headYawRangeRight = n ;
continue ;
}
//headPitchRangeUp
if ( ! Q_stricmp ( token , " headPitchRangeUp " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > headPitchRangeUp = n ;
continue ;
}
//headPitchRangeDown
if ( ! Q_stricmp ( token , " headPitchRangeDown " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > headPitchRangeDown = n ;
continue ;
}
//torsoYawRangeLeft
if ( ! Q_stricmp ( token , " torsoYawRangeLeft " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > torsoYawRangeLeft = n ;
continue ;
}
//torsoYawRangeRight
if ( ! Q_stricmp ( token , " torsoYawRangeRight " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > torsoYawRangeRight = n ;
continue ;
}
//torsoPitchRangeUp
if ( ! Q_stricmp ( token , " torsoPitchRangeUp " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > torsoPitchRangeUp = n ;
continue ;
}
//torsoPitchRangeDown
if ( ! Q_stricmp ( token , " torsoPitchRangeDown " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
ri - > torsoPitchRangeDown = n ;
continue ;
}
// Uniform XYZ scale
if ( ! Q_stricmp ( token , " scale " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( n ! = 100 )
{
NPC - > s . modelScale [ 0 ] = NPC - > s . modelScale [ 1 ] = NPC - > s . modelScale [ 2 ] = n / 100.0f ;
}
continue ;
}
//X scale
if ( ! Q_stricmp ( token , " scaleX " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( n ! = 100 )
{
NPC - > s . modelScale [ 0 ] = n / 100.0f ;
}
continue ;
}
//Y scale
if ( ! Q_stricmp ( token , " scaleY " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( n ! = 100 )
{
NPC - > s . modelScale [ 1 ] = n / 100.0f ;
}
continue ;
}
//Z scale
if ( ! Q_stricmp ( token , " scaleZ " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( n ! = 100 )
{
NPC - > s . modelScale [ 2 ] = n / 100.0f ;
}
continue ;
}
//===AI STATS=====================================================================
if ( ! parsingPlayer )
{
// aggression
if ( ! Q_stricmp ( token , " aggression " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 5 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > aggression = n ;
}
continue ;
}
// aim
if ( ! Q_stricmp ( token , " aim " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 5 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > aim = n ;
}
continue ;
}
// earshot
if ( ! Q_stricmp ( token , " earshot " ) ) {
if ( COM_ParseFloat ( & p , & f ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( f < 0.0f )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > earshot = f ;
}
continue ;
}
// evasion
if ( ! Q_stricmp ( token , " evasion " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 5 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > evasion = n ;
}
continue ;
}
// hfov
if ( ! Q_stricmp ( token , " hfov " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 180 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > hfov = n ; // / 2; //FIXME: Why was this being done?!
}
continue ;
}
// intelligence
if ( ! Q_stricmp ( token , " intelligence " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 5 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > intelligence = n ;
}
continue ;
}
// move
if ( ! Q_stricmp ( token , " move " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 5 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > move = n ;
}
continue ;
}
// reactions
if ( ! Q_stricmp ( token , " reactions " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 1 | | n > 5 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > reactions = n ;
}
continue ;
}
// shootDistance
if ( ! Q_stricmp ( token , " shootDistance " ) ) {
if ( COM_ParseFloat ( & p , & f ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( f < 0.0f )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > shootDistance = f ;
}
continue ;
}
// vfov
if ( ! Q_stricmp ( token , " vfov " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 2 | | n > 360 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > vfov = n / 2 ;
}
continue ;
}
// vigilance
if ( ! Q_stricmp ( token , " vigilance " ) ) {
if ( COM_ParseFloat ( & p , & f ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( f < 0.0f )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > vigilance = f ;
}
continue ;
}
// visrange
if ( ! Q_stricmp ( token , " visrange " ) ) {
if ( COM_ParseFloat ( & p , & f ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( f < 0.0f )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > visrange = f ;
if ( g_entities [ ENTITYNUM_WORLD ] . max_health & & stats - > visrange > g_entities [ ENTITYNUM_WORLD ] . max_health )
{
stats - > visrange = g_entities [ ENTITYNUM_WORLD ] . max_health ;
}
}
continue ;
}
// race
// if ( !Q_stricmp( token, "race" ) )
// {
// if ( COM_ParseString( &p, &value ) )
// {
// continue;
// }
// NPC->client->race = TranslateRaceName(value);
// continue;
// }
// rank
if ( ! Q_stricmp ( token , " rank " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( NPC - > NPC )
{
NPC - > NPC - > rank = TranslateRankName ( value ) ;
}
continue ;
}
}
// health
if ( ! Q_stricmp ( token , " health " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > health = n ;
}
else if ( parsingPlayer )
{
NPC - > client - > ps . stats [ STAT_MAX_HEALTH ] = NPC - > client - > pers . maxHealth = NPC - > max_health = n ;
}
continue ;
}
// fullName
if ( ! Q_stricmp ( token , " fullName " ) )
{
# ifndef FINAL_BUILD
gi . Printf ( S_COLOR_YELLOW " WARNING: fullname ignored in NPC '%s' \n " , NPCName ) ;
# endif
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
continue ;
}
// playerTeam
if ( ! Q_stricmp ( token , " playerTeam " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
NPC - > client - > playerTeam = ( team_t ) GetIDForString ( TeamTable , value ) ;
continue ;
}
// enemyTeam
if ( ! Q_stricmp ( token , " enemyTeam " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
NPC - > client - > enemyTeam = ( team_t ) GetIDForString ( TeamTable , value ) ;
continue ;
}
// class
if ( ! Q_stricmp ( token , " class " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
NPC - > client - > NPC_class = ( class_t ) GetIDForString ( ClassTable , value ) ;
// No md3's for vehicles.
if ( NPC - > client - > NPC_class = = CLASS_VEHICLE )
{
if ( ! NPC - > m_pVehicle )
{ //you didn't spawn this guy right!
Com_Printf ( S_COLOR_RED " ERROR: Tried to spawn a vehicle NPC (%s) without using NPC_Vehicle or 'NPC spawn vehicle <vehiclename>'!!! Bad, bad, bad! Shame on you! \n " , NPCName ) ;
COM_EndParseSession ( ) ;
return qfalse ;
}
md3Model = qfalse ;
}
continue ;
}
// dismemberment probability for head
if ( ! Q_stricmp ( token , " dismemberProbHead " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
NPC - > client - > dismemberProbHead = n ;
}
continue ;
}
// dismemberment probability for arms
if ( ! Q_stricmp ( token , " dismemberProbArms " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
NPC - > client - > dismemberProbArms = n ;
}
continue ;
}
// dismemberment probability for hands
if ( ! Q_stricmp ( token , " dismemberProbHands " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
NPC - > client - > dismemberProbHands = n ;
}
continue ;
}
// dismemberment probability for waist
if ( ! Q_stricmp ( token , " dismemberProbWaist " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
NPC - > client - > dismemberProbWaist = n ;
}
continue ;
}
// dismemberment probability for legs
if ( ! Q_stricmp ( token , " dismemberProbLegs " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
NPC - > client - > dismemberProbLegs = n ;
}
continue ;
}
//===MOVEMENT STATS============================================================
if ( ! Q_stricmp ( token , " width " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
continue ;
}
NPC - > mins [ 0 ] = NPC - > mins [ 1 ] = - n ;
NPC - > maxs [ 0 ] = NPC - > maxs [ 1 ] = n ;
continue ;
}
if ( ! Q_stricmp ( token , " height " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
continue ;
}
if ( NPC - > client - > NPC_class = = CLASS_VEHICLE
& & NPC - > m_pVehicle
& & NPC - > m_pVehicle - > m_pVehicleInfo
& & NPC - > m_pVehicle - > m_pVehicleInfo - > type = = VH_FIGHTER )
{ //a flying vehicle's origin must be centered in bbox
NPC - > maxs [ 2 ] = NPC - > client - > standheight = ( n / 2.0f ) ;
NPC - > mins [ 2 ] = - NPC - > maxs [ 2 ] ;
NPC - > s . origin [ 2 ] + = ( DEFAULT_MINS_2 - NPC - > mins [ 2 ] ) + 0.125f ;
VectorCopy ( NPC - > s . origin , NPC - > client - > ps . origin ) ;
VectorCopy ( NPC - > s . origin , NPC - > currentOrigin ) ;
G_SetOrigin ( NPC , NPC - > s . origin ) ;
gi . linkentity ( NPC ) ;
}
else
{
NPC - > mins [ 2 ] = DEFAULT_MINS_2 ; //Cannot change
NPC - > maxs [ 2 ] = NPC - > client - > standheight = n + DEFAULT_MINS_2 ;
}
NPC - > s . radius = n ;
continue ;
}
if ( ! Q_stricmp ( token , " crouchheight " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
continue ;
}
NPC - > client - > crouchheight = n + DEFAULT_MINS_2 ;
continue ;
}
if ( ! parsingPlayer )
{
if ( ! Q_stricmp ( token , " movetype " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
NPC - > client - > moveType = ( movetype_t ) MoveTypeNameToEnum ( value ) ;
continue ;
}
// yawSpeed
if ( ! Q_stricmp ( token , " yawSpeed " ) ) {
if ( COM_ParseInt ( & p , & n ) ) {
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < = 0 ) {
gi . Printf ( " bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > yawSpeed = ( ( float ) ( n ) ) ;
}
continue ;
}
// walkSpeed
if ( ! Q_stricmp ( token , " walkSpeed " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > walkSpeed = n ;
}
continue ;
}
//runSpeed
if ( ! Q_stricmp ( token , " runSpeed " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > runSpeed = n ;
}
continue ;
}
//acceleration
if ( ! Q_stricmp ( token , " acceleration " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < 0 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
stats - > acceleration = n ;
}
continue ;
}
//sex
if ( ! Q_stricmp ( token , " sex " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( value [ 0 ] = = ' m ' )
{ //male
stats - > sex = SEX_MALE ;
}
else if ( value [ 0 ] = = ' n ' )
{ //neutral
stats - > sex = SEX_NEUTRAL ;
}
else if ( value [ 0 ] = = ' a ' )
{ //asexual?
stats - > sex = SEX_NEUTRAL ;
}
else if ( value [ 0 ] = = ' f ' )
{ //female
stats - > sex = SEX_FEMALE ;
}
else if ( value [ 0 ] = = ' s ' )
{ //shemale?
stats - > sex = SEX_SHEMALE ;
}
else if ( value [ 0 ] = = ' h ' )
{ //hermaphrodite?
stats - > sex = SEX_SHEMALE ;
}
else if ( value [ 0 ] = = ' t ' )
{ //transsexual/transvestite?
stats - > sex = SEX_SHEMALE ;
}
continue ;
}
//===MISC===============================================================================
// default behavior
if ( ! Q_stricmp ( token , " behavior " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( n < BS_DEFAULT | | n > = NUM_BSTATES )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad %s in NPC '%s' \n " , token , NPCName ) ;
continue ;
}
if ( NPC - > NPC )
{
NPC - > NPC - > defaultBehavior = ( bState_t ) ( n ) ;
}
continue ;
}
}
// snd
if ( ! Q_stricmp ( token , " snd " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! ( NPC - > svFlags & SVF_NO_BASIC_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci - > customBasicSoundDir = G_NewString ( sound ) ;
}
continue ;
}
// sndcombat
if ( ! Q_stricmp ( token , " sndcombat " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! ( NPC - > svFlags & SVF_NO_COMBAT_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci - > customCombatSoundDir = G_NewString ( sound ) ;
}
continue ;
}
// sndextra
if ( ! Q_stricmp ( token , " sndextra " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! ( NPC - > svFlags & SVF_NO_EXTRA_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci - > customExtraSoundDir = G_NewString ( sound ) ;
}
continue ;
}
// sndjedi
if ( ! Q_stricmp ( token , " sndjedi " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! ( NPC - > svFlags & SVF_NO_EXTRA_SOUNDS ) )
{
//FIXME: store this in some sound field or parse in the soundTable like the animTable...
Q_strncpyz ( sound , value , sizeof ( sound ) ) ;
patch = strstr ( sound , " / " ) ;
if ( patch )
{
* patch = 0 ;
}
ci - > customJediSoundDir = G_NewString ( sound ) ;
}
continue ;
}
//New NPC/jedi stats:
//starting weapon
if ( ! Q_stricmp ( token , " weapon " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
//FIXME: need to precache the weapon, too? (in above func)
int weap = GetIDForString ( WPTable , value ) ;
if ( weap > = WP_NONE & & weap < WP_NUM_WEAPONS )
{
NPC - > client - > ps . weapon = weap ;
NPC - > client - > ps . stats [ STAT_WEAPONS ] | = ( 1 < < weap ) ;
if ( weap > WP_NONE )
{
RegisterItem ( FindItemForWeapon ( ( weapon_t ) ( weap ) ) ) ; //precache the weapon
NPC - > client - > ps . ammo [ weaponData [ weap ] . ammoIndex ] = ammoData [ weaponData [ weap ] . ammoIndex ] . max ;
}
}
continue ;
}
if ( ! parsingPlayer )
{
//altFire
if ( ! Q_stricmp ( token , " altFire " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
if ( NPC - > NPC )
{
if ( n ! = 0 )
{
NPC - > NPC - > scriptFlags | = SCF_ALT_FIRE ;
}
}
continue ;
}
//Other unique behaviors/numbers that are currently hardcoded?
}
//force powers
int fp = GetIDForString ( FPTable , token ) ;
if ( fp > = FP_FIRST & & fp < NUM_FORCE_POWERS )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
//FIXME: need to precache the fx, too? (in above func)
//cap
if ( n > 5 )
{
n = 5 ;
}
else if ( n < 0 )
{
n = 0 ;
}
if ( n )
{ //set
NPC - > client - > ps . forcePowersKnown | = ( 1 < < fp ) ;
}
else
{ //clear
NPC - > client - > ps . forcePowersKnown & = ~ ( 1 < < fp ) ;
}
NPC - > client - > ps . forcePowerLevel [ fp ] = n ;
continue ;
}
//max force power
if ( ! Q_stricmp ( token , " forcePowerMax " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
NPC - > client - > ps . forcePowerMax = n ;
continue ;
}
//force regen rate - default is 100ms
if ( ! Q_stricmp ( token , " forceRegenRate " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
NPC - > client - > ps . forcePowerRegenRate = n ;
continue ;
}
//force regen amount - default is 1 (points per second)
if ( ! Q_stricmp ( token , " forceRegenAmount " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
NPC - > client - > ps . forcePowerRegenAmount = n ;
continue ;
}
//have a sabers.cfg and just name your saber in your NPCs.cfg/ICARUS script
//saber name
if ( ! Q_stricmp ( token , " saber " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
char * saberName = G_NewString ( value ) ;
WP_SaberParseParms ( saberName , & NPC - > client - > ps . saber [ 0 ] ) ;
//if it requires a specific style, make sure we know how to use it
if ( NPC - > client - > ps . saber [ 0 ] . stylesLearned )
{
NPC - > client - > ps . saberStylesKnown | = NPC - > client - > ps . saber [ 0 ] . stylesLearned ;
}
if ( NPC - > client - > ps . saber [ 0 ] . singleBladeStyle )
{
NPC - > client - > ps . saberStylesKnown | = NPC - > client - > ps . saber [ 0 ] . singleBladeStyle ;
}
continue ;
}
//second saber name
if ( ! Q_stricmp ( token , " saber2 " ) )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
if ( ! ( NPC - > client - > ps . saber [ 0 ] . saberFlags & SFL_TWO_HANDED ) )
{ //can't use a second saber if first one is a two-handed saber...?
char * saberName = G_NewString ( value ) ;
WP_SaberParseParms ( saberName , & NPC - > client - > ps . saber [ 1 ] ) ;
if ( NPC - > client - > ps . saber [ 1 ] . stylesLearned )
{
NPC - > client - > ps . saberStylesKnown | = NPC - > client - > ps . saber [ 1 ] . stylesLearned ;
}
if ( NPC - > client - > ps . saber [ 1 ] . singleBladeStyle )
{
NPC - > client - > ps . saberStylesKnown | = NPC - > client - > ps . saber [ 1 ] . singleBladeStyle ;
}
if ( ( NPC - > client - > ps . saber [ 1 ] . saberFlags & SFL_TWO_HANDED ) )
{ //tsk tsk, can't use a twoHanded saber as second saber
WP_RemoveSaber ( NPC , 1 ) ;
}
else
{
NPC - > client - > ps . dualSabers = qtrue ;
}
}
continue ;
}
// saberColor
if ( ! Q_stricmpn ( token , " saberColor " , 10 ) )
{
if ( ! NPC - > client )
{
continue ;
}
if ( strlen ( token ) = = 10 )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
saber_colors_t color = TranslateSaberColor ( value ) ;
for ( n = 0 ; n < MAX_BLADES ; n + + )
{
NPC - > client - > ps . saber [ 0 ] . blade [ n ] . color = color ;
}
}
else if ( strlen ( token ) = = 11 )
{
int index = atoi ( & token [ 10 ] ) - 1 ;
if ( index > 7 | | index < 1 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saberColor '%s' in %s \n " , token , NPCName ) ;
continue ;
}
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
NPC - > client - > ps . saber [ 0 ] . blade [ index ] . color = TranslateSaberColor ( value ) ;
}
else
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saberColor '%s' in %s \n " , token , NPCName ) ;
}
continue ;
}
if ( ! Q_stricmpn ( token , " saber2Color " , 11 ) )
{
if ( ! NPC - > client )
{
continue ;
}
if ( strlen ( token ) = = 11 )
{
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
saber_colors_t color = TranslateSaberColor ( value ) ;
for ( n = 0 ; n < MAX_BLADES ; n + + )
{
NPC - > client - > ps . saber [ 1 ] . blade [ n ] . color = color ;
}
}
else if ( strlen ( token ) = = 12 )
{
n = atoi ( & token [ 11 ] ) - 1 ;
if ( n > 7 | | n < 1 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saber2Color '%s' in %s \n " , token , NPCName ) ;
continue ;
}
if ( COM_ParseString ( & p , & value ) )
{
continue ;
}
NPC - > client - > ps . saber [ 1 ] . blade [ n ] . color = TranslateSaberColor ( value ) ;
}
else
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saber2Color '%s' in %s \n " , token , NPCName ) ;
}
continue ;
}
//saber length
if ( ! Q_stricmpn ( token , " saberLength " , 11 ) )
{
if ( strlen ( token ) = = 11 )
{
n = - 1 ;
}
else if ( strlen ( token ) = = 12 )
{
n = atoi ( & token [ 11 ] ) - 1 ;
if ( n > 7 | | n < 1 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saberLength '%s' in %s \n " , token , NPCName ) ;
continue ;
}
}
else
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saberLength '%s' in %s \n " , token , NPCName ) ;
continue ;
}
if ( COM_ParseFloat ( & p , & f ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
//cap
if ( f < 4.0f )
{
f = 4.0f ;
}
if ( n = = - 1 ) //do them all
{
for ( n = 0 ; n < MAX_BLADES ; n + + )
{
NPC - > client - > ps . saber [ 0 ] . blade [ n ] . lengthMax = f ;
}
}
else //just one
{
NPC - > client - > ps . saber [ 0 ] . blade [ n ] . lengthMax = f ;
}
continue ;
}
if ( ! Q_stricmpn ( token , " saber2Length " , 12 ) )
{
if ( strlen ( token ) = = 12 )
{
n = - 1 ;
}
else if ( strlen ( token ) = = 13 )
{
n = atoi ( & token [ 12 ] ) - 1 ;
if ( n > 7 | | n < 1 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saber2Length '%s' in %s \n " , token , NPCName ) ;
continue ;
}
}
else
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saber2Length '%s' in %s \n " , token , NPCName ) ;
continue ;
}
if ( COM_ParseFloat ( & p , & f ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
//cap
if ( f < 4.0f )
{
f = 4.0f ;
}
if ( n = = - 1 ) //do them all
{
for ( n = 0 ; n < MAX_BLADES ; n + + )
{
NPC - > client - > ps . saber [ 1 ] . blade [ n ] . lengthMax = f ;
}
}
else //just one
{
NPC - > client - > ps . saber [ 1 ] . blade [ n ] . lengthMax = f ;
}
continue ;
}
//saber radius
if ( ! Q_stricmpn ( token , " saberRadius " , 11 ) )
{
if ( strlen ( token ) = = 11 )
{
n = - 1 ;
}
else if ( strlen ( token ) = = 12 )
{
n = atoi ( & token [ 11 ] ) - 1 ;
if ( n > 7 | | n < 1 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saberRadius '%s' in %s \n " , token , NPCName ) ;
continue ;
}
}
else
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saberRadius '%s' in %s \n " , token , NPCName ) ;
continue ;
}
if ( COM_ParseFloat ( & p , & f ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
//cap
if ( f < 0.25f )
{
f = 0.25f ;
}
if ( n = = - 1 )
{ //NOTE: this fills in the rest of the blades with the same length by default
for ( n = 0 ; n < MAX_BLADES ; n + + )
{
NPC - > client - > ps . saber [ 0 ] . blade [ n ] . radius = f ;
}
}
else
{
NPC - > client - > ps . saber [ 0 ] . blade [ n ] . radius = f ;
}
continue ;
}
if ( ! Q_stricmpn ( token , " saber2Radius " , 12 ) )
{
if ( strlen ( token ) = = 12 )
{
n = - 1 ;
}
else if ( strlen ( token ) = = 13 )
{
n = atoi ( & token [ 12 ] ) - 1 ;
if ( n > 7 | | n < 1 )
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saber2Radius '%s' in %s \n " , token , NPCName ) ;
continue ;
}
}
else
{
gi . Printf ( S_COLOR_YELLOW " WARNING: bad saber2Radius '%s' in %s \n " , token , NPCName ) ;
continue ;
}
if ( COM_ParseFloat ( & p , & f ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
//cap
if ( f < 0.25f )
{
f = 0.25f ;
}
if ( n = = - 1 )
{ //NOTE: this fills in the rest of the blades with the same length by default
for ( n = 0 ; n < MAX_BLADES ; n + + )
{
NPC - > client - > ps . saber [ 1 ] . blade [ n ] . radius = f ;
}
}
else
{
NPC - > client - > ps . saber [ 1 ] . blade [ n ] . radius = f ;
}
continue ;
}
//ADD:
//saber sounds (on, off, loop)
//loop sound (like Vader's breathing or droid bleeps, etc.)
//starting saber style
if ( ! Q_stricmp ( token , " saberStyle " ) )
{
if ( COM_ParseInt ( & p , & n ) )
{
SkipRestOfLine ( & p ) ;
continue ;
}
//cap
if ( n > SS_STAFF )
{
n = SS_STAFF ;
}
else if ( n < SS_FAST )
{
n = SS_FAST ;
}
if ( n )
{ //set
NPC - > client - > ps . saberStylesKnown | = ( 1 < < n ) ;
}
else
{ //clear
NPC - > client - > ps . saberStylesKnown & = ~ ( 1 < < n ) ;
}
NPC - > client - > ps . saberAnimLevel = n ;
if ( parsingPlayer )
{
cg . saberAnimLevelPending = n ;
}
continue ;
}
if ( ! parsingPlayer )
{
gi . Printf ( " WARNING: unknown keyword '%s' while parsing '%s' \n " , token , NPCName ) ;
}
SkipRestOfLine ( & p ) ;
}
# ifdef _WIN32
# pragma endregion
# endif
COM_EndParseSession ( ) ;
}
ci - > infoValid = qfalse ;
/*
Ghoul2 Insert Start
*/
if ( ! md3Model )
{
NPC - > weaponModel [ 0 ] = - 1 ;
if ( Q_stricmp ( " player " , playerModel ) = = 0 )
{ //set the model from the console cvars
G_InitPlayerFromCvars ( NPC ) ;
//now set the weapon, etc.
G_MatchPlayerWeapon ( NPC ) ;
//NPC->NPC->aiFlags |= NPCAI_MATCHPLAYERWEAPON;//FIXME: may not always want this
}
else
{ //do a normal model load
// If this is a vehicle, set the model name from the vehicle type array.
if ( NPC - > client - > NPC_class = = CLASS_VEHICLE )
{
int iVehIndex = BG_VehicleGetIndex ( NPC - > NPC_type ) ;
strcpy ( customSkin , " default " ) ; // Ignore any custom skin that may have come from the NPC File
Q_strncpyz ( playerModel , g_vehicleInfo [ iVehIndex ] . model , sizeof ( playerModel ) ) ;
if ( g_vehicleInfo [ iVehIndex ] . skin & & g_vehicleInfo [ iVehIndex ] . skin [ 0 ] )
{
bool forceSkin = false ;
// Iterate Over All Possible Skins
//---------------------------------
ratl : : vector_vs < hstring , 15 > skinarray ;
ratl : : string_vs < 256 > skins ( g_vehicleInfo [ iVehIndex ] . skin ) ;
for ( ratl : : string_vs < 256 > : : tokenizer i = skins . begin ( " | " ) ; i ! = skins . end ( ) ; i + + )
{
if ( NPC - > soundSet & & NPC - > soundSet [ 0 ] & & Q_stricmp ( * i , NPC - > soundSet ) = = 0 )
{
forceSkin = true ;
}
skinarray . push_back ( * i ) ;
}
// Soundset Is The Designer Set Way To Supply A Skin
//---------------------------------------------------
if ( forceSkin )
{
Q_strncpyz ( customSkin , NPC - > soundSet , sizeof ( customSkin ) ) ;
}
// Otherwise Choose A Random Skin
//--------------------------------
else
{
if ( NPC - > soundSet & & NPC - > soundSet [ 0 ] )
{
gi . Printf ( S_COLOR_RED " WARNING: Unable to use skin (%s) " , NPC - > soundSet ) ;
}
Q_strncpyz ( customSkin , * skinarray [ Q_irand ( 0 , skinarray . size ( ) - 1 ) ] , sizeof ( customSkin ) ) ;
}
if ( NPC - > soundSet & & gi . bIsFromZone ( NPC - > soundSet , TAG_G_ALLOC ) ) {
gi . Free ( NPC - > soundSet ) ;
}
NPC - > soundSet = 0 ; // clear the pointer
}
}
G_SetG2PlayerModel ( NPC , playerModel , customSkin , surfOff , surfOn ) ;
}
}
/*
Ghoul2 Insert End
*/
if ( NPCsPrecached )
{ //Spawning in after initial precache, our models are precached, we just need to set our clientInfo
CG_RegisterClientModels ( NPC - > s . number ) ;
CG_RegisterNPCCustomSounds ( ci ) ;
//CG_RegisterNPCEffects( NPC->client->playerTeam );
}
return qtrue ;
}
void NPC_LoadParms ( void )
{
int len , totallen , npcExtFNLen , fileCnt , i ;
char * buffer , * holdChar , * marker ;
char npcExtensionListBuf [ 2048 ] ; // The list of file names read in
//gi.Printf( "Parsing ext_data/npcs/*.npc definitions\n" );
//set where to store the first one
totallen = 0 ;
marker = NPCParms ;
marker [ 0 ] = ' \0 ' ;
//now load in the .npc definitions
fileCnt = gi . FS_GetFileList ( " ext_data/npcs " , " .npc " , npcExtensionListBuf , sizeof ( npcExtensionListBuf ) ) ;
holdChar = npcExtensionListBuf ;
for ( i = 0 ; i < fileCnt ; i + + , holdChar + = npcExtFNLen + 1 )
{
npcExtFNLen = strlen ( holdChar ) ;
//gi.Printf( "Parsing %s\n", holdChar );
len = gi . FS_ReadFile ( va ( " ext_data/npcs/%s " , holdChar ) , ( void * * ) & buffer ) ;
if ( len = = - 1 )
{
gi . Printf ( " NPC_LoadParms: error reading file %s \n " , holdChar ) ;
}
else
{
if ( totallen & & * ( marker - 1 ) = = ' } ' )
{ //don't let previous file end on a } because that must be a stand-alone token
strcat ( marker , " " ) ;
totallen + + ;
marker + + ;
}
len = COM_Compress ( buffer ) ;
if ( totallen + len > = MAX_NPC_DATA_SIZE ) {
G_Error ( " NPC_LoadParms: ran out of space before reading %s \n (you must make the .npc files smaller) " , holdChar ) ;
}
strcat ( marker , buffer ) ;
gi . FS_FreeFile ( buffer ) ;
totallen + = len ;
marker + = len ;
}
}
}