mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 16:21:04 +02:00
915 lines
17 KiB
C++
915 lines
17 KiB
C++
// Bot_wieghts.cpp
|
|
//
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "../Game_local.h"
|
|
|
|
idBotFuzzyWeightManager botFuzzyWeightManager;
|
|
|
|
/*
|
|
========================
|
|
idBotFuzzyWeightManager::Init
|
|
========================
|
|
*/
|
|
void idBotFuzzyWeightManager::Init( void )
|
|
{
|
|
memset( &fuzzyseperators[0], 0, sizeof( fuzzyseperators ) );
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idBotFuzzyWeightManager::AllocFuzzyWeight
|
|
========================
|
|
*/
|
|
fuzzyseperator_t* idBotFuzzyWeightManager::AllocFuzzyWeight( void )
|
|
{
|
|
for( int i = 0; i < MAX_FUZZY_OPERATORS; i++ )
|
|
{
|
|
if( fuzzyseperators[i].inUse == false )
|
|
{
|
|
memset( &fuzzyseperators[i], 0, sizeof( fuzzyseperator_t ) );
|
|
fuzzyseperators[i].inUse = true;
|
|
return &fuzzyseperators[i];
|
|
}
|
|
}
|
|
|
|
gameLocal.Error( "AllocFuzzyWeight: Not enough fuzzy weights\n" );
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idBotFuzzyWeightManager::ReadValue
|
|
========================
|
|
*/
|
|
bool idBotFuzzyWeightManager::ReadValue( idParser& source, float* value )
|
|
{
|
|
idToken token;
|
|
|
|
if( value == NULL || !source.ReadToken( &token ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool negative = false;
|
|
if( token == "-" )
|
|
{
|
|
negative = true;
|
|
if( !source.ExpectTokenType( TT_NUMBER, 0, &token ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if( token.type != TT_NUMBER )
|
|
{
|
|
source.Error( "invalid return value %s\n", token.c_str() );
|
|
return false;
|
|
}
|
|
|
|
*value = negative ? -token.GetFloatValue() : token.GetFloatValue();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idBotFuzzyWeightManager::ReadFuzzyWeight
|
|
===================
|
|
*/
|
|
int idBotFuzzyWeightManager::ReadFuzzyWeight( idParser& source, fuzzyseperator_t* fs )
|
|
{
|
|
if( source.CheckTokenString( "balance" ) )
|
|
{
|
|
fs->type = WT_BALANCE;
|
|
|
|
if( !source.ExpectTokenString( "(" ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !ReadValue( source, &fs->weight ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !source.ExpectTokenString( "," ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !ReadValue( source, &fs->minweight ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !source.ExpectTokenString( "," ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !ReadValue( source, &fs->maxweight ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( !source.ExpectTokenString( ")" ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fs->type = 0;
|
|
|
|
if( !ReadValue( source, &fs->weight ) )
|
|
{
|
|
return false;
|
|
}
|
|
fs->minweight = fs->weight;
|
|
fs->maxweight = fs->weight;
|
|
}
|
|
|
|
if( !source.ExpectTokenString( ";" ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idBotFuzzyWeightManager::FreeFuzzySeperators_r
|
|
===================
|
|
*/
|
|
void idBotFuzzyWeightManager::FreeFuzzySeperators_r( fuzzyseperator_t* fs )
|
|
{
|
|
if( !fs )
|
|
{
|
|
return;
|
|
}
|
|
if( fs->child )
|
|
{
|
|
FreeFuzzySeperators_r( fs->child );
|
|
}
|
|
if( fs->next )
|
|
{
|
|
FreeFuzzySeperators_r( fs->next );
|
|
}
|
|
|
|
fs->inUse = false;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
FreeWeightConfig2
|
|
===================
|
|
*/
|
|
void idBotFuzzyWeightManager::FreeWeightConfig2( weightconfig_t* config )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < config->numweights; i++ )
|
|
{
|
|
FreeFuzzySeperators_r( config->weights[i].firstseperator );
|
|
// jmarshall - todo
|
|
//if (config->weights[i].name)
|
|
// FreeMemory(config->weights[i].name);
|
|
// jmarshall end
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idBotFuzzyWeightManager::FreeWeightConfig
|
|
===================
|
|
*/
|
|
void idBotFuzzyWeightManager::FreeWeightConfig( weightconfig_t* config )
|
|
{
|
|
//if (!LibVarGetValue("bot_reloadcharacters"))
|
|
// return;
|
|
|
|
FreeWeightConfig2( config );
|
|
}
|
|
|
|
/*
|
|
===================
|
|
idBotFuzzyWeightManager::ReadFuzzySeperators_r
|
|
===================
|
|
*/
|
|
fuzzyseperator_t* idBotFuzzyWeightManager::ReadFuzzySeperators_r( idParser& source )
|
|
{
|
|
int newindent, index, founddefault;
|
|
bool def;
|
|
idToken token;
|
|
fuzzyseperator_t* fs, * lastfs, * firstfs;
|
|
|
|
founddefault = false;
|
|
firstfs = NULL;
|
|
lastfs = NULL;
|
|
if( !source.ExpectTokenString( "(" ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if( !source.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
index = token.GetIntValue();
|
|
|
|
if( !source.ExpectTokenString( ")" ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if( !source.ExpectTokenString( "{" ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if( !source.ExpectAnyToken( &token ) )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
do
|
|
{
|
|
def = ( token == "default" ); //!strcmp(token.string, "default");
|
|
if( def || ( token == "case" ) )
|
|
{
|
|
fs = AllocFuzzyWeight();
|
|
fs->index = index;
|
|
if( lastfs )
|
|
{
|
|
lastfs->next = fs;
|
|
}
|
|
else
|
|
{
|
|
firstfs = fs;
|
|
}
|
|
lastfs = fs;
|
|
if( def )
|
|
{
|
|
if( founddefault )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
gameLocal.Error( "switch already has a default\n" );
|
|
return NULL;
|
|
}
|
|
fs->value = MAX_INVENTORYVALUE;
|
|
founddefault = true;
|
|
}
|
|
else
|
|
{
|
|
if( !source.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
|
|
fs->value = token.GetIntValue();
|
|
}
|
|
|
|
if( !source.ExpectTokenString( ":" ) || !source.ExpectAnyToken( &token ) )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
|
|
newindent = false;
|
|
if( token == "{" )
|
|
{
|
|
newindent = true;
|
|
if( !source.ExpectAnyToken( &token ) )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if( token == "return" )
|
|
{
|
|
if( !ReadFuzzyWeight( source, fs ) )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
}
|
|
else if( token == "switch" )
|
|
{
|
|
fs->child = ReadFuzzySeperators_r( source );
|
|
if( !fs->child )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gameLocal.Error( "invalid name %s\n", token.c_str() );
|
|
return NULL;
|
|
}
|
|
|
|
if( newindent )
|
|
{
|
|
if( !source.ExpectTokenString( "}" ) )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gameLocal.Error( "invalid name %s\n", token.c_str() );
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
|
|
if( !source.ExpectAnyToken( &token ) )
|
|
{
|
|
FreeFuzzySeperators_r( firstfs );
|
|
return NULL;
|
|
}
|
|
}
|
|
while( token != "}" );
|
|
|
|
if( !founddefault )
|
|
{
|
|
source.Warning( "switch without default\n" );
|
|
fs = AllocFuzzyWeight();
|
|
fs->index = index;
|
|
fs->value = MAX_INVENTORYVALUE;
|
|
fs->weight = 0;
|
|
fs->next = NULL;
|
|
fs->child = NULL;
|
|
if( lastfs )
|
|
{
|
|
lastfs->next = fs;
|
|
}
|
|
else
|
|
{
|
|
firstfs = fs;
|
|
}
|
|
lastfs = fs;
|
|
}
|
|
|
|
return firstfs;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idBotFuzzyWeightManager::ReadWeightConfig
|
|
=====================
|
|
*/
|
|
weightconfig_t* idBotFuzzyWeightManager::ReadWeightConfig( char* filename )
|
|
{
|
|
int newindent, avail = 0, n;
|
|
idToken token;
|
|
idParser source;
|
|
fuzzyseperator_t* fs;
|
|
weightconfig_t* config = NULL;
|
|
|
|
avail = -1;
|
|
for( n = 0; n < MAX_WEIGHT_FILES; n++ )
|
|
{
|
|
config = &weightFileList[n];
|
|
|
|
if( config->inUse )
|
|
{
|
|
if( config->filename == filename )
|
|
{
|
|
return config;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if( avail == -1 )
|
|
{
|
|
avail = n;
|
|
}
|
|
}
|
|
|
|
if( avail == -1 )
|
|
{
|
|
gameLocal.Error( "weightFileList was full trying to load %s\n", filename );
|
|
return NULL;
|
|
}
|
|
|
|
rvmScopedLexerBaseFolder scopedBaseFolder( BOTFILESBASEFOLDER );
|
|
|
|
if( !source.LoadFile( filename ) )
|
|
{
|
|
gameLocal.Error( "couldn't load %s\n", filename );
|
|
return NULL;
|
|
}
|
|
|
|
config = &weightFileList[avail];
|
|
config->Reset();
|
|
|
|
config->filename = filename;
|
|
|
|
//parse the item config file
|
|
while( source.ReadToken( &token ) )
|
|
{
|
|
if( token == "weight" )
|
|
{
|
|
if( config->numweights >= MAX_WEIGHTS )
|
|
{
|
|
gameLocal.Error( "too many fuzzy weights\n" );
|
|
break;
|
|
}
|
|
|
|
if( !source.ExpectTokenType( TT_STRING, 0, &token ) )
|
|
{
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
|
|
token.StripDoubleQuotes();
|
|
config->weights[config->numweights].name = token.c_str();
|
|
|
|
if( !source.ExpectAnyToken( &token ) )
|
|
{
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
|
|
newindent = false;
|
|
if( token == "{" )
|
|
{
|
|
newindent = true;
|
|
if( !source.ExpectAnyToken( &token ) )
|
|
{
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if( token == "switch" )
|
|
{
|
|
fs = ReadFuzzySeperators_r( source );
|
|
if( !fs )
|
|
{
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
|
|
config->weights[config->numweights].firstseperator = fs;
|
|
}
|
|
else if( token == "return" )
|
|
{
|
|
fs = ( fuzzyseperator_t* )AllocFuzzyWeight();
|
|
fs->index = 0;
|
|
fs->value = MAX_INVENTORYVALUE;
|
|
fs->next = NULL;
|
|
fs->child = NULL;
|
|
if( !ReadFuzzyWeight( source, fs ) )
|
|
{
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
config->weights[config->numweights].firstseperator = fs;
|
|
}
|
|
else
|
|
{
|
|
gameLocal.Error( "invalid name %s\n", token.c_str() );
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
|
|
if( newindent )
|
|
{
|
|
if( !source.ExpectTokenString( "}" ) )
|
|
{
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
}
|
|
config->numweights++;
|
|
}
|
|
else
|
|
{
|
|
gameLocal.Error( "invalid name %s\n", token.c_str() );
|
|
FreeWeightConfig( config );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//if the file was located in a pak file
|
|
common->Printf( "idBotFuzzyWeightManager::ReadWeightConfig: loaded %s\n", filename );
|
|
config->inUse = true;
|
|
return config;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idBotFuzzyWeightManager::FindFuzzyWeight
|
|
==================
|
|
*/
|
|
int idBotFuzzyWeightManager::FindFuzzyWeight( weightconfig_t* wc, char* name )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < wc->numweights; i++ )
|
|
{
|
|
if( wc->weights[i].name == name )
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
==================
|
|
idBotFuzzyWeightManager::FuzzyWeight_r
|
|
==================
|
|
*/
|
|
float idBotFuzzyWeightManager::FuzzyWeight_r( int* inventory, fuzzyseperator_t* fs )
|
|
{
|
|
float scale, w1, w2;
|
|
|
|
if( inventory[fs->index] < fs->value )
|
|
{
|
|
if( fs->child )
|
|
{
|
|
return FuzzyWeight_r( inventory, fs->child );
|
|
}
|
|
else
|
|
{
|
|
return fs->weight;
|
|
}
|
|
}
|
|
else if( fs->next )
|
|
{
|
|
if( inventory[fs->index] < fs->next->value )
|
|
{
|
|
//first weight
|
|
if( fs->child )
|
|
{
|
|
w1 = FuzzyWeight_r( inventory, fs->child );
|
|
}
|
|
else
|
|
{
|
|
w1 = fs->weight;
|
|
}
|
|
|
|
//second weight
|
|
if( fs->next->child )
|
|
{
|
|
w2 = FuzzyWeight_r( inventory, fs->next->child );
|
|
}
|
|
else
|
|
{
|
|
w2 = fs->next->weight;
|
|
}
|
|
|
|
//the scale factor
|
|
scale = ( float )( inventory[fs->index] - fs->value ) / ( float )( fs->next->value - fs->value );
|
|
|
|
//scale between the two weights
|
|
return ( 1 - scale ) * w1 + scale * w2;
|
|
}
|
|
return FuzzyWeight_r( inventory, fs->next );
|
|
}
|
|
return fs->weight;
|
|
}
|
|
|
|
/*
|
|
============================
|
|
idBotFuzzyWeightManager::FuzzyWeightUndecided_r
|
|
============================
|
|
*/
|
|
float idBotFuzzyWeightManager::FuzzyWeightUndecided_r( int* inventory, fuzzyseperator_t* fs )
|
|
{
|
|
float scale, w1, w2;
|
|
|
|
if( inventory[fs->index] < fs->value )
|
|
{
|
|
if( fs->child )
|
|
{
|
|
return FuzzyWeightUndecided_r( inventory, fs->child );
|
|
}
|
|
else
|
|
{
|
|
return fs->minweight + rvmBotUtil::random() * ( fs->maxweight - fs->minweight );
|
|
}
|
|
}
|
|
else if( fs->next )
|
|
{
|
|
if( inventory[fs->index] < fs->next->value )
|
|
{
|
|
//first weight
|
|
if( fs->child )
|
|
{
|
|
w1 = FuzzyWeightUndecided_r( inventory, fs->child );
|
|
}
|
|
else
|
|
{
|
|
w1 = fs->minweight + rvmBotUtil::random() * ( fs->maxweight - fs->minweight );
|
|
}
|
|
|
|
//second weight
|
|
if( fs->next->child )
|
|
{
|
|
w2 = FuzzyWeight_r( inventory, fs->next->child );
|
|
}
|
|
else
|
|
{
|
|
w2 = fs->next->minweight + rvmBotUtil::random() * ( fs->next->maxweight - fs->next->minweight );
|
|
}
|
|
|
|
//the scale factor
|
|
scale = ( float )( inventory[fs->index] - fs->value ) / ( float )( fs->next->value - fs->value );
|
|
|
|
//scale between the two weights
|
|
return ( 1 - scale ) * w1 + scale * w2;
|
|
}
|
|
return FuzzyWeightUndecided_r( inventory, fs->next );
|
|
}
|
|
return fs->weight;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idBotFuzzyWeightManager::FuzzyWeight
|
|
=================
|
|
*/
|
|
float idBotFuzzyWeightManager::FuzzyWeight( int* inventory, weightconfig_t* wc, int weightnum )
|
|
{
|
|
return FuzzyWeight_r( inventory, wc->weights[weightnum].firstseperator );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
idBotFuzzyWeightManager::FuzzyWeightUndecided
|
|
=================
|
|
*/
|
|
float idBotFuzzyWeightManager::FuzzyWeightUndecided( int* inventory, weightconfig_t* wc, int weightnum )
|
|
{
|
|
return FuzzyWeightUndecided_r( inventory, wc->weights[weightnum].firstseperator );
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::EvolveFuzzySeperator_r
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::EvolveFuzzySeperator_r( fuzzyseperator_t* fs )
|
|
{
|
|
if( fs->child )
|
|
{
|
|
EvolveFuzzySeperator_r( fs->child );
|
|
}
|
|
else if( fs->type == WT_BALANCE )
|
|
{
|
|
//every once in a while an evolution leap occurs, mutation
|
|
if( rvmBotUtil::random() < 0.01 )
|
|
{
|
|
fs->weight += rvmBotUtil::crandom() * ( fs->maxweight - fs->minweight );
|
|
}
|
|
else
|
|
{
|
|
fs->weight += rvmBotUtil::crandom() * ( fs->maxweight - fs->minweight ) * 0.5;
|
|
}
|
|
|
|
//modify bounds if necesary because of mutation
|
|
if( fs->weight < fs->minweight )
|
|
{
|
|
fs->minweight = fs->weight;
|
|
}
|
|
else if( fs->weight > fs->maxweight )
|
|
{
|
|
fs->maxweight = fs->weight;
|
|
}
|
|
}
|
|
if( fs->next )
|
|
{
|
|
EvolveFuzzySeperator_r( fs->next );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::EvolveWeightConfig
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::EvolveWeightConfig( weightconfig_t* config )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < config->numweights; i++ )
|
|
{
|
|
EvolveFuzzySeperator_r( config->weights[i].firstseperator );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::ScaleWeight
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::ScaleFuzzySeperator_r( fuzzyseperator_t* fs, float scale )
|
|
{
|
|
if( fs->child )
|
|
{
|
|
ScaleFuzzySeperator_r( fs->child, scale );
|
|
}
|
|
else if( fs->type == WT_BALANCE )
|
|
{
|
|
fs->weight = fs->minweight + ( fs->maxweight - fs->minweight ) * scale;
|
|
|
|
//get the weight between bounds
|
|
if( fs->weight < fs->minweight )
|
|
{
|
|
fs->weight = fs->minweight;
|
|
}
|
|
else if( fs->weight > fs->maxweight )
|
|
{
|
|
fs->weight = fs->maxweight;
|
|
}
|
|
}
|
|
if( fs->next )
|
|
{
|
|
ScaleFuzzySeperator_r( fs->next, scale );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::ScaleWeight
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::ScaleWeight( weightconfig_t* config, char* name, float scale )
|
|
{
|
|
int i;
|
|
|
|
if( scale < 0 )
|
|
{
|
|
scale = 0;
|
|
}
|
|
else if( scale > 1 )
|
|
{
|
|
scale = 1;
|
|
}
|
|
for( i = 0; i < config->numweights; i++ )
|
|
{
|
|
if( config->weights[i].name == name )
|
|
{
|
|
ScaleFuzzySeperator_r( config->weights[i].firstseperator, scale );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::ScaleFuzzySeperatorBalanceRange_r
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::ScaleFuzzySeperatorBalanceRange_r( fuzzyseperator_t* fs, float scale )
|
|
{
|
|
if( fs->child )
|
|
{
|
|
ScaleFuzzySeperatorBalanceRange_r( fs->child, scale );
|
|
}
|
|
else if( fs->type == WT_BALANCE )
|
|
{
|
|
float mid = ( fs->minweight + fs->maxweight ) * 0.5;
|
|
//get the weight between bounds
|
|
fs->maxweight = mid + ( fs->maxweight - mid ) * scale;
|
|
fs->minweight = mid + ( fs->minweight - mid ) * scale;
|
|
if( fs->maxweight < fs->minweight )
|
|
{
|
|
fs->maxweight = fs->minweight;
|
|
}
|
|
}
|
|
if( fs->next )
|
|
{
|
|
ScaleFuzzySeperatorBalanceRange_r( fs->next, scale );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::ScaleFuzzyBalanceRange
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::ScaleFuzzyBalanceRange( weightconfig_t* config, float scale )
|
|
{
|
|
int i;
|
|
|
|
if( scale < 0 )
|
|
{
|
|
scale = 0;
|
|
}
|
|
else if( scale > 100 )
|
|
{
|
|
scale = 100;
|
|
}
|
|
for( i = 0; i < config->numweights; i++ )
|
|
{
|
|
ScaleFuzzySeperatorBalanceRange_r( config->weights[i].firstseperator, scale );
|
|
}
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::InterbreedFuzzySeperator_r
|
|
====================
|
|
*/
|
|
int idBotFuzzyWeightManager::InterbreedFuzzySeperator_r( fuzzyseperator_t* fs1, fuzzyseperator_t* fs2, fuzzyseperator_t* fsout )
|
|
{
|
|
if( fs1->child )
|
|
{
|
|
if( !fs2->child || !fsout->child )
|
|
{
|
|
gameLocal.Error( "cannot interbreed weight configs, unequal child\n" );
|
|
return false;
|
|
}
|
|
if( !InterbreedFuzzySeperator_r( fs1->child, fs2->child, fsout->child ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if( fs1->type == WT_BALANCE )
|
|
{
|
|
if( fs2->type != WT_BALANCE || fsout->type != WT_BALANCE )
|
|
{
|
|
gameLocal.Error( "cannot interbreed weight configs, unequal balance\n" );
|
|
return false;
|
|
}
|
|
fsout->weight = ( fs1->weight + fs2->weight ) / 2;
|
|
if( fsout->weight > fsout->maxweight )
|
|
{
|
|
fsout->maxweight = fsout->weight;
|
|
}
|
|
if( fsout->weight < fsout->minweight )
|
|
{
|
|
fsout->minweight = fsout->weight;
|
|
}
|
|
}
|
|
if( fs1->next )
|
|
{
|
|
if( !fs2->next || !fsout->next )
|
|
{
|
|
gameLocal.Error( "cannot interbreed weight configs, unequal next\n" );
|
|
return false;
|
|
}
|
|
if( !InterbreedFuzzySeperator_r( fs1->next, fs2->next, fsout->next ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idBotFuzzyWeightManager::InterbreedWeightConfigs
|
|
====================
|
|
*/
|
|
void idBotFuzzyWeightManager::InterbreedWeightConfigs( weightconfig_t* config1, weightconfig_t* config2, weightconfig_t* configout )
|
|
{
|
|
int i;
|
|
|
|
if( config1->numweights != config2->numweights ||
|
|
config1->numweights != configout->numweights )
|
|
{
|
|
gameLocal.Error( "cannot interbreed weight configs, unequal numweights\n" );
|
|
return;
|
|
}
|
|
|
|
for( i = 0; i < config1->numweights; i++ )
|
|
{
|
|
InterbreedFuzzySeperator_r( config1->weights[i].firstseperator,
|
|
config2->weights[i].firstseperator,
|
|
configout->weights[i].firstseperator );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=======================
|
|
idBotFuzzyWeightManager::BotShutdownWeights
|
|
=======================
|
|
*/
|
|
void idBotFuzzyWeightManager::BotShutdownWeights( void )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < MAX_WEIGHT_FILES; i++ )
|
|
{
|
|
if( weightFileList[i].inUse )
|
|
{
|
|
FreeWeightConfig2( &weightFileList[i] );
|
|
}
|
|
weightFileList[i].Reset();
|
|
}
|
|
} |