-inline const char* string_find_if(const char* string, Predicate predicate)
-{
- for(; *string != 0; ++string)
- {
- if(predicate(*string))
- {
- return string;
- }
- }
- return string;
-}
-
-inline const char* string_findFirstSpaceOrTab(const char* string)
-{
- return string_find_if(string, char_isSpaceOrTab);
-}
-
-inline const char* string_findFirstNonSpaceOrTab(const char* string)
-{
- return string_find_if(string, char_isNotSpaceOrTab);
-}
-
-
-static bool EntityClass_parse(EntityClass& entityClass, Tokeniser& tokeniser)
-{
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, entityClass.m_name));
-
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser, "{"));
- tokeniser.nextLine();
-
- StringOutputStream usage(256);
- StringOutputStream description(256);
- CopiedString* currentDescription = 0;
- StringOutputStream* currentString = 0;
-
- for(;;)
- {
- const char* key;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, key));
-
- const char* last = string_findFirstSpaceOrTab(key);
- CopiedString first(StringRange(key, last));
-
- if(!string_empty(last))
- {
- last = string_findFirstNonSpaceOrTab(last);
- }
-
- if(currentString != 0 && string_equal(key, "\\"))
- {
- tokeniser.nextLine();
- *currentString << " ";
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, *currentString));
- continue;
- }
-
- if(currentDescription != 0)
- {
- *currentDescription = description.c_str();
- description.clear();
- currentDescription = 0;
- }
- currentString = 0;
-
- if(string_equal(key, "}"))
- {
- tokeniser.nextLine();
- break;
- }
- else if(string_equal(key, "model"))
- {
- const char* token;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
- entityClass.fixedsize = true;
- StringOutputStream buffer(256);
- buffer << PathCleaned(token);
- entityClass.m_modelpath = buffer.c_str();
- }
- else if(string_equal(key, "editor_color"))
- {
- const char* value;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
- if(!string_empty(value))
- {
- entityClass.colorSpecified = true;
- bool success = string_parse_vector3(value, entityClass.color);
- ASSERT_MESSAGE(success, "editor_color: parse error");
- }
- }
- else if(string_equal(key, "editor_ragdoll"))
- {
- //bool ragdoll = atoi(tokeniser.getToken()) != 0;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
- }
- else if(string_equal(key, "editor_mins"))
- {
- entityClass.sizeSpecified = true;
- const char* value;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
- if(!string_empty(value) && !string_equal(value, "?"))
- {
- entityClass.fixedsize = true;
- bool success = string_parse_vector3(value, entityClass.mins);
- ASSERT_MESSAGE(success, "editor_mins: parse error");
- }
- }
- else if(string_equal(key, "editor_maxs"))
- {
- entityClass.sizeSpecified = true;
- const char* value;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
- if(!string_empty(value) && !string_equal(value, "?"))
- {
- entityClass.fixedsize = true;
- bool success = string_parse_vector3(value, entityClass.maxs);
- ASSERT_MESSAGE(success, "editor_maxs: parse error");
- }
- }
- else if(string_equal(key, "editor_usage"))
- {
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage));
- currentString = &usage;
- }
- else if(string_equal_n(key, "editor_usage", 12))
- {
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, usage));
- currentString = &usage;
- }
- else if(string_equal(key, "editor_rotatable")
- || string_equal(key, "editor_showangle")
- || string_equal(key, "editor_showangles") // typo? in prey movables.def
- || string_equal(key, "editor_mover")
- || string_equal(key, "editor_model")
- || string_equal(key, "editor_material")
- || string_equal(key, "editor_combatnode")
- || (!string_empty(last) && string_equal(first.c_str(), "editor_gui"))
- || string_equal_n(key, "editor_copy", 11))
- {
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
- }
- else if(!string_empty(last) && (string_equal(first.c_str(), "editor_var") || string_equal(first.c_str(), "editor_string")))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "string";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && string_equal(first.c_str(), "editor_float"))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "string";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && string_equal(first.c_str(), "editor_snd"))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "sound";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && string_equal(first.c_str(), "editor_bool"))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "boolean";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && string_equal(first.c_str(), "editor_int"))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "integer";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && string_equal(first.c_str(), "editor_model"))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "model";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && string_equal(first.c_str(), "editor_color"))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "color";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(!string_empty(last) && (string_equal(first.c_str(), "editor_material") || string_equal(first.c_str(), "editor_mat")))
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, last).second;
- attribute.m_type = "shader";
- currentDescription = &attribute.m_description;
- currentString = &description;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, description));
- }
- else if(string_equal(key, "inherit"))
- {
- entityClass.inheritanceResolved = false;
- ASSERT_MESSAGE(entityClass.m_parent.empty(), "only one 'inherit' supported per entityDef");
- const char* token;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, token));
- entityClass.m_parent.push_back(token);
- }
- // begin quake4-specific keys
- else if(string_equal(key, "editor_targetonsel"))
- {
- //const char* value =
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
- }
- else if(string_equal(key, "editor_menu"))
- {
- //const char* value =
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
- }
- else if(string_equal(key, "editor_ignore"))
- {
- //const char* value =
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
- }
- // end quake4-specific keys
- // begin ignore prey (unknown/unused?) entity keys
- else if(string_equal(key, "editor_light")
- || string_equal(key, "editor_def def_debrisspawner")
- || string_equal(key, "editor_def def_drop")
- || string_equal(key, "editor_def def_guihand")
- || string_equal(key, "editor_def def_mine"))
- {
- //const char* value =
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseToken(tokeniser));
- }
- // end ignore prey entity keys
- else
- {
- CopiedString tmp(key);
- ASSERT_MESSAGE(!string_equal_n(key, "editor_", 7), "unsupported editor key: " << makeQuoted(key));
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, key).second;
- attribute.m_type = "string";
- const char* value;
- PARSE_RETURN_FALSE_IF_FAIL(EntityClassDoom3_parseString(tokeniser, value));
- if(string_equal(value, "}")) // hack for quake4 powerups.def bug
- {
- globalErrorStream() << "entityDef " << makeQuoted(entityClass.m_name.c_str()) << " key " << makeQuoted(tmp.c_str()) << " has no value\n";
- break;
- }
- else
- {
- attribute.m_value = value;
- }
- }
- tokeniser.nextLine();
- }
-
- entityClass.m_comments = usage.c_str();
-
- if(string_equal(entityClass.m_name.c_str(), "light"))
- {
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "light_radius").second;
- attribute.m_type = "vector3";
- attribute.m_value = "300 300 300";
- }
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "light_center").second;
- attribute.m_type = "vector3";
- }
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "noshadows").second;
- attribute.m_type = "boolean";
- attribute.m_value = "0";
- }
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "nospecular").second;
- attribute.m_type = "boolean";
- attribute.m_value = "0";
- }
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "nodiffuse").second;
- attribute.m_type = "boolean";
- attribute.m_value = "0";
- }
- {
- EntityClassAttribute& attribute = EntityClass_insertAttribute(entityClass, "falloff").second;
- attribute.m_type = "real";
- }
- }
-
- return true;
-}
-
-bool EntityClassDoom3_parseEntityDef(Tokeniser& tokeniser)
-{
- EntityClass* entityClass = Eclass_Alloc();
- entityClass->free = &Eclass_Free;
-
- if(!EntityClass_parse(*entityClass, tokeniser))
- {
- eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
- entityClass->free(entityClass);
- return false;
- }
-
- EntityClass* inserted = EntityClassDoom3_insertUnique(entityClass);
- if(inserted != entityClass)
- {
- globalErrorStream() << "entityDef " << entityClass->name() << " is already defined, second definition ignored\n";
- eclass_capture_state(entityClass); // finish constructing the entity so that it can be destroyed cleanly.
- entityClass->free(entityClass);
- }
- return true;
-}
-
-bool EntityClassDoom3_parseBlock(Tokeniser& tokeniser, const char* blockType)
-{
- if(string_equal(blockType, "entityDef"))
- {
- return EntityClassDoom3_parseEntityDef(tokeniser);
- }
- else if(string_equal(blockType, "model"))
- {
- return EntityClassDoom3_parseModel(tokeniser);
- }
- else
- {
- return EntityClassDoom3_parseUnknown(tokeniser);
- }
-}
-
-bool EntityClassDoom3_parse(TextInputStream& inputStream, const char* filename)
-{
- Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser(inputStream);
-
- tokeniser.nextLine();
-
- for(;;)
- {
- const char* blockType = tokeniser.getToken();
- if(blockType == 0)
- {
- return true;
- }
- CopiedString tmp(blockType);
- if(!EntityClassDoom3_parseBlock(tokeniser, tmp.c_str()))
- {
- globalErrorStream() << GlobalFileSystem().findFile(filename) << filename << ":" << (unsigned int)tokeniser.getLine() << ": " << tmp.c_str() << " parse failed, skipping rest of file\n";
- return false;
- }
- }
-
- tokeniser.release();
-}
-
-
-void EntityClassDoom3_loadFile(const char* filename)
-{
- globalOutputStream() << "parsing entity classes from " << makeQuoted(filename) << "\n";
-
- StringOutputStream fullname(256);
- fullname << "def/" << filename;
-
- ArchiveTextFile* file = GlobalFileSystem().openTextFile(fullname.c_str());
- if(file != 0)
- {
- EntityClassDoom3_parse(file->getInputStream(), fullname.c_str());
- file->release();
- }
-}
-
-EntityClass* EntityClassDoom3_findOrInsert(const char *name, bool has_brushes)
-{
- ASSERT_NOTNULL(name);
-
- if(string_empty(name))
- {
- return g_EntityClassDoom3_bad;
- }
-
- EntityClasses::iterator i = g_EntityClassDoom3_classes.find(name);
- if(i != g_EntityClassDoom3_classes.end()
- //&& string_equal((*i).first, name)
- )
- {
- return (*i).second;
- }
-
- EntityClass* e = EntityClass_Create_Default(name, has_brushes);
- EntityClass* inserted = EntityClassDoom3_insertUnique(e);
- ASSERT_MESSAGE(inserted == e, "");
- return inserted;
-}
-
-const ListAttributeType* EntityClassDoom3_findListType(const char* name)
-{
- return 0;
-}
-
-
-void EntityClass_resolveInheritance(EntityClass* derivedClass)
-{
- if(derivedClass->inheritanceResolved == false)
- {
- derivedClass->inheritanceResolved = true;
- EntityClasses::iterator i = g_EntityClassDoom3_classes.find(derivedClass->m_parent.front().c_str());
- if(i == g_EntityClassDoom3_classes.end())
- {
- globalErrorStream() << "failed to find entityDef " << makeQuoted(derivedClass->m_parent.front().c_str()) << " inherited by " << makeQuoted(derivedClass->m_name.c_str()) << "\n";
- }
- else
- {
- EntityClass* parentClass = (*i).second;
- EntityClass_resolveInheritance(parentClass);
- if(!derivedClass->colorSpecified)
- {
- derivedClass->colorSpecified = parentClass->colorSpecified;
- derivedClass->color = parentClass->color;
- }
- if(!derivedClass->sizeSpecified)
- {
- derivedClass->sizeSpecified = parentClass->sizeSpecified;
- derivedClass->mins = parentClass->mins;
- derivedClass->maxs = parentClass->maxs;
- derivedClass->fixedsize = parentClass->fixedsize;
- }
-
- for(EntityClassAttributes::iterator j = parentClass->m_attributes.begin(); j != parentClass->m_attributes.end(); ++j)
- {
- EntityClass_insertAttribute(*derivedClass, (*j).first.c_str(), (*j).second);
- }
- }
- }
+inline const char* string_find_if( const char* string, Predicate predicate ){
+ for (; *string != 0; ++string )
+ {
+ if ( predicate( *string ) ) {
+ return string;
+ }
+ }
+ return string;
+}
+
+inline const char* string_findFirstSpaceOrTab( const char* string ){
+ return string_find_if( string, char_isSpaceOrTab );
+}
+
+inline const char* string_findFirstNonSpaceOrTab( const char* string ){
+ return string_find_if( string, char_isNotSpaceOrTab );
+}
+
+
+static bool EntityClass_parse( EntityClass& entityClass, Tokeniser& tokeniser ){
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, entityClass.m_name ) );
+
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser, "{" ) );
+ tokeniser.nextLine();
+
+ StringOutputStream usage( 256 );
+ StringOutputStream description( 256 );
+ CopiedString* currentDescription = 0;
+ StringOutputStream* currentString = 0;
+
+ for (;; )
+ {
+ const char* key;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, key ) );
+
+ const char* last = string_findFirstSpaceOrTab( key );
+ CopiedString first( StringRange( key, last ) );
+
+ if ( !string_empty( last ) ) {
+ last = string_findFirstNonSpaceOrTab( last );
+ }
+
+ if ( currentString != 0 && string_equal( key, "\\" ) ) {
+ tokeniser.nextLine();
+ *currentString << " ";
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, *currentString ) );
+ continue;
+ }
+
+ if ( currentDescription != 0 ) {
+ *currentDescription = description.c_str();
+ description.clear();
+ currentDescription = 0;
+ }
+ currentString = 0;
+
+ if ( string_equal( key, "}" ) ) {
+ tokeniser.nextLine();
+ break;
+ }
+ else if ( string_equal( key, "model" ) ) {
+ const char* token;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) );
+ entityClass.fixedsize = true;
+ StringOutputStream buffer( 256 );
+ buffer << PathCleaned( token );
+ entityClass.m_modelpath = buffer.c_str();
+ }
+ else if ( string_equal( key, "editor_color" ) ) {
+ const char* value;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) );
+ if ( !string_empty( value ) ) {
+ entityClass.colorSpecified = true;
+ bool success = string_parse_vector3( value, entityClass.color );
+ ASSERT_MESSAGE( success, "editor_color: parse error" );
+ }
+ }
+ else if ( string_equal( key, "editor_ragdoll" ) ) {
+ //bool ragdoll = atoi(tokeniser.getToken()) != 0;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) );
+ }
+ else if ( string_equal( key, "editor_mins" ) ) {
+ entityClass.sizeSpecified = true;
+ const char* value;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) );
+ if ( !string_empty( value ) && !string_equal( value, "?" ) ) {
+ entityClass.fixedsize = true;
+ bool success = string_parse_vector3( value, entityClass.mins );
+ ASSERT_MESSAGE( success, "editor_mins: parse error" );
+ }
+ }
+ else if ( string_equal( key, "editor_maxs" ) ) {
+ entityClass.sizeSpecified = true;
+ const char* value;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) );
+ if ( !string_empty( value ) && !string_equal( value, "?" ) ) {
+ entityClass.fixedsize = true;
+ bool success = string_parse_vector3( value, entityClass.maxs );
+ ASSERT_MESSAGE( success, "editor_maxs: parse error" );
+ }
+ }
+ else if ( string_equal( key, "editor_usage" ) ) {
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, usage ) );
+ currentString = &usage;
+ }
+ else if ( string_equal_n( key, "editor_usage", 12 ) ) {
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, usage ) );
+ currentString = &usage;
+ }
+ else if ( string_equal( key, "editor_rotatable" )
+ || string_equal( key, "editor_showangle" )
+ || string_equal( key, "editor_showangles" ) // typo? in prey movables.def
+ || string_equal( key, "editor_mover" )
+ || string_equal( key, "editor_model" )
+ || string_equal( key, "editor_material" )
+ || string_equal( key, "editor_combatnode" )
+ || ( !string_empty( last ) && string_equal( first.c_str(), "editor_gui" ) )
+ || string_equal_n( key, "editor_copy", 11 ) ) {
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) );
+ }
+ else if ( !string_empty( last ) && ( string_equal( first.c_str(), "editor_var" ) || string_equal( first.c_str(), "editor_string" ) ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "string";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_float" ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "string";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_snd" ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "sound";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_bool" ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "boolean";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_int" ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "integer";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_model" ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "model";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && string_equal( first.c_str(), "editor_color" ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "color";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( !string_empty( last ) && ( string_equal( first.c_str(), "editor_material" ) || string_equal( first.c_str(), "editor_mat" ) ) ) {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, last ).second;
+ attribute.m_type = "shader";
+ currentDescription = &attribute.m_description;
+ currentString = &description;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, description ) );
+ }
+ else if ( string_equal( key, "inherit" ) ) {
+ entityClass.inheritanceResolved = false;
+ ASSERT_MESSAGE( entityClass.m_parent.empty(), "only one 'inherit' supported per entityDef" );
+ const char* token;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) );
+ entityClass.m_parent.push_back( token );
+ }
+ // begin quake4-specific keys
+ else if ( string_equal( key, "editor_targetonsel" ) ) {
+ //const char* value =
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) );
+ }
+ else if ( string_equal( key, "editor_menu" ) ) {
+ //const char* value =
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) );
+ }
+ else if ( string_equal( key, "editor_ignore" ) ) {
+ //const char* value =
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) );
+ }
+ // end quake4-specific keys
+ // begin ignore prey (unknown/unused?) entity keys
+ else if ( string_equal( key, "editor_light" )
+ || string_equal( key, "editor_def def_debrisspawner" )
+ || string_equal( key, "editor_def def_drop" )
+ || string_equal( key, "editor_def def_guihand" )
+ || string_equal( key, "editor_def def_mine" ) ) {
+ //const char* value =
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseToken( tokeniser ) );
+ }
+ // end ignore prey entity keys
+ else
+ {
+ CopiedString tmp( key );
+ ASSERT_MESSAGE( !string_equal_n( key, "editor_", 7 ), "unsupported editor key: " << makeQuoted( key ) );
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, key ).second;
+ attribute.m_type = "string";
+ const char* value;
+ PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, value ) );
+ if ( string_equal( value, "}" ) ) { // hack for quake4 powerups.def bug
+ globalErrorStream() << "entityDef " << makeQuoted( entityClass.m_name.c_str() ) << " key " << makeQuoted( tmp.c_str() ) << " has no value\n";
+ break;
+ }
+ else
+ {
+ attribute.m_value = value;
+ }
+ }
+ tokeniser.nextLine();
+ }
+
+ entityClass.m_comments = usage.c_str();
+
+ if ( string_equal( entityClass.m_name.c_str(), "light" ) ) {
+ {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "light_radius" ).second;
+ attribute.m_type = "vector3";
+ attribute.m_value = "300 300 300";
+ }
+ {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "light_center" ).second;
+ attribute.m_type = "vector3";
+ }
+ {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "noshadows" ).second;
+ attribute.m_type = "boolean";
+ attribute.m_value = "0";
+ }
+ {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "nospecular" ).second;
+ attribute.m_type = "boolean";
+ attribute.m_value = "0";
+ }
+ {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "nodiffuse" ).second;
+ attribute.m_type = "boolean";
+ attribute.m_value = "0";
+ }
+ {
+ EntityClassAttribute& attribute = EntityClass_insertAttribute( entityClass, "falloff" ).second;
+ attribute.m_type = "real";
+ }
+ }
+
+ return true;
+}
+
+bool EntityClassDoom3_parseEntityDef( Tokeniser& tokeniser ){
+ EntityClass* entityClass = Eclass_Alloc();
+ entityClass->free = &Eclass_Free;
+
+ if ( !EntityClass_parse( *entityClass, tokeniser ) ) {
+ eclass_capture_state( entityClass ); // finish constructing the entity so that it can be destroyed cleanly.
+ entityClass->free( entityClass );
+ return false;
+ }
+
+ EntityClass* inserted = EntityClassDoom3_insertUnique( entityClass );
+ if ( inserted != entityClass ) {
+ globalErrorStream() << "entityDef " << entityClass->name() << " is already defined, second definition ignored\n";
+ eclass_capture_state( entityClass ); // finish constructing the entity so that it can be destroyed cleanly.
+ entityClass->free( entityClass );
+ }
+ return true;
+}
+
+bool EntityClassDoom3_parseBlock( Tokeniser& tokeniser, const char* blockType ){
+ if ( string_equal( blockType, "entityDef" ) ) {
+ return EntityClassDoom3_parseEntityDef( tokeniser );
+ }
+ else if ( string_equal( blockType, "model" ) ) {
+ return EntityClassDoom3_parseModel( tokeniser );
+ }
+ else
+ {
+ return EntityClassDoom3_parseUnknown( tokeniser );
+ }
+}
+
+bool EntityClassDoom3_parse( TextInputStream& inputStream, const char* filename ){
+ Tokeniser& tokeniser = GlobalScriptLibrary().m_pfnNewScriptTokeniser( inputStream );
+
+ tokeniser.nextLine();
+
+ for (;; )
+ {
+ const char* blockType = tokeniser.getToken();
+ if ( blockType == 0 ) {
+ return true;
+ }
+ CopiedString tmp( blockType );
+ if ( !EntityClassDoom3_parseBlock( tokeniser, tmp.c_str() ) ) {
+ globalErrorStream() << GlobalFileSystem().findFile( filename ) << filename << ":" << (unsigned int)tokeniser.getLine() << ": " << tmp.c_str() << " parse failed, skipping rest of file\n";
+ return false;
+ }
+ }
+
+ tokeniser.release();
+}
+
+
+void EntityClassDoom3_loadFile( const char* filename ){
+ globalOutputStream() << "parsing entity classes from " << makeQuoted( filename ) << "\n";
+
+ StringOutputStream fullname( 256 );
+ fullname << "def/" << filename;
+
+ ArchiveTextFile* file = GlobalFileSystem().openTextFile( fullname.c_str() );
+ if ( file != 0 ) {
+ EntityClassDoom3_parse( file->getInputStream(), fullname.c_str() );
+ file->release();
+ }
+}
+
+EntityClass* EntityClassDoom3_findOrInsert( const char *name, bool has_brushes ){
+ ASSERT_NOTNULL( name );
+
+ if ( string_empty( name ) ) {
+ return g_EntityClassDoom3_bad;
+ }
+
+ EntityClasses::iterator i = g_EntityClassDoom3_classes.find( name );
+ if ( i != g_EntityClassDoom3_classes.end()
+ //&& string_equal((*i).first, name)
+ ) {
+ return ( *i ).second;
+ }
+
+ EntityClass* e = EntityClass_Create_Default( name, has_brushes );
+ EntityClass* inserted = EntityClassDoom3_insertUnique( e );
+ ASSERT_MESSAGE( inserted == e, "" );
+ return inserted;
+}
+
+const ListAttributeType* EntityClassDoom3_findListType( const char* name ){
+ return 0;
+}
+
+
+void EntityClass_resolveInheritance( EntityClass* derivedClass ){
+ if ( derivedClass->inheritanceResolved == false ) {
+ derivedClass->inheritanceResolved = true;
+ EntityClasses::iterator i = g_EntityClassDoom3_classes.find( derivedClass->m_parent.front().c_str() );
+ if ( i == g_EntityClassDoom3_classes.end() ) {
+ globalErrorStream() << "failed to find entityDef " << makeQuoted( derivedClass->m_parent.front().c_str() ) << " inherited by " << makeQuoted( derivedClass->m_name.c_str() ) << "\n";
+ }
+ else
+ {
+ EntityClass* parentClass = ( *i ).second;
+ EntityClass_resolveInheritance( parentClass );
+ if ( !derivedClass->colorSpecified ) {
+ derivedClass->colorSpecified = parentClass->colorSpecified;
+ derivedClass->color = parentClass->color;
+ }
+ if ( !derivedClass->sizeSpecified ) {
+ derivedClass->sizeSpecified = parentClass->sizeSpecified;
+ derivedClass->mins = parentClass->mins;
+ derivedClass->maxs = parentClass->maxs;
+ derivedClass->fixedsize = parentClass->fixedsize;
+ }
+
+ for ( EntityClassAttributes::iterator j = parentClass->m_attributes.begin(); j != parentClass->m_attributes.end(); ++j )
+ {
+ EntityClass_insertAttribute( *derivedClass, ( *j ).first.c_str(), ( *j ).second );
+ }
+ }
+ }