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 ); } } } }
/** * Add a new EntityClassAttribute to entity class based on given definition * @param e entity class to add attribute to * @param keydef definition parsed from entities.ufo with information about type, * default values and mandatory state. * @note opposed to old parsing code this adds attributes for all definitions, * not only for the ones that get special treatment in gui. */ void EntityClassScannerUFO::parseAttribute (EntityClass *e, const entityKeyDef_t* keydef) { const bool mandatory = (keydef->flags & ED_MANDATORY); /* we use attribute key as its type, only for some types this is really used */ std::string attributeName = keydef->name; std::string value = ""; std::string desc = ""; if (keydef->defaultVal) value = keydef->defaultVal; if (keydef->desc) desc = keydef->desc; int typeFlag = keydef->flags & ED_KEY_TYPE; std::string type = attributeName; if (attributeName == "noise") type = "sound"; else if (attributeName == "_color" || attributeName == "color") type = "colour"; else if (attributeName == "target") type = "entity"; else if (typeFlag & ED_TYPE_FLOAT) { if (keydef->vLen == 3) type = "vector3"; else if (keydef->vLen == 1) type = "float"; } else if (typeFlag & ED_TYPE_INT) { // integer } else if (typeFlag == 0 || (typeFlag & ED_TYPE_STRING)) { // string } EntityClassAttribute attribute = EntityClassAttribute(type, attributeName, mandatory, value, desc); EntityClass_insertAttribute(*e, attributeName, attribute); }
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 ); if ( string_equal_n( key, "editor_", 7 ) ) { globalErrorStream() << "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; }
/** * Creates a new entityclass for given parsed definition * @param entityDef parsed definition information to use * @return a new entity class or 0 if something was wrong with definition */ EntityClass *EntityClassScannerUFO::initFromDefinition (const entityDef_t* definition) { g_debug("Creating entity class for entity definition '%s'\n", definition->classname); EntityClass* e = Eclass_Alloc(); e->free = &Eclass_Free; e->m_name = definition->classname; for (int idx = 0; idx < definition->numKeyDefs; idx++) { const entityKeyDef_t* keydef = &definition->keyDefs[idx]; const std::string keyName = keydef->name; if (keyName == "color") { //not using _color as this is a valid attribute flag // grab the color, reformat as texture name const int r = sscanf(keydef->desc, "%f %f %f", &e->color[0], &e->color[1], &e->color[2]); if (r != 3) { g_message("Invalid color token given\n"); return 0; } } else if (keyName == "size") { e->fixedsize = true; const int r = sscanf(keydef->desc, "%f %f %f %f %f %f", &e->mins[0], &e->mins[1], &e->mins[2], &e->maxs[0], &e->maxs[1], &e->maxs[2]); if (r != 6) { g_message("Invalid size token given\n"); return 0; } } else if (keyName == "description") { e->m_comments = keydef->desc; } else if (keyName == "spawnflags") { if (keydef->flags & ED_ABSTRACT) { /* there are two keydefs, abstract holds the valid levelflags, the other one default value and type */ const char* flags = keydef->desc; parseFlags(e, &flags); } else { parseAttribute(e, keydef); } } else if (keyName == "classname") { /* ignore, read from head */ continue; } else if (keyName == "model") { /** @todo what does that modelpath stuff do? it does not read anything from keydef */ e->m_modelpath = os::standardPath(e->m_modelpath); const bool mandatory = (keydef->flags & ED_MANDATORY); EntityClass_insertAttribute(*e, "model", EntityClassAttribute("model", "model", mandatory)); } else { /* all other keys are valid attribute keys */ parseAttribute(e, keydef); } } #if 0 /** * @todo direction and angle are 2 types used for different display * (see entityinspector DirectionAttribute and AngleAttribute) * the problem is that different entities have "angle" property, but different defines what values are valid * which is actually not reflected by this code. Perhaps we should introduce different types for these representations. */ EntityClassAttribute *angle = e->getAttribute("angle"); if (angle) { if (e->fixedsize) { angle->name = _("Yaw Angle"); } else { angle->name = _("Direction"); } } #endif eclass_capture_state(e); return e; }