function autoexec main() { /# level.__ai_debugInterface = GetDvarInt( "ai_debugInterface" ); #/ } function private _CheckValue( archetype, attributeName, value ) { /# attribute = level.__ai_interface[ archetype ][ attributeName ]; switch ( attribute[ "type" ] ) { case "_interface_match": possibleValues = attribute[ "values" ]; assert( !IsArray( possibleValues ) || IsInArray( possibleValues, value ), "AI: \"" + value + "\" is not one of the allowed values for attribute \"" + attributeName + "\"." ); break; case "_interface_numeric": maxValue = attribute[ "max_value" ]; minValue = attribute[ "min_value" ]; assert( IsInt( value ) || IsFloat( value ), "AI: Attribute \"" + attributeName + "\" requires a numeric value and \"" + value + "\" does not qualify." ); assert( ( !IsDefined( maxValue ) && !IsDefined( minValue ) ) || ( value <= maxValue && value >= minValue ), "AI: \"" + value + "\" is outside the allowed range of (" + minValue + "," + maxValue + ")." ); break; case "_interface_vector": if ( IsDefined( value ) ) assert( IsVec( value ), "AI: Attribute \"" + attributeName + "\" requires a vector value and \"" + value + "\" does not qualify." ); break; default: assert( "AI: Unknown attribute type of \"" + attribute[ "type" ] + "\" for attribute \"" + attributeName + "\"." ); break; } #/ } function private _CheckPrerequisites( entity, attribute ) { /# assert( IsEntity( entity ), "AI: Must pass an entity to access an attribute." ); assert( IsActor( entity ) || IsVehicle( entity ), "AI: Must pass an actor or vehicle to access an attribute." ); assert( IsString( attribute ), "AI: Must pass in a valid attribute name." ); // In depth debugging, only necessary to debug if an AI or the AI Interface system has been setup properly. if ( IsDefined( level.__ai_debugInterface ) && level.__ai_debugInterface > 0 ) { assert( IsArray( entity.__interface ), "AI: Entity(" + entity.archetype + ") must create an interface before accessing an " + "attribute, see \"ai::CreateInterfaceForEntity\"." ); assert( IsArray( level.__ai_interface ), "AI: No attributes have been registered with the AI interface system yet." ); assert( IsArray( level.__ai_interface[ entity.archetype ] ), "AI: No attributes for archetype \"" + entity.archetype + "\" have been registered." ); assert( IsArray( level.__ai_interface[ entity.archetype ][ attribute ] ), "AI: Attribute \"" + attribute + "\" has not been registered for archetype \"" + entity.archetype + "\" yet." ); assert( IsString( level.__ai_interface[ entity.archetype ][ attribute ][ "type" ] ), "AI: Attribute type is undefined for \"" + attribute + "\"." ); } #/ } function private _CheckRegistrationPrerequisites( archetype, attribute, callbackFunction ) { /# assert( IsString( archetype ), "AI: \"archetype\" value is mandatory for registration." ); assert( IsString( attribute ), "AI: \"attribute\" value is mandatory for registration." ); assert( !IsDefined( callbackFunction ) || IsFunctionPtr( callbackFunction ), "AI: \"callbackFunction\" is optional but must be a function pointer if specified." ); #/ } function private _InitializeLevelInterface( archetype ) { if ( !IsDefined( level.__ai_interface ) ) { level.__ai_interface = []; } if ( !IsDefined( level.__ai_interface[ archetype ] ) ) { level.__ai_interface[ archetype ] = []; } } #namespace ai; function CreateInterfaceForEntity( entity ) { if ( !IsDefined( entity.__interface ) ) { entity.__interface = []; } } function GetAiAttribute( entity, attribute ) { /# ai_interface::_CheckPrerequisites( entity, attribute ); #/ if ( !IsDefined( entity.__interface[ attribute ] ) ) { return level.__ai_interface[ entity.archetype ][ attribute ][ "default_value" ]; } return entity.__interface[ attribute ]; } function HasAiAttribute( entity, attribute ) { return IsDefined( entity ) && IsDefined( attribute ) && IsDefined( entity.archetype ) && IsDefined( level.__ai_interface ) && IsDefined( level.__ai_interface[ entity.archetype ] ) && IsDefined( level.__ai_interface[ entity.archetype ][ attribute ] ); } function RegisterMatchedInterface( archetype, attribute, defaultValue, possibleValues, callbackFunction ) { /# ai_interface::_CheckRegistrationPrerequisites( archetype, attribute, callbackFunction ); assert( !IsDefined( possibleValues ) || IsArray( possibleValues ), "AI: \"possibleValues\" is optional but must be an array if specified." ); #/ ai_interface::_InitializeLevelInterface( archetype ); /# assert( !IsDefined( level.__ai_interface[ archetype ][ attribute ] ), "AI: \"" + attribute + "\" is already registered for archetype \"" + archetype + "\"" ); #/ level.__ai_interface[ archetype ][ attribute ] = []; level.__ai_interface[ archetype ][ attribute ][ "callback" ] = callbackFunction; level.__ai_interface[ archetype ][ attribute ][ "default_value" ] = defaultValue; level.__ai_interface[ archetype ][ attribute ][ "type" ] = "_interface_match"; level.__ai_interface[ archetype ][ attribute ][ "values" ] = possibleValues; /# ai_interface::_CheckValue( archetype, attribute, defaultValue ); #/ } function RegisterNumericInterface( archetype, attribute, defaultValue, minimum, maximum, callbackFunction ) { /# ai_interface::_CheckRegistrationPrerequisites( archetype, attribute, callbackFunction ); assert( !IsDefined( minimum ) || IsInt( minimum ) || IsFloat( minimum ), "AI: \"minimum\" is optional but must be a numeric if specified." ); assert( !IsDefined( maximum ) || IsInt( maximum ) || IsFloat( maximum ), "AI: \"maximum\" is optional but must be a numeric if specified." ); assert( ( !IsDefined( minimum ) && !IsDefined( maximum ) ) || ( IsDefined( minimum ) && IsDefined( maximum ) ), "AI: Either both a minimum and maximum must be defined or both undefined, not mixed."); assert( ( !IsDefined( minimum ) && !IsDefined( maximum ) ) || ( minimum <= maximum ), "AI: Attribute \"" + attribute + "\" cannot specify a minimum greater than " + "the attribute's maximum"); #/ ai_interface::_InitializeLevelInterface( archetype ); /# assert( !IsDefined( level.__ai_interface[ archetype ][ attribute ] ), "AI: \"" + attribute + "\" is already registered for archetype \"" + archetype + "\"" ); #/ level.__ai_interface[ archetype ][ attribute ] = []; level.__ai_interface[ archetype ][ attribute ][ "callback" ] = callbackFunction; level.__ai_interface[ archetype ][ attribute ][ "default_value" ] = defaultValue; level.__ai_interface[ archetype ][ attribute ][ "max_value" ] = maximum; level.__ai_interface[ archetype ][ attribute ][ "min_value" ] = minimum; level.__ai_interface[ archetype ][ attribute ][ "type" ] = "_interface_numeric"; /# ai_interface::_CheckValue( archetype, attribute, defaultValue ); #/ } function RegisterVectorInterface( archetype, attribute, defaultValue, callbackFunction ) { /# ai_interface::_CheckRegistrationPrerequisites( archetype, attribute, callbackFunction ); #/ ai_interface::_InitializeLevelInterface( archetype ); /# assert( !IsDefined( level.__ai_interface[ archetype ][ attribute ] ), "AI: \"" + attribute + "\" is already registered for archetype \"" + archetype + "\"" ); #/ level.__ai_interface[ archetype ][ attribute ] = []; level.__ai_interface[ archetype ][ attribute ][ "callback" ] = callbackFunction; level.__ai_interface[ archetype ][ attribute ][ "default_value" ] = defaultValue; level.__ai_interface[ archetype ][ attribute ][ "type" ] = "_interface_vector"; /# ai_interface::_CheckValue( archetype, attribute, defaultValue ); #/ } function SetAiAttribute( entity, attribute, value ) { /# ai_interface::_CheckPrerequisites( entity, attribute ); ai_interface::_CheckValue( entity.archetype, attribute, value ); #/ oldValue = entity.__interface[ attribute ]; if ( !IsDefined( oldValue ) ) { oldValue = level.__ai_interface[ entity.archetype ][ attribute ][ "default_value" ]; } entity.__interface[ attribute ] = value; callback = level.__ai_interface[ entity.archetype ][ attribute ][ "callback" ]; if ( IsFunctionPtr( callback ) ) { [[callback]]( entity, attribute, oldValue, value ); } }