// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/> // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // phrase_generator.cpp : Defines the entry point for the console application. // //-b -p r:\code\ryzom\data_leveldesign -o r:/code/ryzom/data_leveldesign/leveldesign/game_element/sphrase/magic/ magic_bricks.csv -d -m // -p r:\code\ryzom\data_leveldesign -o r:/code/ryzom/data_leveldesign/leveldesign/game_element/sphrase/magic/ magic_bricks.csv -d -m #include "stdafx.h" // Misc #include <nel/misc/types_nl.h> #include "nel/misc/path.h" #include "nel/misc/file.h" #include "nel/misc/smart_ptr.h" #include "nel/misc/command.h" #include "nel/misc/common.h" #include "nel/misc/path.h" #include <nel/misc/sstring.h> #include <nel/misc/diff_tool.h> #include "nel/misc/algo.h" #include "nel/misc/words_dictionary.h" // Georges #include "nel/georges/u_form.h" #include "nel/georges/u_form_elm.h" #include "nel/georges/u_form_dfn.h" #include "nel/georges/u_form_loader.h" #include "nel/georges/u_type.h" // Georges, bypassing interface #include "georges/stdgeorges.h" #include "georges/form.h" // Game share //#include "game_share/xml.h" // Unicode language file // C #include <time.h> #include <stdio.h> #include <conio.h> #include <fstream> // stl #include <map> #include "skill_tree.h" using namespace NLMISC; using namespace NLGEORGES; using namespace std; typedef vector<string> vs; typedef map< string, string > mss; typedef map< string, vs > msvs; bool GenerateBrickProgression = false; bool ProduceDocFromExistingPhrases = false; bool MultipleDocFiles = false; bool Hypertext = true; string PhrasePath = "r:/code/ryzom/data_leveldesign/leveldesign/game_element/sphrase/"; uint NbSheetsGenTries = 0; uint NbSheetsWritten = 0; uint NbSheetsRead = 0; uint NbSheetsRejected = 0; bool UseBricks; const string brSheetType = "sbrick"; const string phSheetType = "sphrase"; const string PHRASE_MAGIC_PREFIX = "abm_"; // action bricks magic (bm for brick filter) struct CBrickInfo { CBrickInfo( const string& ls="", const string& t="", const vs& props=vs() ) : LearnSkills(ls), Text(t), Props(props) {} string LearnSkills; string Text; // UTF-8 vs Props; }; vs OptionBricks, CounterpartBricks, AllBricks, PhrasesWithInvalidCost, InvalidPhrases; set<string> UsedCounterpartBricks, UsedCounterpartBrickFamiliesInPhrase; map<string, sint> SabrinaCosts; map<string, sint> PhraseSabrinaCosts; map<string, bool> PhraseCastable; map<string, CBrickInfo> BrickInfo; mss TextToBrick; multimap< uint, pair<string, string> > Progression; // phrase code, min. skill mss PhraseNames, PhraseTitles; vector<vs> ValidPhrases; set<string> UsedBricks, GeneratedPhrases; map<string, vs> GrammarMandatParamBrickFamilies, GrammarOptionCreditBrickFamilies; UFormLoader *FormLoader; vector<FILE*> PhraseDocFiles( 26 ); string DocFileName,DocFileNameRoot; msvs Phrases; map<string,uint> SkillNameToMaxSkill; map<string,string> PhraseCodeToLink; CWordsDictionary Dico; CStaticSkillsTree SkillsTree; /* * */ string inputSheetPath; bool inputSheetPathLoaded = false; map<string, string> inputSheetPathContent; // short filename without ext, full filename with path //----------------------------------------------- // getBrickTypeLetterRPos // //----------------------------------------------- uint getBrickTypeLetterRPos( string& brick ) { /* uint i =0; while( i<brick.size() && !isdigit(brick[i]) ) i++; nlassert(i<brick.size()); return (brick.size() - i + 2); */ uint i =brick.size()-1; while( i>=0 && (isdigit(brick[i]) || brick[i]=='_') ) i--; return (brick.size() - i + 1); } // getBrickTypeLetterRPos // //----------------------------------------------- // loadSheetPath // // from georges2csv //----------------------------------------------- void loadSheetPath() { if (inputSheetPathLoaded) return; NLMISC::createDebug(); NLMISC::WarningLog->addNegativeFilter( "CPath::insertFileInMap" ); CPath::addSearchPath(inputSheetPath, true, false); // for Georges to work properly vector<string> files; CPath::getPathContent (inputSheetPath, true, false, true, files); uint i; for (i=0; i<files.size(); ++i) { string filename = files[i]; string filebase = CFile::getFilenameWithoutExtension(filename); if( CFile::getExtension(filename)!="saibrick" && CFile::getExtension(filename)!="saiphrase" ) { inputSheetPathContent[filebase] = filename; } } inputSheetPathLoaded = true; } // loadSheetPath // /* * */ void displayList( const string& title, const vector<string>& v, CLog *log=DebugLog ) { if ( ! title.empty() ) log->displayRaw( "%s: ", title.c_str() ); vector<string>::const_iterator ist; for ( ist=v.begin(); ist!=v.end(); ++ist ) log->displayRaw( "%s ", (*ist).c_str() ); log->displayRawNL( "" ); } /* * */ class CStrIComparator : public binary_function<string, string, bool> { public: bool operator() ( const string& s1, const string& s2 ) const { return (nlstricmp( s1, s2 ) == 0); } }; /* * */ uint getIndexFromString( const string& s, const vector<string>& v, bool displayWarning=true ) { if ( v.empty() ) { nlwarning( "Can't find '%s' in empty array", s.c_str() ); return ~0; } else { vector<string>::const_iterator ist = find_if( v.begin(), v.end(), bind2nd(CStrIComparator(), s) ); if ( ist == v.end() ) { if ( displayWarning ) { nlwarning( "Can't find '%s' in:", s.c_str() ); displayList( "", v, WarningLog ); } return ~0; } else return ist - v.begin(); } } //----------------------------------------------- // Erase every carriage returns of the string // //----------------------------------------------- void eraseCarriageReturns( string& s ) { const char CR = '\n'; string::size_type p = s.find( CR ); while ( (p=s.find( CR )) != string::npos ) s.erase( p, 1 ); } // // First param: vector of indices of columns matching wantedColumnNames // Second param: vector of fields matching wantedColumnNames typedef void (*TDeliveryCallback) ( mss& ); //----------------------------------------------- // loadCSVFile // //----------------------------------------------- void loadCSVFile( const char *filename, TDeliveryCallback deliveryCallback ) { char lineBuffer[2048]; FILE *file; const char *SEPARATOR = ";"; vector<string> args; vector<string>::iterator iarg; if ( (file = nlfopen( filename, "r" )) == NULL ) { nlwarning( "Can't find file %s", filename ); } else { // Read first line as header with column names lineBuffer[0] = '\0'; fgets( lineBuffer, 2048, file ); explode( lineBuffer, SEPARATOR, args ); // Store column names (and get rid of carriage returns!) vector < string > columnNames; mss valuesByName; for ( iarg=args.begin(); iarg!=args.end(); ++iarg ) { eraseCarriageReturns( *iarg ); columnNames.push_back( *iarg ); valuesByName.insert( make_pair( *iarg, string("") ) ); } // for each line, deliver the value of the fields while ( ! feof(file) ) { // Get from file lineBuffer[0] = '\0'; fgets( lineBuffer, 2048, file ); explode( lineBuffer, SEPARATOR, args ); // Set values (and get rid of carriage returns!) for ( iarg=args.begin(); iarg!=args.end(); ++iarg ) { eraseCarriageReturns( *iarg ); valuesByName[columnNames[iarg-args.begin()]] = *iarg; } // Deliver the wanted fields deliveryCallback( valuesByName ); } } } // loadCSVFile // //set<string> Skills; //----------------------------------------------- // brickDeliveryCallback // // Fetch brick code and sabrina cost // - AllBricks // - BrickInfo // - OptionBricks // - CounterpartBricks // - SabrinaCosts //----------------------------------------------- void brickDeliveryCallback( mss& values ) { string s = values["Brick_id"]; if ( s.empty() ) { s = values["FILE"]; if ( s.empty() ) s = values["fileName"]; } string brick = CFile::getFilenameWithoutExtension( s ); strupr( brick ); if ( brick.empty() ) { nlwarning("<brickDeliveryCallback> can't get root filename of %s",s.c_str()); return; } string sc = values["Basics.SabrinaCost"]; string ls = values["Basics.LearnRequiresOneOfSkills"]; string txt = values["name"]; // TODO: only for combat string fmn = values["familyName"]; string propIdent = "Basics.Property"; if ( UseBricks ) { AllBricks.push_back( brick ); string name = (txt.empty()) ? fmn : txt; vs props; // Find all Basics.Property N (assumes they are subsequent) mss::const_iterator imv = values.find( propIdent + " 0" ); for ( ; imv!=values.end(); ++imv ) { const string& colName = (*imv).first; const string& v = (*imv).second; if ( colName.find( propIdent ) != string::npos ) { if ( v != "NULL" && !v.empty() ) props.push_back( v ); } else break; } BrickInfo.insert( make_pair( brick, CBrickInfo( ls, name, props ) ) ); } // Store brick in right container string::size_type p = brick.size() - getBrickTypeLetterRPos(brick); if ( ((sint)p) >= 0 ) { switch ( brick[p] ) { case 'O': OptionBricks.push_back( brick ); break; case 'C': CounterpartBricks.push_back( brick ); break; } } else { nlwarning( "Invalid brick code: %s", brick.c_str() ); return; } // Store cost sint sabrinaCost; if ( sc.empty() ) { nldebug( "No sabrina cost for %s, assuming cost 0", brick.c_str() ); sabrinaCost = 0; } else { sabrinaCost = atoi( sc.c_str() ); } SabrinaCosts.insert( make_pair( brick, sabrinaCost ) ); /* // Quick hack to generate skill codes string skill = brick.substr( 1, p-1 ); if ( ! skill.empty() ) Skills.insert( skill );*/ } // brickDeliveryCallback // //----------------------------------------------- // loadBricks // //----------------------------------------------- void loadBricks( const char* filename ) { loadCSVFile( filename, brickDeliveryCallback ); if ( ProduceDocFromExistingPhrases ) nlinfo( "Loaded %u option bricks, %u counterpart bricks, %u sabrina costs", OptionBricks.size(), CounterpartBricks.size(), SabrinaCosts.size() ); else if ( UseBricks ) nlinfo( "Loaded %u bricks", AllBricks.size() ); /*set<string>::const_iterator iss; for ( iss=Skills.begin(); iss!=Skills.end(); ++iss ) { const string& skill = (*iss); InfoLog->displayRawNL( " <DEFINITION Label=\"S%s\" Value=\"S%s\"/>", skill.c_str(), skill.c_str() ); }*/ } // loadBricks // /* * */ string getRootBrickForOptionOrCredit( const string& ob ) { // Extract brick code radix string::size_type p = ob.size() - getBrickTypeLetterRPos(const_cast<string&>(ob)); if ( (ob.size() <= getBrickTypeLetterRPos(const_cast<string&>(ob))) || ((ob[p] != 'O') && (ob[p] != 'C')) ) nlerror( "%s is not an option or credit brick", ob.c_str() ); string radix = ob.substr( 0, p ); // Append root brick suffix return radix + "PA01"; } /* * */ string getBrickFamily( const string& b ) { if ( b.size() >= getBrickTypeLetterRPos(const_cast<string&>(b))+2 ) { string::size_type p = b.size() - getBrickTypeLetterRPos(const_cast<string&>(b)); return b.substr( 0, p+2 ); } return string(); } /* * */ bool isFromBrickFamily( const string& brick, const string& fam ) { return nlstricmp( brick.substr( 0, fam.size() ), fam ) == 0; } /* * */ string getFirstBrickOfFamily( const string& family ) { vs::const_iterator ib; for ( ib=AllBricks.begin(); ib!=AllBricks.end(); ++ib ) { const string& brick = *ib; if ( isFromBrickFamily( brick, family ) ) return brick; } return string(); } /* * */ vs getAllBricksOfFamily( const string& family ) { vs res; vs::const_iterator ib; for ( ib=AllBricks.begin(); ib!=AllBricks.end(); ++ib ) { const string& brick = *ib; if ( isFromBrickFamily( brick, family ) ) res.push_back( brick ); } return res; } /* * */ uint getCompatibleCounterpartBrickForCost( uint phraseCost, vs& phrase ) { //nlinfo( "Searching credit for cost %u", phraseCost ); // Get the lowest matching counterpart brick uint minHigherCounterpartValue = ~0, maxLowerCounterpartValue = 0, counterpartValue; vs::const_iterator icb, iPerfectMatch = CounterpartBricks.end(), iMinCb = CounterpartBricks.end(), iMaxCb = CounterpartBricks.end(); for ( icb=CounterpartBricks.begin(); icb!=CounterpartBricks.end(); ++icb) { const string& cb = *icb; // Skip if family already used in current phrase if ( UsedCounterpartBrickFamiliesInPhrase.find( getBrickFamily( cb ) ) != UsedCounterpartBrickFamiliesInPhrase.end() ) continue; counterpartValue = abs( SabrinaCosts[cb] ); //nldebug( "Trying with credit %u", counterpartValue ); if ( counterpartValue == phraseCost ) { // Perfect match, check if not already taken if ( UsedCounterpartBricks.insert( cb ).second ) { UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( cb ) ); phrase.push_back( cb ); return counterpartValue; } else { // If already taken, we will come back to it later iPerfectMatch = icb; } } else if ( counterpartValue > phraseCost ) { // Higher => get the minimum if ( counterpartValue < minHigherCounterpartValue ) { minHigherCounterpartValue = counterpartValue; iMinCb = icb; } } else // counterpartValue < phraseCost : store the max { if ( counterpartValue >= maxLowerCounterpartValue ) { maxLowerCounterpartValue = counterpartValue; iMaxCb = icb; } } } if ( iPerfectMatch != CounterpartBricks.end() ) { // We skipped a perfect match in order to try to get a new value. But none found. Now get back to the last value. phrase.push_back( *iPerfectMatch ); UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( *iPerfectMatch ) ); return abs( SabrinaCosts[*iPerfectMatch] ); } else if ( iMinCb == CounterpartBricks.end() ) { if ( iMaxCb == CounterpartBricks.end() ) { nlerror( "No matching counterpart" ); return ~0; } else { // No phrase possible with only one (more) counterpart, try with the max and more (recurse) UsedCounterpartBricks.insert( *iMaxCb ); UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( *iMaxCb ) ); phrase.push_back( *iMaxCb ); return maxLowerCounterpartValue + getCompatibleCounterpartBrickForCost( phraseCost - maxLowerCounterpartValue, phrase ); } } else { // Phrase possible with one (more) counterpart UsedCounterpartBricks.insert( *iMinCb ); UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( *iMinCb ) ); phrase.push_back( *iMinCb ); return minHigherCounterpartValue; } } /* * */ void getCompatibleCounterpartBricks( vs& phrase ) { // Calculate the cost of the phrase sint phraseCost = 0; string phraseStr; vs::const_iterator ip; for ( ip=phrase.begin(); ip!=phrase.end(); ++ip ) { const string& brick = *ip; sint sabrinaCost; map<string, sint>::const_iterator isc = SabrinaCosts.find( brick ); if ( isc != SabrinaCosts.end() ) sabrinaCost = (*isc).second; else sabrinaCost = 0; phraseCost += sabrinaCost; phraseStr += brick + " "; } // Find matching counterpart(s), only 1 per family UsedCounterpartBrickFamiliesInPhrase.clear(); uint counterpartValue = getCompatibleCounterpartBrickForCost( phraseCost, phrase ); displayList( toString( "+%3u -%3u", phraseCost, counterpartValue ), phrase ); } /* * */ /*void getCompatiblePhraseByCounterpart( const string& counterpartBrick, vs& phrase ) { sint sabrinaCost = SabrinaCosts[counterpartBrick]; // Assuming root brick cost is zero! vs::const_iterator iob; for ( iob=OptionBricks.begin(); iob!=OptionBricks.end(); ++iob ) { // TODO: Find the highest cost that is lower or equal than the counterpart value const string& ob = *iob; if ( SabrinaCosts[ob] <= SabrinaCosts[counterpartBrick] ) break; // currently, take the first found } if ( iob != OptionBricks.end() ) { string rb = getRootBrickForOptionOrCredit( *iob ); phrase.push_back( rb ); phrase.push_back( *iob ); phrase.push_back( counterpartBrick ); nldebug( "%s %s %s: +%u -%u", rb.c_str(), (*iob).c_str(), counterpartBrick.c_str(), SabrinaCosts[rb]+SabrinaCosts[*iob], SabrinaCosts[counterpartBrick] ); } else nlwarning( "No matching phrase for counterpart %s", counterpartBrick.c_str() ); }*/ /* * Clear the form to reuse it (and all contents below node) */ void clearSheet( CForm *form, UFormElm* node ) { ((CFormElm*)node)->clean(); form->clean(); } /* * */ inline void explodeBrickAndParameters( const string& brickAndParams, vs& bricks ) { explode( brickAndParams, " ", bricks ); } /* * */ string getBrickType( const string& brick ) { if ( brick.size() < 4 ) return "INVALID TYPE in " + brick; else { switch ( brick[brick.size()-getBrickTypeLetterRPos(const_cast<string&>(brick))] ) { case 'P': return "Root"; break; case 'E': return "Effect"; break; case 'O': return "Option"; break; case 'M': return "Modifier"; break; case 'C': return "Credit"; break; default: return "INVALID TYPE in " + brick; } } } //----------------------------------------------- // printBrickInfo // //----------------------------------------------- void printBrickInfo( FILE *htmlfile, const string& brick, const string& grammarError, sint& sabrinaCost, uint& minSkillValue, string& minSkill ) { minSkill.clear(); string b = brick; strupr( b ); string brickType = getBrickType( b ); sint sc = (brickType=="Credit") ? -abs( SabrinaCosts[b] ) : SabrinaCosts[b]; CBrickInfo& bInfo = BrickInfo[b]; fprintf( htmlfile, "<LI><B>%s %s</B> %s<BR>\n", brickType.c_str(), b.c_str(), bInfo.Text.c_str() ); if ( ! grammarError.empty() ) { fprintf( htmlfile, "<FONT COLOR=\"RED\">%s</FONT><BR>\n", grammarError.c_str() ); } else { fprintf( htmlfile, "Sabrina Cost: %d <BR>\n", sc ); if( !bInfo.LearnSkills.empty() ) { fprintf( htmlfile, "Skills required: %s<BR>\n", bInfo.LearnSkills.c_str() ); } if( bInfo.Props.size() ) { fprintf( htmlfile, "Properties:" ); for ( vs::const_iterator ip = bInfo.Props.begin(); ip!=bInfo.Props.end(); ++ip ) { fprintf( htmlfile, " %s", (*ip) ); } } } fprintf( htmlfile, "</LI>\n" ); // Calculate sabrina cost & skill value sabrinaCost = sc; if ( bInfo.LearnSkills.empty() ) minSkillValue = 0; else { minSkillValue = ~0; vector<string> skillsAndValues; explode( bInfo.LearnSkills, ":", skillsAndValues, true ); vector<uint> skillValues( skillsAndValues.size(), ~0 ); vector<string>::iterator isv; for ( isv=skillsAndValues.begin(); isv!=skillsAndValues.end(); ++isv ) { const string& sav = *isv; string::size_type p = sav.find( ' ' ); if ( (p == string::npos) || (sav.size() == p+1) ) nlwarning( "Invalid LearnRequiresOneOfSkills value '%s'", sav.c_str() ); else { uint sv = atoi( sav.substr( p+1 ).c_str() ); skillValues[isv-skillsAndValues.begin()] = sv; if ( sv < minSkillValue ) minSkillValue = sv; } } for ( isv=skillsAndValues.begin(); isv!=skillsAndValues.end(); ++isv ) { if ( skillValues[isv-skillsAndValues.begin()] == minSkillValue ) { string& sav = *isv; if ( (! sav.empty()) && (sav[0] != 'S') ) sav = 'S' + sav; if ( minSkill.find( sav ) == string::npos ) { if ( ! minSkill.empty() ) minSkill += ", "; minSkill += sav; } } } } } // printBrickInfo // //----------------------------------------------- // loadBrickGrammar // //----------------------------------------------- void loadBrickGrammar() { uint nbRootBricks = 0; vs::const_iterator ib; for ( ib=AllBricks.begin(); ib!=AllBricks.end(); ++ib ) { string brick = *ib; strupr( brick ); if ( brick.size() >= 4 ) { char brickType = brick[brick.size()-getBrickTypeLetterRPos(brick)]; /*// As the root bricks may be absent from the table, deduce them (obsolete) if ( brickType == 'O' ) { string rootBrick = getRootBrickForOptionOrCredit( brick ); if ( GrammarOptionCreditBrickFamilies.find( rootBrick ) == GrammarOptionCreditBrickFamilies.end() ) { brick = rootBrick; brickType = 'P'; } else { continue; } }*/ // If not skipped by previous 'continue' if ( (brickType == 'P') || (brickType == 'E') || (brickType == 'O' ) ) // root, effect, option { NLMISC::CSmartPtr<CForm> form = (CForm*)FormLoader->loadForm( (strlwr(static_cast<const string&>(brick))+"."+brSheetType).c_str() ); if ( ! form ) { nlwarning( "Can't load sheet %s", ((strlwr(static_cast<const string&>(brick)))+"."+phSheetType).c_str() ); continue; } for ( uint i=0; i!=12; ++i ) { string value; form->getRootNode().getValueByName( value, toString( "Mandatory.f%u", i ).c_str() ); if ( (! value.empty()) && (value != "Unknown") ) { GrammarMandatParamBrickFamilies[brick].push_back( value ); } } if ( brickType == 'O' ) { for ( uint i=0; i!=4; ++i ) { string value; form->getRootNode().getValueByName( value, toString( "Parameter.f%u", i ).c_str() ); if ( (! value.empty()) && (value != "Unknown") ) { GrammarMandatParamBrickFamilies[brick].push_back( value ); } } } if ( brickType == 'P' ) // root { ++nbRootBricks; for ( uint i=0; i!=32; ++i ) { string value; form->getRootNode().getValueByName( value, toString( "Optional.f%u", i ).c_str() ); if ( (! value.empty()) && (value != "Unknown") ) { GrammarOptionCreditBrickFamilies[brick].push_back( value ); } } for ( uint i=0; i!=12; ++i ) { string value; form->getRootNode().getValueByName( value, toString( "Credit.f%u", i ).c_str() ); if ( (! value.empty()) && (value != "Unknown") ) { GrammarOptionCreditBrickFamilies[brick].push_back( value ); } } } } } else { nlwarning( "Invalid brick code %s", brick.c_str() ); } } nlinfo( "%u bricks have mandatory/parameter grammar rules", GrammarMandatParamBrickFamilies.size() ); nlinfo( "%u bricks have option/credit grammar rules", GrammarOptionCreditBrickFamilies.size() ); nlinfo( "Found or deduced %u root bricks", nbRootBricks ); } // loadBrickGrammar // //----------------------------------------------- // loadPhraseTitles // //----------------------------------------------- void loadPhraseTitles() { STRING_MANAGER::TWorksheet worksheet; STRING_MANAGER::loadExcelSheet( "r:/code/ryzom/translation/translated/sphrase_words_en.txt", worksheet ); uint cp, cn; if ( worksheet.findCol( ucstring("sphrase ID"), cp ) && worksheet.findCol( ucstring("name"), cn ) ) { for ( std::vector<STRING_MANAGER::TWorksheet::TRow>::iterator ip = worksheet.begin(); ip!=worksheet.end(); ++ip ) { if ( ip == worksheet.begin() ) // skip first row continue; STRING_MANAGER::TWorksheet::TRow& row = *ip; PhraseTitles.insert( make_pair( strlwr(row[cp].toString()), row[cn].toUtf8() ) ); } } else nlwarning( "sphrase ID or name not found" ); nlinfo( "Loaded %u phrase titles", PhraseTitles.size() ); } // loadPhraseTitles // //----------------------------------------------- // loadBrickTitles // //----------------------------------------------- void loadBrickTitles() { STRING_MANAGER::TWorksheet worksheet; STRING_MANAGER::loadExcelSheet( "r:/code/ryzom/translation/translated/sbrick_words_en.txt", worksheet ); uint cp, cn, nbTitles = 0; if ( worksheet.findCol( ucstring("sbrick ID"), cp ) && worksheet.findCol( ucstring("name"), cn ) ) { for ( std::vector<STRING_MANAGER::TWorksheet::TRow>::iterator ip = worksheet.begin(); ip!=worksheet.end(); ++ip ) { if ( ip == worksheet.begin() ) // skip first row continue; STRING_MANAGER::TWorksheet::TRow& row = *ip; BrickInfo[strupr(row[cp].toString())].Text = row[cn].toUtf8();; ++nbTitles; } } else nlwarning( "sbrick ID or name not found" ); nlinfo( "Loaded %u brick titles", nbTitles ); } // loadBrickTitles // /* * */ void getChildrenBricks( const string& brick, vs& chFamilies ) { chFamilies = GrammarMandatParamBrickFamilies[brick]; } /* * */ void addError( string& errorStr, string& newError, uint& nbGrammarErrors ) { if ( ! errorStr.empty() ) errorStr += "<BR>"; errorStr += newError; ++nbGrammarErrors; } /* * */ void checkOptionOrCreditCompatibility( string& errorStr, const string& currentBrick, const string& rootBrick, uint& nbGrammarErrors ) { string brick = currentBrick; strupr( brick ); if ( brick.size() >= 4 && brick[1]!='C' && brick[1]!='H') // C & H for craft and harvest { char brickType = brick[brick.size()-getBrickTypeLetterRPos(brick)]; if ( (brickType == 'O') || (brickType == 'C') ) { string rootBrick = getRootBrickForOptionOrCredit( brick ); const vs& compatibleOptionOrCredits = GrammarOptionCreditBrickFamilies[rootBrick]; vs::const_iterator ic; for ( ic=compatibleOptionOrCredits.begin(); ic!=compatibleOptionOrCredits.end(); ++ic ) { if ( isFromBrickFamily( brick, (*ic) ) ) break; } if ( ic == compatibleOptionOrCredits.end() ) { addError( errorStr, toString( "This family is not compatible with options/credits of root %s", rootBrick.c_str() ), nbGrammarErrors ); } } } } /* * Preconditions: * - grammarErrors.size() == phrase.size() * - r < phrase.size() * * Note: does not check that all bricks should have a different family */ void checkGrammar( const vs& phrase, uint& r, vs& grammarErrors, uint& nbGrammarErrors, const string& rootBrick, bool readNext=true ) { uint origR = r; string grammarBrick = phrase[origR]; strupr( grammarBrick ); // Check option/credit checkOptionOrCreditCompatibility( grammarErrors[r], phrase[r], rootBrick, nbGrammarErrors ); // Check mandatory/parameter vs chFamilies; getChildrenBricks( grammarBrick, chFamilies ); ++r; for ( vs::const_iterator icf=chFamilies.begin(); icf!=chFamilies.end(); ++icf ) { // Detect incomplete phrase if ( r >= phrase.size() ) { addError( grammarErrors[origR], "Missing mandatory/parameter " + (*icf) + " at the end", nbGrammarErrors ); break; } // Detect wrong brick family if ( isFromBrickFamily( phrase[r], (*icf) ) ) { // Check grammar using child as root checkGrammar( phrase, r, grammarErrors, nbGrammarErrors, phrase[r], false ); } else { addError( grammarErrors[r], "Error: " + (*icf) + " expected (mandatory/parameter of " + grammarBrick + ")", nbGrammarErrors ); ++r; } } // Next if ( readNext && (r < phrase.size()) ) { checkGrammar( phrase, r, grammarErrors, nbGrammarErrors, rootBrick ); } } /* * */ char getDocFileLetter( const string& sheetName ) { // skip abm_mt_, abm_ml_... char letter = 'a'; uint nbUnderscoresToSkip = 2, nbUnderscoresFound = 0; for ( uint c=0; c!=sheetName.size(); ++c ) { if ( nbUnderscoresFound == nbUnderscoresToSkip ) { letter = sheetName[c]; break; } if ( sheetName[c] == '_' ) ++nbUnderscoresFound; } return tolower( letter ); } //----------------------------------------------- // testPhraseGrammarAndProduceDoc // //----------------------------------------------- bool testPhraseGrammarAndProduceDoc( const string& sheetName, const vs& phrase ) { string filename = strlwr( sheetName ) + "." + phSheetType; string phraseStatus; bool isPhraseCorrect = true; const char *rejectedstr = "(grammatically invalid)"; // Check grammar for this phrase vs grammarErrors( phrase.size() ); uint nbGrammarErrors = 0, r = 0; checkGrammar( phrase, r, grammarErrors, nbGrammarErrors, phrase[0] ); if ( nbGrammarErrors != 0 ) { InvalidPhrases.push_back( sheetName ); isPhraseCorrect = false; phraseStatus = rejectedstr; } // Look-up phrase title string phraseTitle = PhraseTitles[sheetName]; // Output phrase description char letter = 'a'; if ( (! MultipleDocFiles) && (sheetName.size() > 3) ) { letter = tolower( sheetName[3] ); } else { letter = getDocFileLetter( sheetName ); } if ( letter < 'a' ) letter = 'a'; else if ( letter > 'z' ) letter = 'z'; FILE *htmlFile = PhraseDocFiles[letter - 'a']; sint sabrinaCost; fprintf( htmlFile, "<A NAME=\"%s\"></A><P><B>%s</B> %s %s<BR><UL>\n", sheetName.c_str(), filename.c_str(), phraseTitle.c_str(), phraseStatus.c_str() ); vector<string> minBrickSkills( phrase.size() ); vector<uint> minBrickSkillValues( phrase.size(), 0 ); string brickMinSkill, maxSkill; sint posCost = 0, negCost = 0, totalCost; uint maxSkillValue = 0, brickMinSkillValue; for ( uint i=0; i!=phrase.size(); ++i ) { printBrickInfo( htmlFile, phrase[i], grammarErrors[i], sabrinaCost, brickMinSkillValue, brickMinSkill ); if ( sabrinaCost > 0 ) posCost += sabrinaCost; else negCost += sabrinaCost; minBrickSkillValues[i] = brickMinSkillValue; minBrickSkills[i] = brickMinSkill; if ( brickMinSkillValue > maxSkillValue ) maxSkillValue = brickMinSkillValue; } for ( uint i=0; i!=phrase.size(); ++i ) { if ( minBrickSkillValues[i] == maxSkillValue ) { if ( maxSkill.find( minBrickSkills[i] ) == string::npos ) { if ( ! maxSkill.empty() ) maxSkill += "; "; maxSkill += minBrickSkills[i]; } } } if ( phrase.size() > 1 ) { string effectOrOptionBrick = phrase[1]; strupr( effectOrOptionBrick ); if ( ! PhraseNames.insert( make_pair( sheetName, BrickInfo[effectOrOptionBrick].Text ) ).second ) nlwarning( "Found duplicate phrase %s", sheetName.c_str() ); } Progression.insert( make_pair( maxSkillValue, make_pair( sheetName, maxSkill ) ) ); totalCost = posCost + negCost; PhraseSabrinaCosts.insert( make_pair(sheetName,totalCost) ); char *redbegin = "", *redend = ""; if ( totalCost > 0 ) { map<string,bool>::const_iterator itCastable = PhraseCastable.find(sheetName); if( itCastable != PhraseCastable.end() ) { if( (*itCastable).second ) { redbegin = "<FONT COLOR=\"RED\">"; redend = "</FONT>"; PhrasesWithInvalidCost.push_back( sheetName ); isPhraseCorrect = false; } } } fprintf( htmlFile, "<LI>%s<B>Total sabrina cost: </B>+%d %d = %d%s</LI>\n", redbegin, posCost, negCost, totalCost, redend ); fprintf( htmlFile, "<LI><B>Minimum skill value required: %d</B></LI>\n", maxSkillValue ); fprintf( htmlFile, "</UL></P>\n" ); if ( ! isPhraseCorrect ) { ++NbSheetsRejected; } return isPhraseCorrect; } // testPhraseGrammarAndProduceDoc // /* * */ inline bool isSeparator( char c ) { return (c == ' ') || (c == '\t'); } //----------------------------------------------- // produceDocFromExistingPhrases // // - Phrases //----------------------------------------------- void produceDocFromExistingPhrases() { vs files; CPath::getPathContent( PhrasePath, true, false, true, files ); NbSheetsRead = 0; for ( vs::const_iterator ip=files.begin(); ip!=files.end(); ++ip ) { if ( CFile::getExtension( *ip ) == phSheetType ) { // Read george sheet NLMISC::CSmartPtr<UForm> form = (UForm*)FormLoader->loadForm( (*ip).c_str() ); if ( ! form ) nlerror( "Can't load sheet %s", (*ip).c_str() ); // Get the bricks of the phrase vs phrase; for ( uint i=0; i!=100; ++i ) { string value; form->getRootNode().getValueByName( value, toString( "brick %u", i ).c_str() ); if ( !value.empty() ) { strupr( value ); phrase.push_back( CFile::getFilenameWithoutExtension( value ) ); } } Phrases.insert( make_pair(CFile::getFilenameWithoutExtension( *ip ), phrase) ); // look if phrase is castable bool castable; form->getRootNode().getValueByName( castable, "castable"); PhraseCastable.insert( make_pair(CFile::getFilenameWithoutExtension( *ip ), castable) ); // Test grammar and produce doc testPhraseGrammarAndProduceDoc( CFile::getFilenameWithoutExtension( *ip ), phrase ); ++NbSheetsRead; } } nlinfo( "Total: %u phrases", NbSheetsRead ); } // produceDocFromExistingPhrases // /* * */ string getLink( const string& phrase ) { string res; if ( MultipleDocFiles && (! phrase.empty()) ) { res += DocFileName + "_" + getDocFileLetter( phrase ) + ".html"; } else { res += DocFileName + ".html"; } res += "#" + phrase; //nlinfo( "%s", res.c_str() ); return res; } /* * */ void usage(char *argv0, FILE *out) { fprintf(out, "\n"); fprintf(out, "Syntax: %s [-p <sheet path>] <bricksFilename> [-o <phrasePath>] [-b] [-d] [-m] [-n]\n", argv0); fprintf(out, "-o: output phrase path (or input if -d is set)\n"); fprintf(out, "-b: produce doc about brick learning infos\n"); fprintf(out, "-d: browse existing phrases in <phrasePath> (and subdirs) and produce doc\n"); fprintf(out, "-m: multiple doc html files, alphabetically (use with -g,-c,-d with numerous phrases)\n"); fprintf(out, "-n: no hypertext (don't produce links phrases)\n"); fprintf(out, "\n"); } //----------------------------------------------- // makeIndexFile // //----------------------------------------------- void makeIndexFile() { FILE * indexFile = nlfopen( "_" + DocFileNameRoot + "_INDEX.html", "wt" ); if( indexFile ) { fprintf( indexFile, ("<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n<title>Summary of " + DocFileNameRoot + "</title>\n</head><body>\n").c_str() ); DocFileName = DocFileNameRoot + "_actions"; if ( MultipleDocFiles ) { // One HTML file per alphabet letter for ( uint l=0; l!=26; ++l ) { string filename = toString( "%s_%c.html", DocFileName.c_str(), 'a'+l ); PhraseDocFiles[l] = nlfopen( filename, "wt" ); fprintf( PhraseDocFiles[l], ("<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n<title>" + DocFileName + toString( " - %c", (char)('A'+l) ) + "</title>\n</head><body>\n").c_str() ); fprintf( indexFile, ("<A HREF=\"" + filename + "\">" + (char)('A'+l) + "</A> ").c_str() ); } } else { // One single HTML file fprintf( indexFile, ("<A HREF=\"" + DocFileName + ".html\">Go to action details</A>").c_str() ); PhraseDocFiles[0] = nlfopen( DocFileName + ".html", "wt" ); fprintf( PhraseDocFiles[0], ("<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n<title>" + DocFileName + "</title>\n</head><body>\n").c_str() ); for ( uint l=1; l!=26; ++l ) { PhraseDocFiles[l] = PhraseDocFiles[0]; } } fprintf( indexFile, ("<BR><A HREF=\"" + DocFileName + "__by_skill_value.html" + "\">Go to action by skill value</A>\n").c_str() ); fprintf( indexFile, ("<BR><A HREF=\"" + DocFileName + "__by_skill_value_detail.html" + "\">Go to action by skill value (detail)</A>\n").c_str() ); fprintf( indexFile, ("<BR><A HREF=\"" + DocFileName + "__by_skill.html" + "\">Go to action by skill</A><BR>\n").c_str() ); if( GenerateBrickProgression ) { fprintf( indexFile, ("<BR><BR><A HREF=\"" + DocFileNameRoot + ".html" + "\">Go to brick list</A><BR>\n").c_str() ); } produceDocFromExistingPhrases(); for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip ) { const string& phraseCode = (*ip).second.first; string link = Hypertext ? toString( "<A HREF=\"%s\">%s</A>", getLink(phraseCode).c_str(), phraseCode.c_str() ) : "<B>" + phraseCode + "</B>"; PhraseCodeToLink.insert( make_pair(phraseCode,link) ); } // Summary (errors in phrases) fprintf( indexFile, "<BR><A NAME=\"summary\"></A>\n" ); fprintf( indexFile, ("<FONT SIZE=\"20\">Summary of " + DocFileName + "</FONT><BR>\n").c_str() ); if ( NbSheetsGenTries != 0 ) fprintf( indexFile, "<P>%u valid sheets written on %u</P>\n", NbSheetsWritten, NbSheetsGenTries ); if ( NbSheetsRead != 0 ) fprintf( indexFile, "<P>%u sheets read</P>\n", NbSheetsRead ); fprintf( indexFile, "<P>%u invalid sheets rejected", NbSheetsRejected ); if ( ! PhrasesWithInvalidCost.empty() ) { fprintf( indexFile, "<P><B>Phrases with invalid sabrina cost:</B><BR>\n" ); for ( vs::const_iterator iip=PhrasesWithInvalidCost.begin(); iip!=PhrasesWithInvalidCost.end(); ++iip ) { string link = Hypertext ? toString( "<A HREF=\"%s\">%s</A>", getLink(*iip).c_str(), (*iip).c_str() ) : "<B>" + (*iip) + "</B>"; fprintf( indexFile, "%s<BR>\n", link.c_str() ); } fprintf( indexFile, "</P>\n" ); } else { fprintf( indexFile, "<P><B>All phrases have valid sabrina cost.</B></P>\n" ); } if ( ! InvalidPhrases.empty() ) { fprintf( indexFile, "<P><B>Grammatically invalid phrases:</B><BR>\n" ); for ( vs::const_iterator iip=InvalidPhrases.begin(); iip!=InvalidPhrases.end(); ++iip ) { string link = Hypertext ? toString( "<A HREF=\"%s\">%s</A>", getLink(*iip).c_str(), (*iip).c_str() ) : "<B>" + (*iip) + "</B>"; fprintf( indexFile, "%s<BR>\n", link.c_str() ); } fprintf( indexFile, "</P>\n" ); } else { fprintf( indexFile, "<P><B>All phrases are grammatically valid.</B></P>\n" ); } fprintf( indexFile, "</body></html>\n" ); fclose( indexFile ); if ( MultipleDocFiles ) { for ( uint l=0; l!=26; ++l ) { fprintf( PhraseDocFiles[l], "</body></html>\n" ); fclose( PhraseDocFiles[l] ); } } else { fprintf( PhraseDocFiles[0], "</body></html>\n" ); fclose( PhraseDocFiles[0] ); } } } // makeIndexFile // //----------------------------------------------- // makeActionsBySkillGroupFile // //----------------------------------------------- void makeActionsBySkillGroupFile() { // progression by skill FILE * actionsBySkillGroupFile = nlfopen( DocFileName + "__by_skill.html", "wt" ); if( actionsBySkillGroupFile ) { fprintf( actionsBySkillGroupFile, ("<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n<title>Progression of " + DocFileName + "</title>\n</head><body>\n").c_str() ); fprintf( actionsBySkillGroupFile, "<BR><A NAME=\"by_skill_group\"></A>\n" ); fprintf( actionsBySkillGroupFile, "<P><B>ACTIONS BY SKILL GROUP:</B><BR>\n<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n" ); map<string, multimap<uint,string> > phrasesBySkill; for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip ) { const string& phraseCode = (*ip).second.first; string skillName = (*ip).second.second.substr(0,(*ip).second.second.find(" ")); string skillValueStr = (*ip).second.second.substr((*ip).second.second.find(" ")+1,(*ip).second.second.size()-(*ip).second.second.find(" ")-1); uint skillValue = atoi(skillValueStr.c_str()); map<string, multimap<uint,string> >::iterator it = phrasesBySkill.find(skillName); if( it != phrasesBySkill.end() ) { (*it).second.insert(make_pair(skillValue,phraseCode)); } else { multimap<uint,string> m; m.insert(make_pair(skillValue,phraseCode)); phrasesBySkill.insert( make_pair(skillName,m) ); } } map<string, multimap<uint,string> >::iterator itPhrasesBySkill; for( itPhrasesBySkill = phrasesBySkill.begin(); itPhrasesBySkill != phrasesBySkill.end(); ++itPhrasesBySkill ) { CVectorSString dicoResult; Dico.lookup( (*itPhrasesBySkill).first, dicoResult, true ); if( !dicoResult.empty() ) fprintf( actionsBySkillGroupFile, "<tr><td><A HREF=\"#%s\">%s</A></td></tr>\n", (*itPhrasesBySkill).first.c_str(),dicoResult[0].c_str()); else fprintf( actionsBySkillGroupFile, "<tr><td><A HREF=\"#%s\">%s</A></td></tr>\n", (*itPhrasesBySkill).first.c_str(),(*itPhrasesBySkill).first.c_str()); } for( itPhrasesBySkill = phrasesBySkill.begin(); itPhrasesBySkill != phrasesBySkill.end(); ++itPhrasesBySkill ) { CVectorSString dicoResult; Dico.lookup( (*itPhrasesBySkill).first, dicoResult, true ); if( !dicoResult.empty() ) fprintf( actionsBySkillGroupFile, "<tr><td><A NAME=\"%s\"><B>%s</B></A><BR></td></tr>\n", (*itPhrasesBySkill).first.c_str(), dicoResult[0].c_str() ); else fprintf( actionsBySkillGroupFile, "<tr><td><A NAME=\"%s\"><B>%s</B></A><BR></td></tr>\n", (*itPhrasesBySkill).first.c_str(),(*itPhrasesBySkill).first.c_str() ); multimap<uint,string>::iterator it; for( it = (*itPhrasesBySkill).second.begin(); it != (*itPhrasesBySkill).second.end(); ++it ) { fprintf( actionsBySkillGroupFile, "<tr><td>%d</td><td>%s</td><td>%s<BR></td></tr>\n", (*it).first, PhraseCodeToLink[(*it).second].c_str(), PhraseTitles[(*it).second].c_str()); } } fprintf( actionsBySkillGroupFile, "</tbody><table></P>\n" ); fprintf( actionsBySkillGroupFile, "</body></html>\n" ); fclose( actionsBySkillGroupFile ); } } // makeActionsBySkillGroupFile // //----------------------------------------------- // makeActionsBySkillValueFile // //----------------------------------------------- void makeActionsBySkillValueFile() { FILE * actionsBySkillValueFile = fopen( (DocFileName + "__by_skill_value.html").c_str(), "wt" ); if( actionsBySkillValueFile ) { fprintf( actionsBySkillValueFile, ("<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n<title>Progression of " + DocFileName + "</title>\n</head><body>\n").c_str() ); // Progression (phrases sorted by skill value) fprintf( actionsBySkillValueFile, "<BR><A NAME=\"by_skill_value\"></A>\n" ); fprintf( actionsBySkillValueFile, "<P><B>ACTIONS BY SKILL VALUE: <A HREF=\"%s\">[detail]</A></B>\n<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n",(DocFileName + "__by_skill_value_detail.html").c_str() ); fprintf( actionsBySkillValueFile, "<tr><td><B>File</B></td><td><B>Name</B></td><td><B>Skill needed</B><BR></td></tr>\n"); map<string,string> phraseCodeToLink; for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip ) { const string& phraseCode = (*ip).second.first; fprintf( actionsBySkillValueFile, "<tr><td><font size=2>%s</font></td><td><font size=2>%s</font></td><td><B><font size=2>%s</font></B><BR></td></tr>\n", PhraseCodeToLink[phraseCode].c_str(), /*newbrickTitle.c_str(),*/ PhraseTitles[phraseCode].c_str(), (*ip).second.second.c_str() ); } fprintf( actionsBySkillValueFile, "</tbody><table></P>\n" ); fprintf( actionsBySkillValueFile, "</body></html>\n" ); fclose( actionsBySkillValueFile ); } } // makeActionsBySkillValueFile // //----------------------------------------------- // makeActionsBySkillValueDetailFile // //----------------------------------------------- void makeActionsBySkillValueDetailFile() { FILE * actionsBySkillValueDetailFile = nlfopen( DocFileName + "__by_skill_value_detail.html", "wt" ); if( actionsBySkillValueDetailFile ) { fprintf( actionsBySkillValueDetailFile, ("<html><head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n<title>Progression of " + DocFileName + "</title>\n</head><body>\n").c_str() ); // Progression summary (phrases sorted by skill value) fprintf( actionsBySkillValueDetailFile, "<BR><A NAME=\"progression\"></A>\n" ); fprintf( actionsBySkillValueDetailFile, "<P><B>ACTIONS BY SKILL VALUE:</B><BR>\n<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n" ); fprintf( actionsBySkillValueDetailFile, "<tr><td><B>File</B></td><td><B>Name</B></td><td><B>Skill needed</B><BR></td><td><B>Sabrina cost</B></td><td><B>Bricks ...</B></td></tr>\n"); set<string> effects; map<string,set<string> > effectAndModifiers; for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip ) { const string& phraseCode = (*ip).second.first; fprintf( actionsBySkillValueDetailFile, "<tr><td><font size=2>%s</font></td><td><font size=2>%s</font></td><td><B><font size=2>%s</font></B></td><td><font size=2>%d</font></td>",PhraseCodeToLink[phraseCode].c_str(), PhraseTitles[phraseCode].c_str(), (*ip).second.second.c_str(),PhraseSabrinaCosts[phraseCode]); msvs::iterator itPhrases = Phrases.find( phraseCode ); if( itPhrases != Phrases.end() ) { string effect; uint modifierCount = 0; uint creditCount = 0; for( uint i = 0; i<(*itPhrases).second.size(); ++i ) { string brick = (*itPhrases).second[i]; string color; switch ( brick[brick.size()-getBrickTypeLetterRPos(brick)] ) { case 'P': color = "Black"; break; case 'E': { color = "Brown"; effects.insert(brick); if( effectAndModifiers.find(brick) == effectAndModifiers.end() ) { set<string> s; effectAndModifiers.insert( make_pair(brick,s) ); } effect = brick; } break; case 'O': color = "Green"; break; case 'M': { color = "Blue"; effectAndModifiers[effect].insert(brick); modifierCount++; } break; case 'C': color = "Red"; creditCount++; break; default: color = "Black"; } string text = BrickInfo[brick].Text; if( text.empty() ) { text = strlwr(brick); nlwarning("%s not found in BrickInfo",brick.c_str()); } else { if(text.find("$|sap")!=-1) { text = text.substr(0,text.size()-5); string str = brick.substr(brick.size()-5,5); text += toString(atoi(str.c_str())); } } fprintf( actionsBySkillValueDetailFile, "<td><FONT COLOR=\"%s\" SIZE=2>%s</FONT></td>",color.c_str(),text.c_str()); } } else { nlerror("not found : %s",phraseCode.c_str()); } fprintf( actionsBySkillValueDetailFile, "</tr>\n"); } fprintf( actionsBySkillValueDetailFile, "</tbody><table></P>\n" ); fprintf( actionsBySkillValueDetailFile, "</body></html>\n" ); fclose( actionsBySkillValueDetailFile ); } } // makeActionsBySkillValueDetailFile // //----------------------------------------------- // validateBrick // //----------------------------------------------- bool validateBrick( const string& brk ) { if(brk[1]=='C') return true; if(brk[1]=='F') return true; if(brk[1]=='H') return true; if(brk[1]=='M') return true; if(brk[1]=='S') return true; return false; } // validateBrick // //----------------------------------------------- // makeSkillTreeFile // //----------------------------------------------- void makeSkillTreeFile( char filter, string skillFamily, bool withTraduction ) { vector<map<string,uint16> > skillsArray; skillsArray.resize(6); // 6 tranches de skill uint i; for( i = 0; i<SkillsTree.SkillsTree.size(); ++i ) { string skillCode = SkillsTree.SkillsTree[i].SkillCode; if( skillCode[1] == filter ) { uint sIdx = skillCode.length()-2; // -1 for 'S', -1 for 0 skillsArray[sIdx].insert( make_pair(skillCode,SkillsTree.SkillsTree[i].MaxSkillValue) ); } } uint16 maxLine = 0; for( i=0; i<skillsArray.size(); ++i ) { if( skillsArray[i].size() > maxLine ) { maxLine = skillsArray[i].size(); } } string filename = skillFamily + "_skill_tree.html"; string filenameWithTraduction = skillFamily + "_skill_tree_detailed.html"; FILE * skillTreeFile; if( withTraduction ) skillTreeFile = nlfopen( filenameWithTraduction, "wt" ); else skillTreeFile = nlfopen( filename, "wt" ); fprintf( skillTreeFile,"<html><head>\n"); fprintf( skillTreeFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( skillTreeFile,"<title>SKILL TREE ( %s )</title>\n",skillFamily.c_str()); fprintf( skillTreeFile,"</head><body>\n"); if( withTraduction ) fprintf( skillTreeFile,"<b>SKILL TREE ( %s )</b>\n",skillFamily.c_str()); else fprintf( skillTreeFile,"<b>SKILL TREE ( %s )</b> [<A HREF=\"%s\">display traduction</A>]<BR>\n",skillFamily.c_str(),filenameWithTraduction.c_str()); fprintf( skillTreeFile,"<table cellpadding=\"2\" cellspacing=\"2\" border=\"0\" style=\"text-align: left;\"><tbody>\n"); fprintf( skillTreeFile,"<tr><td><b>0 to 20</b></td><td><b>20 to 50</b></td><td><b>50 to 100</b></td><td><b>100 to 150</b></td><td><b>150 to 200</b></td><td><b>200 to 250</b></td></tr>\n"); uint j; // print line by line for( j=0; j<maxLine; ++j ) { fprintf( skillTreeFile,"<tr>"); // for each column for( i=0; i<skillsArray.size(); ++i ) { uint p; map<string,uint16>::iterator itSkillcode; for( itSkillcode = skillsArray[i].begin(), p=0; itSkillcode != skillsArray[i].end() && p<j; ++itSkillcode,++p ); if( itSkillcode != skillsArray[i].end() ) { if( withTraduction ) { CVectorSString dicoResult; Dico.lookup( (*itSkillcode).first, dicoResult, true ); if(dicoResult.empty()) fprintf( skillTreeFile,"<td>%s : ???</td>",(*itSkillcode).first.c_str()); else fprintf( skillTreeFile,"<td>%s</td>",dicoResult[0].c_str()); } else fprintf( skillTreeFile,"<td>%s</td>",(*itSkillcode).first.c_str()); } else fprintf( skillTreeFile,"<td></td>"); } fprintf( skillTreeFile,"</tr>\n"); } fprintf( skillTreeFile, "</tbody><table></P>\n" ); fprintf( skillTreeFile, "</body></html>\n" ); fclose( skillTreeFile ); } // makeSkillTreeFile // //----------------------------------------------- // MAIN // //----------------------------------------------- int main(int argc, char* argv[]) { // parse command line const char *inputFilename = NULL; for ( uint i=1; (sint)i!=argc; i++ ) { const char *arg = argv[i]; if ( arg[0] == '-' ) { switch ( arg[1] ) { case 'p': ++i; if ( (sint)i == argc ) { fprintf( stderr, "Missing <sheet path> after -p option\n" ); usage( argv[0], stderr ); exit( 0 ); } inputSheetPath = argv[i]; break; case 'o': ++i; if ( (sint)i == argc ) { fprintf( stderr, "Missing <phrasePath> after -o option\n" ); usage( argv[0], stderr ); exit( 0 ); } PhrasePath = argv[i]; if ( PhrasePath[PhrasePath.size()-1] != '/' ) PhrasePath += '/'; break; case 'b' : GenerateBrickProgression = true; break; case 'd': ProduceDocFromExistingPhrases = true; break; case 'm': MultipleDocFiles = true; break; case 'n': Hypertext = false; break; } } else { if ( CFile::getExtension(arg) == "csv" ) { inputFilename = arg; } else nlerror( "Unrecognized extension in %s", arg ); } } Dico.init(); loadSheetPath(); FormLoader = UFormLoader::createLoader(); CSheetId::init(); CSheetId skillTreeSheet("skills.skill_tree"); CSmartPtr<UForm> skillTreeForm = FormLoader->loadForm( "skills.skill_tree" ); SkillsTree.readGeorges( skillTreeForm, skillTreeSheet ); makeSkillTreeFile('C',"craft", false); makeSkillTreeFile('F',"fight", false); makeSkillTreeFile('H',"forage", false); makeSkillTreeFile('M',"magic", false); makeSkillTreeFile('C',"craft", true); makeSkillTreeFile('F',"fight", true); makeSkillTreeFile('H',"forage", true); makeSkillTreeFile('M',"magic", true); // Load bricks from the csv UseBricks = ProduceDocFromExistingPhrases; if ( UseBricks ) { if ( ! inputFilename ) { usage( argv[0], stderr ); exit( 0 ); } loadBricks( inputFilename ); } // Phrases if ( ProduceDocFromExistingPhrases ) { loadBrickGrammar(); loadBrickTitles(); loadPhraseTitles(); DocFileNameRoot = toString( "%s", CFile::getFilenameWithoutExtension( inputFilename ).c_str() ); // index makeIndexFile(); // progression by skill makeActionsBySkillGroupFile(); // Progression (phrases sorted by skill value) makeActionsBySkillValueFile(); // Progression (phrases sorted by skill value + detail) makeActionsBySkillValueDetailFile(); } if( GenerateBrickProgression ) { map<uint,map<string,set<string> > > levelToBrick; map<string,string> phraseToSkill; for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip ) { const string& phraseCode = (*ip).second.first; string skillTmp = (*ip).second.second.c_str(); phraseToSkill.insert( make_pair(phraseCode,skillTmp) ); if(skillTmp.empty()==false) { // get skill string skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); // get level string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } if(levelStr.find(".")!=-1) levelStr = levelStr.substr(0,levelStr.size()-1); uint level = atoi(levelStr.c_str()); map<uint,map<string,set<string> > >::iterator itLvl = levelToBrick.find(level); if( itLvl == levelToBrick.end() ) { set<string> s; map<string,set<string> > mp; mp.insert(make_pair(skill,s)); levelToBrick.insert(make_pair(level,mp)); } else { if( (*itLvl).second.find(skill) == (*itLvl).second.end() ) { set<string> s; (*itLvl).second.insert( make_pair(skill,s) ); } } msvs::iterator itPhrases = Phrases.find( phraseCode ); if( itPhrases != Phrases.end() ) { string effect; for( uint i = 0; i<(*itPhrases).second.size(); ++i ) { string brick = (*itPhrases).second[i]; if( levelToBrick[level][skill].find(brick) == levelToBrick[level][skill].end() ) { levelToBrick[level][skill].insert(brick); } } } } } // get family & color map<string,string> brickToColor; map<string,string> brickToFamily; map<string, CBrickInfo>::iterator itBInf; for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string color; string family; if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='M' ) { color = "Blue"; family = "Modifier"; } if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='C' ) { color = "Red"; family = "Credit"; } if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='O' ) { color = "Green"; family = "Option"; } if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='P' ) { color = "Black"; family = "Root"; } if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='E' ) { color = "Brown"; family = "Effect"; } brickToColor.insert(make_pair(brk,color)); brickToFamily.insert(make_pair(brk,family)); } // get phrases where the brick can be found map<string,map<string,string> > brickToPhrases; msvs::iterator itPhrases; for( itPhrases=Phrases.begin(); itPhrases!=Phrases.end(); ++itPhrases ) { for( uint i = 0; i<(*itPhrases).second.size(); ++i ) { string brick = (*itPhrases).second[i]; if( brickToPhrases.find(brick)==brickToPhrases.end() ) { map<string,string> m; m.insert(make_pair((*itPhrases).first,phraseToSkill[(*itPhrases).first])); brickToPhrases.insert(make_pair(brick,m)); } else { brickToPhrases[brick].insert(make_pair((*itPhrases).first,phraseToSkill[(*itPhrases).first])); } } } // get skill when a brick is learnt map<string,string> brickToLearnSkill; map<string,map<string,string> >::iterator itLearn; for( itLearn=brickToPhrases.begin(); itLearn!=brickToPhrases.end(); ++itLearn ) { string minSkill; uint minLevel = 250; mss::iterator itPh; for( itPh=(*itLearn).second.begin(); itPh!=(*itLearn).second.end(); ++itPh ) { string skillTmp = (*itPh).second; string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } uint level = atoi(levelStr.c_str()); if( level<minLevel || minSkill.empty() ) { minSkill = skillTmp; minLevel = level; } } brickToLearnSkill.insert(make_pair((*itLearn).first,minSkill)); } // PHRASES // write header and title bar string filename; filename = DocFileNameRoot + "_m.html"; FILE * brickPhraseDocFile_m = nlfopen( filename, "wt" ); fprintf( brickPhraseDocFile_m,"<html><head>\n"); fprintf( brickPhraseDocFile_m,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickPhraseDocFile_m,"<title>Brick phrases</title>\n"); fprintf( brickPhraseDocFile_m,"</head><body>\n"); fprintf( brickPhraseDocFile_m,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n"); filename = DocFileNameRoot + "_c.html"; FILE * brickPhraseDocFile_c = nlfopen( filename, "wt" ); fprintf( brickPhraseDocFile_c,"<html><head>\n"); fprintf( brickPhraseDocFile_c,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickPhraseDocFile_c,"<title>Brick phrases</title>\n"); fprintf( brickPhraseDocFile_c,"</head><body>\n"); fprintf( brickPhraseDocFile_c,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n"); filename = DocFileNameRoot + "_o.html"; FILE * brickPhraseDocFile_o = nlfopen( filename, "wt" ); fprintf( brickPhraseDocFile_o,"<html><head>\n"); fprintf( brickPhraseDocFile_o,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickPhraseDocFile_o,"<title>Brick phrases</title>\n"); fprintf( brickPhraseDocFile_o,"</head><body>\n"); fprintf( brickPhraseDocFile_o,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n"); filename = DocFileNameRoot + "_p.html"; FILE * brickPhraseDocFile_p = nlfopen( filename, "wt" ); fprintf( brickPhraseDocFile_p,"<html><head>\n"); fprintf( brickPhraseDocFile_p,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickPhraseDocFile_p,"<title>Brick phrases</title>\n"); fprintf( brickPhraseDocFile_p,"</head><body>\n"); fprintf( brickPhraseDocFile_p,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n"); filename = DocFileNameRoot + "_e.html"; FILE * brickPhraseDocFile_e = nlfopen( filename, "wt" ); fprintf( brickPhraseDocFile_e,"<html><head>\n"); fprintf( brickPhraseDocFile_e,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickPhraseDocFile_e,"<title>Brick phrases</title>\n"); fprintf( brickPhraseDocFile_e,"</head><body>\n"); fprintf( brickPhraseDocFile_e,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n"); for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string code = strlwr(brk.c_str()); if(brickToFamily[brk]=="Modifier") fprintf( brickPhraseDocFile_m,"<tr><td><A NAME=\"%s\"><FONT COLOR=\"Blue\">%s</FONT></A></td><td></td></tr>\n",brk.c_str(),code.c_str()); if(brickToFamily[brk]=="Credit") fprintf( brickPhraseDocFile_c,"<tr><td><A NAME=\"%s\"><FONT COLOR=\"Red\">%s</FONT></A></td><td></td></tr>\n",brk.c_str(),code.c_str()); if(brickToFamily[brk]=="Option") fprintf( brickPhraseDocFile_o,"<tr><td><A NAME=\"%s\"><FONT COLOR=\"Green\">%s</FONT></A></td><td></td></tr>\n",brk.c_str(),code.c_str()); if(brickToFamily[brk]=="Effect") fprintf( brickPhraseDocFile_e,"<tr><td><A NAME=\"%s\"><FONT COLOR=\"Brown\">%s</FONT></A></td><td></td></tr>\n",brk.c_str(),code.c_str()); if(brickToFamily[brk]=="Root") fprintf( brickPhraseDocFile_p,"<tr><td><A NAME=\"%s\"><FONT COLOR=\"Black\">%s</FONT></A></td><td></td></tr>\n",brk.c_str(),code.c_str()); map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk); if( itPhrases != brickToPhrases.end() ) { map<string,string>::iterator itPh; for( itPh=(*itPhrases).second.begin(); itPh!=(*itPhrases).second.end(); ++itPh ) { if(brickToFamily[brk]=="Modifier") fprintf( brickPhraseDocFile_m,"<tr><td></td><td><A HREF=\"%s_%c.html#%s\">%s</A></td></tr>\n",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); if(brickToFamily[brk]=="Credit") fprintf( brickPhraseDocFile_c,"<tr><td></td><td><A HREF=\"%s_%c.html#%s\">%s</A></td></tr>\n",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); if(brickToFamily[brk]=="Option") fprintf( brickPhraseDocFile_o,"<tr><td></td><td><A HREF=\"%s_%c.html#%s\">%s</A></td></tr>\n",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); if(brickToFamily[brk]=="Effect") fprintf( brickPhraseDocFile_e,"<tr><td></td><td><A HREF=\"%s_%c.html#%s\">%s</A></td></tr>\n",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); if(brickToFamily[brk]=="Root") fprintf( brickPhraseDocFile_p,"<tr><td></td><td><A HREF=\"%s_%c.html#%s\">%s</A></td></tr>\n",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); } } } fprintf( brickPhraseDocFile_m, "</tbody><table></P>\n" ); fprintf( brickPhraseDocFile_m, "</body></html>\n" ); fclose( brickPhraseDocFile_m ); fprintf( brickPhraseDocFile_c, "</tbody><table></P>\n" ); fprintf( brickPhraseDocFile_c, "</body></html>\n" ); fclose( brickPhraseDocFile_c ); fprintf( brickPhraseDocFile_o, "</tbody><table></P>\n" ); fprintf( brickPhraseDocFile_o, "</body></html>\n" ); fclose( brickPhraseDocFile_o ); fprintf( brickPhraseDocFile_e, "</tbody><table></P>\n" ); fprintf( brickPhraseDocFile_e, "</body></html>\n" ); fclose( brickPhraseDocFile_e ); fprintf( brickPhraseDocFile_p, "</tbody><table></P>\n" ); fprintf( brickPhraseDocFile_p, "</body></html>\n" ); fclose( brickPhraseDocFile_p ); // CODE // write header and title bar filename = DocFileNameRoot + ".html"; FILE * brickDocFile = nlfopen( filename, "wt" ); fprintf( brickDocFile,"<html><head>\n"); fprintf( brickDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickDocFile,"<title>Bricks infos</title>\n"); fprintf( brickDocFile,"</head><body>\n"); fprintf( brickDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n"); fprintf( brickDocFile,"<tr>\n"); fprintf( brickDocFile,"<td><b>*Code*</b></td>\n"); fprintf( brickDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickDocFile,"<td><b>Required Skill Name</b></td>\n"); fprintf( brickDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickDocFile,"<td><b>Learn Skill Name</b></td>\n"); fprintf( brickDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickDocFile,"<td><b>Found In Phrases</b></td>\n"); fprintf( brickDocFile,"</tr>\n"); // write infos for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string skillTmp = (*itBInf).second.LearnSkills; string skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); CVectorSString dicoResult; Dico.lookup( skill, dicoResult, true ); if(dicoResult.empty()) continue; // color string color = brickToColor[brk]; // code string code = strlwr(brk.c_str()); fprintf( brickDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str()); // name string name = (*itBInf).second.Text; fprintf( brickDocFile, "<td>%s</td>\n",name.c_str()); // family string family = brickToFamily[brk]; fprintf( brickDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str()); // required skill name fprintf( brickDocFile, "<td>%s</td>\n",dicoResult[0].c_str()); // required skill value string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickDocFile, "<td>%s</td>\n",levelStr.c_str()); // learn skill name string learnSkillTmp = brickToLearnSkill[brk]; skill = learnSkillTmp.substr(0,learnSkillTmp.find_first_of(" ")); fprintf( brickDocFile, "<td>%s</td>\n",skill.c_str()); // learn skill value if( learnSkillTmp.find(";") != -1 ) { sint idx = learnSkillTmp.find_first_of(" "); levelStr = learnSkillTmp.substr(idx+1,learnSkillTmp.find_first_of(";")-idx-1); } else { sint idx = learnSkillTmp.find_first_of(" "); levelStr = learnSkillTmp.substr(idx+1,learnSkillTmp.size()-idx); } fprintf( brickDocFile, "<td>%s</td>\n",levelStr.c_str()); // phrase list fprintf( brickDocFile, "<td>"); map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk); if( itPhrases != brickToPhrases.end() ) { map<string,string>::iterator itPh; uint i; for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i ) { if( MultipleDocFiles ) fprintf( brickDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); else fprintf( brickDocFile,"<A HREF=\"%s.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str()); } if( i==2 ) { char type = family[0]; fprintf( brickDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str()); } } fprintf( brickDocFile, "</td></tr>\n"); } fprintf( brickDocFile, "</tbody><table></P>\n" ); fprintf( brickDocFile, "</body></html>\n" ); fclose( brickDocFile ); // NAME // write header and title bar filename = DocFileNameRoot + "_name.html"; FILE * brickNameDocFile = nlfopen( filename, "wt" ); fprintf( brickNameDocFile,"<html><head>\n"); fprintf( brickNameDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickNameDocFile,"<title>Bricks infos</title>\n"); fprintf( brickNameDocFile,"</head><body>\n"); fprintf( brickNameDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n"); fprintf( brickNameDocFile,"<tr>\n"); fprintf( brickNameDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickNameDocFile,"<td><b>*Name*</b></td>\n"); fprintf( brickNameDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickNameDocFile,"<td><b>Required Skill Name</b></td>\n"); fprintf( brickNameDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickNameDocFile,"<td><b>Learn Skill Name</b></td>\n"); fprintf( brickNameDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickNameDocFile,"<td><b>Found In Phrases</b></td>\n"); fprintf( brickNameDocFile,"</tr>\n"); map<string,string> nameToCode; for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; // code string code = strlwr(brk.c_str()); // name string name = (*itBInf).second.Text; if( !name.empty()) nameToCode.insert( make_pair(name,brk) ); } mss::iterator itNTC; for( itNTC=nameToCode.begin(); itNTC!=nameToCode.end(); ++itNTC ) { itBInf=BrickInfo.find((*itNTC).second); string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string skillTmp = (*itBInf).second.LearnSkills; string skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); CVectorSString dicoResult; Dico.lookup( skill, dicoResult, true ); if(dicoResult.empty()) continue; // color string color = brickToColor[brk]; // code string code = strlwr(brk.c_str()); fprintf( brickNameDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str()); // name string name = (*itBInf).second.Text; fprintf( brickNameDocFile, "<td>%s</td>\n",name.c_str()); // family string family = brickToFamily[brk]; fprintf( brickNameDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str()); // required skill name fprintf( brickNameDocFile, "<td>%s</td>\n",dicoResult[0].c_str()); // required skill value string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickNameDocFile, "<td>%s</td>\n",levelStr.c_str()); // learn skill name skillTmp = brickToLearnSkill[brk]; skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); fprintf( brickNameDocFile, "<td>%s</td>\n",skill.c_str()); // learn skill value if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickNameDocFile, "<td>%s</td>\n",levelStr.c_str()); // phrase list fprintf( brickNameDocFile, "<td>"); map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk); if( itPhrases != brickToPhrases.end() ) { map<string,string>::iterator itPh; uint i; for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i ) { if( MultipleDocFiles ) fprintf( brickNameDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); else fprintf( brickNameDocFile,"<A HREF=\"%s.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str()); } if( i==2 ) { char type = family[0]; fprintf( brickNameDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str()); } } fprintf( brickNameDocFile, "</td></tr>\n"); } fprintf( brickNameDocFile, "</tbody><table></P>\n" ); fprintf( brickNameDocFile, "</body></html>\n" ); fclose( brickNameDocFile ); // FAMILY // write header and title bar filename = DocFileNameRoot + "_family.html"; FILE * brickFamilyDocFile = nlfopen( filename, "wt" ); fprintf( brickFamilyDocFile,"<html><head>\n"); fprintf( brickFamilyDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickFamilyDocFile,"<title>Bricks infos</title>\n"); fprintf( brickFamilyDocFile,"</head><body>\n"); fprintf( brickFamilyDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n"); fprintf( brickFamilyDocFile,"<tr>\n"); fprintf( brickFamilyDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickFamilyDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickFamilyDocFile,"<td><b>*Family*</b></td>\n"); fprintf( brickFamilyDocFile,"<td><b>Required Skill Name</b></td>\n"); fprintf( brickFamilyDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickFamilyDocFile,"<td><b>Learn Skill Name</b></td>\n"); fprintf( brickFamilyDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickFamilyDocFile,"<td><b>Found In Phrases</b></td>\n"); fprintf( brickFamilyDocFile,"</tr>\n"); // write infos multimap<string,string> familyToCode; for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; // family string family = brickToFamily[brk]; familyToCode.insert( make_pair(family,brk) ); } multimap<string,string>::iterator itFTC; for( itFTC=familyToCode.begin(); itFTC!=familyToCode.end(); ++itFTC ) { itBInf=BrickInfo.find((*itFTC).second); string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string skillTmp = (*itBInf).second.LearnSkills; string skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); CVectorSString dicoResult; Dico.lookup( skill, dicoResult, true ); if(dicoResult.empty()) continue; // color string color = brickToColor[brk]; // code string code = strlwr(brk.c_str()); fprintf( brickFamilyDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str()); // name string name = (*itBInf).second.Text; fprintf( brickFamilyDocFile, "<td>%s</td>\n",name.c_str()); // family string family = brickToFamily[brk]; fprintf( brickFamilyDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str()); // required skill name fprintf( brickFamilyDocFile, "<td>%s</td>\n",dicoResult[0].c_str()); // required skill value string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickFamilyDocFile, "<td>%s</td>\n",levelStr.c_str()); // learn skill name skillTmp = brickToLearnSkill[brk]; skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); fprintf( brickFamilyDocFile, "<td>%s</td>\n",skill.c_str()); // learn skill value if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickFamilyDocFile, "<td>%s</td>\n",levelStr.c_str()); // phrase list fprintf( brickFamilyDocFile, "<td>"); map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk); if( itPhrases != brickToPhrases.end() ) { map<string,string>::iterator itPh; uint i; for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i ) { if( MultipleDocFiles ) fprintf( brickFamilyDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); else fprintf( brickFamilyDocFile,"<A HREF=\"%s.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str()); } if( i==2 ) { char type = family[0]; fprintf( brickFamilyDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str()); } } fprintf( brickFamilyDocFile, "</td></tr>\n"); } fprintf( brickFamilyDocFile, "</tbody><table></P>\n" ); fprintf( brickFamilyDocFile, "</body></html>\n" ); fclose( brickFamilyDocFile ); // REQUIRED SKILL VALUE // write header and title bar filename = DocFileNameRoot + "_required_skill_value.html"; FILE * brickRequiredDocFile = nlfopen( filename, "wt" ); fprintf( brickRequiredDocFile,"<html><head>\n"); fprintf( brickRequiredDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickRequiredDocFile,"<title>Bricks infos</title>\n"); fprintf( brickRequiredDocFile,"</head><body>\n"); fprintf( brickRequiredDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n"); fprintf( brickRequiredDocFile,"<tr>\n"); fprintf( brickRequiredDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickRequiredDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickRequiredDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickRequiredDocFile,"<td><b>Required Skill Name</b></td>\n"); fprintf( brickRequiredDocFile,"<td><b>*Required Skill Value*</b></td>\n"); fprintf( brickRequiredDocFile,"<td><b>Learn Skill Name</b></td>\n"); fprintf( brickRequiredDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickRequiredDocFile,"<td><b>Found In Phrases</b></td>\n"); fprintf( brickRequiredDocFile,"</tr>\n"); // write infos multimap<uint,string> requiredSkillValueToCode; for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; // required skill value string skillTmp = (*itBInf).second.LearnSkills; string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } uint level = atoi(levelStr.c_str()); requiredSkillValueToCode.insert( make_pair(level,brk) ); } multimap<uint,string>::iterator itRTC; for( itRTC=requiredSkillValueToCode.begin(); itRTC!=requiredSkillValueToCode.end(); ++itRTC ) { itBInf=BrickInfo.find((*itRTC).second); string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string skillTmp = (*itBInf).second.LearnSkills; string skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); CVectorSString dicoResult; Dico.lookup( skill, dicoResult, true ); if(dicoResult.empty()) continue; // color string color = brickToColor[brk]; // code string code = strlwr(brk.c_str()); fprintf( brickRequiredDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str()); // name string name = (*itBInf).second.Text; fprintf( brickRequiredDocFile, "<td>%s</td>\n",name.c_str()); // family string family = brickToFamily[brk]; fprintf( brickRequiredDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str()); // required skill name fprintf( brickRequiredDocFile, "<td>%s</td>\n",dicoResult[0].c_str()); // required skill value string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickRequiredDocFile, "<td>%s</td>\n",levelStr.c_str()); // learn skill name skillTmp = brickToLearnSkill[brk]; skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); fprintf( brickRequiredDocFile, "<td>%s</td>\n",skill.c_str()); // learn skill value if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickRequiredDocFile, "<td>%s</td>\n",levelStr.c_str()); // phrase list fprintf( brickRequiredDocFile, "<td>"); map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk); if( itPhrases != brickToPhrases.end() ) { map<string,string>::iterator itPh; uint i; for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i ) { if( MultipleDocFiles ) fprintf( brickRequiredDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); else fprintf( brickRequiredDocFile,"<A HREF=\"%s.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str()); } if( i==2 ) { char type = family[0]; fprintf( brickRequiredDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str()); } } fprintf( brickRequiredDocFile, "</td></tr>\n"); } fprintf( brickRequiredDocFile, "</tbody><table></P>\n" ); fprintf( brickRequiredDocFile, "</body></html>\n" ); fclose( brickRequiredDocFile ); // LEARN SKILL VALUE // write header and title bar filename = DocFileNameRoot + "_learn_skill_value.html"; FILE * brickLearnDocFile = nlfopen( filename, "wt" ); fprintf( brickLearnDocFile,"<html><head>\n"); fprintf( brickLearnDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n"); fprintf( brickLearnDocFile,"<title>Bricks infos</title>\n"); fprintf( brickLearnDocFile,"</head><body>\n"); fprintf( brickLearnDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n"); fprintf( brickLearnDocFile,"<tr>\n"); fprintf( brickLearnDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickLearnDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickLearnDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickLearnDocFile,"<td><b>Required Skill Name</b></td>\n"); fprintf( brickLearnDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str()); fprintf( brickLearnDocFile,"<td><b>Learn Skill Name</b></td>\n"); fprintf( brickLearnDocFile,"<td><b>*Learn Skill Value*</b></td>\n"); fprintf( brickLearnDocFile,"<td><b>Found In Phrases</b></td>\n"); fprintf( brickLearnDocFile,"</tr>\n"); // write infos multimap<uint,string> learnSkillValueToCode; for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf ) { string brk = (*itBInf).first; if(!validateBrick(brk)) continue; // learn skill value string skillTmp = brickToLearnSkill[brk]; string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } uint level = atoi(levelStr.c_str()); learnSkillValueToCode.insert( make_pair(level,brk) ); } multimap<uint,string>::iterator itLTC; for( itLTC=learnSkillValueToCode.begin(); itLTC!=learnSkillValueToCode.end(); ++itLTC ) { itBInf=BrickInfo.find((*itLTC).second); string brk = (*itBInf).first; if(!validateBrick(brk)) continue; string skillTmp = (*itBInf).second.LearnSkills; string skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); CVectorSString dicoResult; Dico.lookup( skill, dicoResult, true ); if(dicoResult.empty()) continue; // color string color = brickToColor[brk]; // code string code = strlwr(brk.c_str()); fprintf( brickLearnDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str()); // name string name = (*itBInf).second.Text; fprintf( brickLearnDocFile, "<td>%s</td>\n",name.c_str()); // family string family = brickToFamily[brk]; fprintf( brickLearnDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str()); // required skill name fprintf( brickLearnDocFile, "<td>%s</td>\n",dicoResult[0].c_str()); // required skill value string levelStr; if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickLearnDocFile, "<td>%s</td>\n",levelStr.c_str()); // learn skill name skillTmp = brickToLearnSkill[brk]; skill = skillTmp.substr(0,skillTmp.find_first_of(" ")); fprintf( brickLearnDocFile, "<td>%s</td>\n",skill.c_str()); // learn skill value if( skillTmp.find(";") != -1 ) { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1); } else { sint idx = skillTmp.find_first_of(" "); levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx); } fprintf( brickLearnDocFile, "<td>%s</td>\n",levelStr.c_str()); // phrase list fprintf( brickLearnDocFile, "<td>"); map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk); if( itPhrases != brickToPhrases.end() ) { map<string,string>::iterator itPh; uint i; for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i ) { if( MultipleDocFiles ) fprintf( brickLearnDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str()); else fprintf( brickLearnDocFile,"<A HREF=\"%s.html#%s\">%s</A>,  ",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str()); } if( i==2 ) { char type = family[0]; fprintf( brickLearnDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str()); } } fprintf( brickLearnDocFile, "</td></tr>\n"); } fprintf( brickLearnDocFile, "</tbody><table></P>\n" ); fprintf( brickLearnDocFile, "</body></html>\n" ); fclose( brickLearnDocFile ); } return 0; } // main //