mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 16:21:04 +02:00
365 lines
7.6 KiB
C++
365 lines
7.6 KiB
C++
// Bot_char.cpp
|
|
//
|
|
|
|
#include "precompiled.h"
|
|
#include "../Game_local.h"
|
|
|
|
idBotCharacterStatsManager botCharacterStatsManager;
|
|
|
|
/*
|
|
====================
|
|
idBotCharacterStatsManager::idBotCharacterStatsManager
|
|
====================
|
|
*/
|
|
idBotCharacterStatsManager::idBotCharacterStatsManager()
|
|
{
|
|
default_char_profile = nullptr;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotCharacterStatsManager::Init
|
|
====================
|
|
*/
|
|
void idBotCharacterStatsManager::Init( void )
|
|
{
|
|
default_char_profile = BotLoadCharacterFromFile( "bots/default_c.c", 1 );
|
|
if( default_char_profile == NULL )
|
|
{
|
|
common->FatalError( "Failed to load default characteristic def file\n" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
============================
|
|
idBotCharacterStatsManager::AllocBotCharacter
|
|
============================
|
|
*/
|
|
bot_character_t* idBotCharacterStatsManager::AllocBotCharacter( void )
|
|
{
|
|
bot_character_t* ch = NULL;
|
|
|
|
for( int i = 0; i < MAX_CHAR_STATS; i++ )
|
|
{
|
|
if( charStatsList[i].inUse == false )
|
|
{
|
|
charStatsList[i].inUse = true;
|
|
ch = &charStatsList[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( ch == nullptr )
|
|
{
|
|
gameLocal.Error( "idBotCharacterStatsManager::AllocBotCharacter: Too many bot characters!" );
|
|
return nullptr;
|
|
}
|
|
|
|
if( default_char_profile == NULL )
|
|
{
|
|
memset( &ch->c[0], 0, MAX_CHARACTERISTICS * sizeof( bot_characteristic_t ) );
|
|
ch->filename = "";
|
|
ch->skill = 0;
|
|
}
|
|
else
|
|
{
|
|
//memcpy( ch, default_char_profile, sizeof( bot_character_t ) + MAX_CHARACTERISTICS * sizeof( bot_characteristic_t ) );
|
|
*ch = *default_char_profile;
|
|
}
|
|
|
|
|
|
|
|
ch->inUse = true;
|
|
|
|
return ch;
|
|
}
|
|
|
|
/*
|
|
============================
|
|
idBotCharacterStatsManager::FreeCharacterFile
|
|
============================
|
|
*/
|
|
void idBotCharacterStatsManager::FreeCharacterFile( bot_character_t* ch )
|
|
{
|
|
ch->inUse = false;
|
|
}
|
|
|
|
/*
|
|
============================
|
|
idBotCharacterStatsManager::BotLoadCharacterFromFile
|
|
============================
|
|
*/
|
|
bot_character_t* idBotCharacterStatsManager::BotLoadCharacterFromFile( const char* charfile, int skill )
|
|
{
|
|
int indent, index;
|
|
bool foundcharacter;
|
|
bot_character_t* ch;
|
|
idParser parser;
|
|
idToken token;
|
|
|
|
foundcharacter = false;
|
|
|
|
// Check to see if we already loaded this bot file.
|
|
for( int i = 0; i < MAX_CHAR_STATS; i++ )
|
|
{
|
|
if(charStatsList[i].inUse && charStatsList[i].filename == charfile )
|
|
{
|
|
return &charStatsList[i];
|
|
}
|
|
}
|
|
|
|
rvmScopedLexerBaseFolder scopedBaseFolder( BOTFILESBASEFOLDER );
|
|
|
|
//a bot character is parsed in two phases
|
|
if( !parser.LoadFile( charfile ) )
|
|
{
|
|
common->Warning( "BotLoadCharacterFromFile: counldn't load %s\n", charfile );
|
|
return NULL;
|
|
}
|
|
|
|
ch = AllocBotCharacter();
|
|
ch->filename = charfile;
|
|
|
|
while( parser.ReadToken( &token ) )
|
|
{
|
|
if( token == "skill" )
|
|
{
|
|
if( !parser.ExpectTokenType( TT_NUMBER, 0, &token ) )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
parser.Warning( "Expected token type number\n" );
|
|
return NULL;
|
|
}
|
|
|
|
if( !parser.ExpectTokenString( "{" ) )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
parser.Warning( "Expected token {\n" );
|
|
return NULL;
|
|
}
|
|
|
|
//if it's the correct skill
|
|
if( skill < 0 || token.GetIntValue() == skill )
|
|
{
|
|
foundcharacter = true;
|
|
ch->skill = token.GetIntValue();
|
|
while( parser.ReadToken( &token ) )
|
|
{
|
|
if( token == "}" )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if( token.type != TT_NUMBER || !( token.subtype & TT_INTEGER ) )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
parser.Error( "expected integer index, found %s\n", token.c_str() );
|
|
return NULL;
|
|
}
|
|
|
|
index = token.GetIntValue();
|
|
if( index < 0 || index >= MAX_CHARACTERISTICS )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
parser.Error( "characteristic index out of range [0, %d]\n", MAX_CHARACTERISTICS );
|
|
return NULL;
|
|
}
|
|
// jmarshall - not sure what we loose by removing this check, basically duplicate definition check?
|
|
//if (ch->c[index].type)
|
|
//{
|
|
// G_Error("characteristic %d already initialized\n", index);
|
|
// trap_PC_FreeSource(source);
|
|
// BotFreeCharacterStrings(ch);
|
|
// //FreeMemory(ch);
|
|
// return NULL;
|
|
//}
|
|
// jmarshall end
|
|
|
|
if( !parser.ReadToken( &token ) )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
parser.Error( "Unexpected EOF during parse characesistic" );
|
|
return NULL;
|
|
}
|
|
|
|
if( token.type == TT_NUMBER )
|
|
{
|
|
if( token.subtype & TT_FLOAT )
|
|
{
|
|
ch->c[index].value._float = token.GetFloatValue();
|
|
ch->c[index].type = CT_FLOAT;
|
|
}
|
|
else
|
|
{
|
|
ch->c[index].value.integer = token.GetIntValue();
|
|
ch->c[index].type = CT_INTEGER;
|
|
}
|
|
}
|
|
else if( token.type == TT_STRING )
|
|
{
|
|
token.StripDoubleQuotes();
|
|
ch->c[index].value.string = token;
|
|
ch->c[index].type = CT_STRING;
|
|
}
|
|
else
|
|
{
|
|
FreeCharacterFile( ch );
|
|
gameLocal.Error( "expected integer, float or string, found %s\n", token.c_str() );
|
|
return NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
indent = 1;
|
|
while( indent )
|
|
{
|
|
if( !parser.ReadToken( &token ) )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
return NULL;
|
|
}
|
|
if( token == "{" )
|
|
{
|
|
indent++;
|
|
}
|
|
else if( token == "}" )
|
|
{
|
|
indent--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FreeCharacterFile( ch );
|
|
gameLocal.Error( "unknown definition %s\n", token.c_str() );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if( !foundcharacter )
|
|
{
|
|
FreeCharacterFile( ch );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
return ch;
|
|
}
|
|
|
|
|
|
/*
|
|
============================
|
|
idBotCharacterStatsManager::CheckCharacteristicIndex
|
|
============================
|
|
*/
|
|
int idBotCharacterStatsManager::CheckCharacteristicIndex( bot_character_t* ch, int index )
|
|
{
|
|
if( ch == NULL )
|
|
{
|
|
gameLocal.Error( "NULL bot character" );
|
|
return false;
|
|
}
|
|
if( index < 0 || index >= MAX_CHARACTERISTICS )
|
|
{
|
|
gameLocal.Error( "characteristic %d does not exist\n", index );
|
|
return false;
|
|
}
|
|
if( !ch->c[index].type )
|
|
{
|
|
gameLocal.Error( "characteristic %d is not initialized\n", index );
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
============================
|
|
idBotCharacterStatsManager::Characteristic_Float
|
|
============================
|
|
*/
|
|
float idBotCharacterStatsManager::Characteristic_Float( bot_character_t* ch, int index )
|
|
{
|
|
if( !ch )
|
|
{
|
|
return 0;
|
|
}
|
|
//check if the index is in range
|
|
if( !CheckCharacteristicIndex( ch, index ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( ch->c[index].type == CT_INTEGER )
|
|
{
|
|
//an integer will be converted to a float
|
|
return ( float )ch->c[index].value.integer;
|
|
}
|
|
else if( ch->c[index].type == CT_FLOAT )
|
|
{
|
|
//floats are just returned
|
|
return ch->c[index].value._float;
|
|
}
|
|
|
|
//cannot convert a string pointer to a float
|
|
gameLocal.Error( "characteristic %d is not a float\n", index );
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
============================
|
|
Characteristic_String
|
|
============================
|
|
*/
|
|
void idBotCharacterStatsManager::Characteristic_String( bot_character_t* ch, int index, char* buf, int size )
|
|
{
|
|
if( buf == NULL || size <= 0 )
|
|
{
|
|
return;
|
|
}
|
|
buf[0] = '\0';
|
|
|
|
//check if the index is in range
|
|
if( !CheckCharacteristicIndex( ch, index ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
//an integer will be converted to a float
|
|
if( ch->c[index].type == CT_STRING )
|
|
{
|
|
idStr::Copynz( buf, ch->c[index].value.string, size );
|
|
return;
|
|
}
|
|
gameLocal.Error( "characteristic %d is not a string\n", index );
|
|
}
|
|
|
|
/*
|
|
============================
|
|
idBotCharacterStatsManager::Characteristic_BFloat
|
|
============================
|
|
*/
|
|
float idBotCharacterStatsManager::Characteristic_BFloat( bot_character_t* ch, int index, float min, float max )
|
|
{
|
|
float value;
|
|
|
|
if( min > max )
|
|
{
|
|
gameLocal.Error( "cannot bound characteristic %d between %f and %f\n", index, min, max );
|
|
return 0;
|
|
}
|
|
|
|
value = Characteristic_Float( ch, index );
|
|
if( value < min )
|
|
{
|
|
return min;
|
|
}
|
|
if( value > max )
|
|
{
|
|
return max;
|
|
}
|
|
return value;
|
|
}
|