Merge branch 'main/rendor-staging' into main/atys-live
[ryzomcore.git] / ryzom / tools / phrase_generator / phrase_generator.cpp
blobde02680ca954e4b7a518100b624a9fbe508bdd3c
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // phrase_generator.cpp : Defines the entry point for the console application.
21 //-b -p r:\code\ryzom\data_leveldesign -o r:/code/ryzom/data_leveldesign/leveldesign/game_element/sphrase/magic/ magic_bricks.csv -d -m
22 // -p r:\code\ryzom\data_leveldesign -o r:/code/ryzom/data_leveldesign/leveldesign/game_element/sphrase/magic/ magic_bricks.csv -d -m
24 #include "stdafx.h"
30 // Misc
31 #include <nel/misc/types_nl.h>
32 #include "nel/misc/path.h"
33 #include "nel/misc/file.h"
34 #include "nel/misc/smart_ptr.h"
35 #include "nel/misc/command.h"
36 #include "nel/misc/common.h"
37 #include "nel/misc/path.h"
38 #include <nel/misc/sstring.h>
39 #include <nel/misc/diff_tool.h>
40 #include "nel/misc/algo.h"
41 #include "nel/misc/words_dictionary.h"
42 // Georges
43 #include "nel/georges/u_form.h"
44 #include "nel/georges/u_form_elm.h"
45 #include "nel/georges/u_form_dfn.h"
46 #include "nel/georges/u_form_loader.h"
47 #include "nel/georges/u_type.h"
48 // Georges, bypassing interface
49 #include "georges/stdgeorges.h"
50 #include "georges/form.h"
51 // Game share
52 //#include "game_share/xml.h"
53 // Unicode language file
54 // C
55 #include <time.h>
56 #include <stdio.h>
57 #include <conio.h>
58 #include <fstream>
59 // stl
60 #include <map>
62 #include "skill_tree.h"
64 using namespace NLMISC;
65 using namespace NLGEORGES;
66 using namespace std;
69 typedef vector<string> vs;
70 typedef map< string, string > mss;
71 typedef map< string, vs > msvs;
73 bool GenerateBrickProgression = false;
74 bool ProduceDocFromExistingPhrases = false;
75 bool MultipleDocFiles = false;
76 bool Hypertext = true;
77 string PhrasePath = "r:/code/ryzom/data_leveldesign/leveldesign/game_element/sphrase/";
78 uint NbSheetsGenTries = 0;
79 uint NbSheetsWritten = 0;
80 uint NbSheetsRead = 0;
81 uint NbSheetsRejected = 0;
84 bool UseBricks;
86 const string brSheetType = "sbrick";
87 const string phSheetType = "sphrase";
88 const string PHRASE_MAGIC_PREFIX = "abm_"; // action bricks magic (bm for brick filter)
90 struct CBrickInfo
92 CBrickInfo( const string& ls="", const string& t="",
93 const vs& props=vs() ) :
94 LearnSkills(ls), Text(t), Props(props) {}
96 string LearnSkills;
97 string Text; // UTF-8
98 vs Props;
102 vs OptionBricks, CounterpartBricks, AllBricks, PhrasesWithInvalidCost, InvalidPhrases;
103 set<string> UsedCounterpartBricks, UsedCounterpartBrickFamiliesInPhrase;
104 map<string, sint> SabrinaCosts;
105 map<string, sint> PhraseSabrinaCosts;
106 map<string, bool> PhraseCastable;
107 map<string, CBrickInfo> BrickInfo;
108 mss TextToBrick;
109 multimap< uint, pair<string, string> > Progression; // phrase code, min. skill
110 mss PhraseNames, PhraseTitles;
111 vector<vs> ValidPhrases;
112 set<string> UsedBricks, GeneratedPhrases;
113 map<string, vs> GrammarMandatParamBrickFamilies, GrammarOptionCreditBrickFamilies;
114 UFormLoader *FormLoader;
115 vector<FILE*> PhraseDocFiles( 26 );
116 string DocFileName,DocFileNameRoot;
117 msvs Phrases;
118 map<string,uint> SkillNameToMaxSkill;
119 map<string,string> PhraseCodeToLink;
120 CWordsDictionary Dico;
121 CStaticSkillsTree SkillsTree;
127 string inputSheetPath;
128 bool inputSheetPathLoaded = false;
129 map<string, string> inputSheetPathContent; // short filename without ext, full filename with path
132 //-----------------------------------------------
133 // getBrickTypeLetterRPos
135 //-----------------------------------------------
136 uint getBrickTypeLetterRPos( string& brick )
139 uint i =0;
140 while( i<brick.size() && !isdigit(brick[i]) )
141 i++;
143 nlassert(i<brick.size());
145 return (brick.size() - i + 2);
148 uint i =brick.size()-1;
149 while( i>=0 && (isdigit(brick[i]) || brick[i]=='_') )
150 i--;
152 return (brick.size() - i + 1);
154 } // getBrickTypeLetterRPos //
159 //-----------------------------------------------
160 // loadSheetPath
162 // from georges2csv
163 //-----------------------------------------------
164 void loadSheetPath()
166 if (inputSheetPathLoaded)
167 return;
169 NLMISC::createDebug();
170 NLMISC::WarningLog->addNegativeFilter( "CPath::insertFileInMap" );
172 CPath::addSearchPath(inputSheetPath, true, false); // for Georges to work properly
174 vector<string> files;
175 CPath::getPathContent (inputSheetPath, true, false, true, files);
177 uint i;
178 for (i=0; i<files.size(); ++i)
180 string filename = files[i];
181 string filebase = CFile::getFilenameWithoutExtension(filename);
182 if( CFile::getExtension(filename)!="saibrick" && CFile::getExtension(filename)!="saiphrase" )
184 inputSheetPathContent[filebase] = filename;
188 inputSheetPathLoaded = true;
190 } // loadSheetPath //
196 void displayList( const string& title, const vector<string>& v, CLog *log=DebugLog )
198 if ( ! title.empty() )
199 log->displayRaw( "%s: ", title.c_str() );
200 vector<string>::const_iterator ist;
201 for ( ist=v.begin(); ist!=v.end(); ++ist )
202 log->displayRaw( "%s ", (*ist).c_str() );
203 log->displayRawNL( "" );
210 class CStrIComparator : public binary_function<string, string, bool>
212 public:
213 bool operator() ( const string& s1, const string& s2 ) const
215 return (nlstricmp( s1, s2 ) == 0);
223 uint getIndexFromString( const string& s, const vector<string>& v, bool displayWarning=true )
225 if ( v.empty() )
227 nlwarning( "Can't find '%s' in empty array", s.c_str() );
228 return ~0;
230 else
232 vector<string>::const_iterator ist = find_if( v.begin(), v.end(), bind2nd(CStrIComparator(), s) );
233 if ( ist == v.end() )
235 if ( displayWarning )
237 nlwarning( "Can't find '%s' in:", s.c_str() );
238 displayList( "", v, WarningLog );
240 return ~0;
242 else
243 return ist - v.begin();
248 //-----------------------------------------------
249 // Erase every carriage returns of the string
251 //-----------------------------------------------
252 void eraseCarriageReturns( string& s )
254 const char CR = '\n';
255 string::size_type p = s.find( CR );
256 while ( (p=s.find( CR )) != string::npos )
257 s.erase( p, 1 );
258 } //
262 // First param: vector of indices of columns matching wantedColumnNames
263 // Second param: vector of fields matching wantedColumnNames
264 typedef void (*TDeliveryCallback) ( mss& );
267 //-----------------------------------------------
268 // loadCSVFile
270 //-----------------------------------------------
271 void loadCSVFile( const char *filename, TDeliveryCallback deliveryCallback )
273 char lineBuffer[2048];
274 FILE *file;
275 const char *SEPARATOR = ";";
276 vector<string> args;
277 vector<string>::iterator iarg;
279 if ( (file = nlfopen( filename, "r" )) == NULL )
281 nlwarning( "Can't find file %s", filename );
283 else
285 // Read first line as header with column names
286 lineBuffer[0] = '\0';
287 fgets( lineBuffer, 2048, file );
288 explode( lineBuffer, SEPARATOR, args );
290 // Store column names (and get rid of carriage returns!)
291 vector < string > columnNames;
292 mss valuesByName;
293 for ( iarg=args.begin(); iarg!=args.end(); ++iarg )
295 eraseCarriageReturns( *iarg );
296 columnNames.push_back( *iarg );
297 valuesByName.insert( make_pair( *iarg, string("") ) );
300 // for each line, deliver the value of the fields
301 while ( ! feof(file) )
303 // Get from file
304 lineBuffer[0] = '\0';
305 fgets( lineBuffer, 2048, file );
306 explode( lineBuffer, SEPARATOR, args );
308 // Set values (and get rid of carriage returns!)
309 for ( iarg=args.begin(); iarg!=args.end(); ++iarg )
311 eraseCarriageReturns( *iarg );
312 valuesByName[columnNames[iarg-args.begin()]] = *iarg;
315 // Deliver the wanted fields
316 deliveryCallback( valuesByName );
320 } // loadCSVFile //
323 //set<string> Skills;
326 //-----------------------------------------------
327 // brickDeliveryCallback
329 // Fetch brick code and sabrina cost
330 // - AllBricks
331 // - BrickInfo
332 // - OptionBricks
333 // - CounterpartBricks
334 // - SabrinaCosts
335 //-----------------------------------------------
336 void brickDeliveryCallback( mss& values )
338 string s = values["Brick_id"];
339 if ( s.empty() )
341 s = values["FILE"];
342 if ( s.empty() )
343 s = values["fileName"];
346 string brick = CFile::getFilenameWithoutExtension( s );
347 strupr( brick );
348 if ( brick.empty() )
350 nlwarning("<brickDeliveryCallback> can't get root filename of %s",s.c_str());
351 return;
354 string sc = values["Basics.SabrinaCost"];
355 string ls = values["Basics.LearnRequiresOneOfSkills"];
356 string txt = values["name"]; // TODO: only for combat
357 string fmn = values["familyName"];
358 string propIdent = "Basics.Property";
360 if ( UseBricks )
362 AllBricks.push_back( brick );
363 string name = (txt.empty()) ? fmn : txt;
364 vs props;
366 // Find all Basics.Property N (assumes they are subsequent)
367 mss::const_iterator imv = values.find( propIdent + " 0" );
368 for ( ; imv!=values.end(); ++imv )
370 const string& colName = (*imv).first;
371 const string& v = (*imv).second;
372 if ( colName.find( propIdent ) != string::npos )
374 if ( v != "NULL" && !v.empty() )
375 props.push_back( v );
377 else
378 break;
380 BrickInfo.insert( make_pair( brick, CBrickInfo( ls, name, props ) ) );
383 // Store brick in right container
384 string::size_type p = brick.size() - getBrickTypeLetterRPos(brick);
385 if ( ((sint)p) >= 0 )
387 switch ( brick[p] )
389 case 'O': OptionBricks.push_back( brick );
390 break;
391 case 'C': CounterpartBricks.push_back( brick );
392 break;
395 else
397 nlwarning( "Invalid brick code: %s", brick.c_str() );
398 return;
401 // Store cost
402 sint sabrinaCost;
403 if ( sc.empty() )
405 nldebug( "No sabrina cost for %s, assuming cost 0", brick.c_str() );
406 sabrinaCost = 0;
408 else
410 sabrinaCost = atoi( sc.c_str() );
412 SabrinaCosts.insert( make_pair( brick, sabrinaCost ) );
414 /* // Quick hack to generate skill codes
415 string skill = brick.substr( 1, p-1 );
416 if ( ! skill.empty() )
417 Skills.insert( skill );*/
419 } // brickDeliveryCallback //
423 //-----------------------------------------------
424 // loadBricks
426 //-----------------------------------------------
427 void loadBricks( const char* filename )
429 loadCSVFile( filename, brickDeliveryCallback );
430 if ( ProduceDocFromExistingPhrases )
431 nlinfo( "Loaded %u option bricks, %u counterpart bricks, %u sabrina costs", OptionBricks.size(), CounterpartBricks.size(), SabrinaCosts.size() );
432 else if ( UseBricks )
433 nlinfo( "Loaded %u bricks", AllBricks.size() );
435 /*set<string>::const_iterator iss;
436 for ( iss=Skills.begin(); iss!=Skills.end(); ++iss )
438 const string& skill = (*iss);
439 InfoLog->displayRawNL( " <DEFINITION Label=\"S%s\" Value=\"S%s\"/>", skill.c_str(), skill.c_str() );
442 } // loadBricks //
448 string getRootBrickForOptionOrCredit( const string& ob )
450 // Extract brick code radix
451 string::size_type p = ob.size() - getBrickTypeLetterRPos(const_cast<string&>(ob));
452 if ( (ob.size() <= getBrickTypeLetterRPos(const_cast<string&>(ob))) ||
453 ((ob[p] != 'O') && (ob[p] != 'C')) )
454 nlerror( "%s is not an option or credit brick", ob.c_str() );
455 string radix = ob.substr( 0, p );
457 // Append root brick suffix
458 return radix + "PA01";
465 string getBrickFamily( const string& b )
467 if ( b.size() >= getBrickTypeLetterRPos(const_cast<string&>(b))+2 )
469 string::size_type p = b.size() - getBrickTypeLetterRPos(const_cast<string&>(b));
470 return b.substr( 0, p+2 );
472 return string();
479 bool isFromBrickFamily( const string& brick, const string& fam )
481 return nlstricmp( brick.substr( 0, fam.size() ), fam ) == 0;
488 string getFirstBrickOfFamily( const string& family )
490 vs::const_iterator ib;
491 for ( ib=AllBricks.begin(); ib!=AllBricks.end(); ++ib )
493 const string& brick = *ib;
494 if ( isFromBrickFamily( brick, family ) )
495 return brick;
497 return string();
504 vs getAllBricksOfFamily( const string& family )
506 vs res;
507 vs::const_iterator ib;
508 for ( ib=AllBricks.begin(); ib!=AllBricks.end(); ++ib )
510 const string& brick = *ib;
511 if ( isFromBrickFamily( brick, family ) )
512 res.push_back( brick );
514 return res;
521 uint getCompatibleCounterpartBrickForCost( uint phraseCost, vs& phrase )
523 //nlinfo( "Searching credit for cost %u", phraseCost );
525 // Get the lowest matching counterpart brick
526 uint minHigherCounterpartValue = ~0, maxLowerCounterpartValue = 0, counterpartValue;
527 vs::const_iterator icb, iPerfectMatch = CounterpartBricks.end(), iMinCb = CounterpartBricks.end(), iMaxCb = CounterpartBricks.end();
528 for ( icb=CounterpartBricks.begin(); icb!=CounterpartBricks.end(); ++icb)
530 const string& cb = *icb;
532 // Skip if family already used in current phrase
533 if ( UsedCounterpartBrickFamiliesInPhrase.find( getBrickFamily( cb ) ) != UsedCounterpartBrickFamiliesInPhrase.end() )
534 continue;
536 counterpartValue = abs( SabrinaCosts[cb] );
537 //nldebug( "Trying with credit %u", counterpartValue );
538 if ( counterpartValue == phraseCost )
540 // Perfect match, check if not already taken
541 if ( UsedCounterpartBricks.insert( cb ).second )
543 UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( cb ) );
544 phrase.push_back( cb );
545 return counterpartValue;
547 else
549 // If already taken, we will come back to it later
550 iPerfectMatch = icb;
553 else if ( counterpartValue > phraseCost )
555 // Higher => get the minimum
556 if ( counterpartValue < minHigherCounterpartValue )
558 minHigherCounterpartValue = counterpartValue;
559 iMinCb = icb;
562 else // counterpartValue < phraseCost : store the max
564 if ( counterpartValue >= maxLowerCounterpartValue )
566 maxLowerCounterpartValue = counterpartValue;
567 iMaxCb = icb;
571 if ( iPerfectMatch != CounterpartBricks.end() )
573 // We skipped a perfect match in order to try to get a new value. But none found. Now get back to the last value.
574 phrase.push_back( *iPerfectMatch );
575 UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( *iPerfectMatch ) );
576 return abs( SabrinaCosts[*iPerfectMatch] );
578 else if ( iMinCb == CounterpartBricks.end() )
580 if ( iMaxCb == CounterpartBricks.end() )
582 nlerror( "No matching counterpart" );
583 return ~0;
585 else
587 // No phrase possible with only one (more) counterpart, try with the max and more (recurse)
588 UsedCounterpartBricks.insert( *iMaxCb );
589 UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( *iMaxCb ) );
590 phrase.push_back( *iMaxCb );
591 return maxLowerCounterpartValue + getCompatibleCounterpartBrickForCost( phraseCost - maxLowerCounterpartValue, phrase );
594 else
596 // Phrase possible with one (more) counterpart
597 UsedCounterpartBricks.insert( *iMinCb );
598 UsedCounterpartBrickFamiliesInPhrase.insert( getBrickFamily( *iMinCb ) );
599 phrase.push_back( *iMinCb );
600 return minHigherCounterpartValue;
608 void getCompatibleCounterpartBricks( vs& phrase )
610 // Calculate the cost of the phrase
611 sint phraseCost = 0;
612 string phraseStr;
613 vs::const_iterator ip;
614 for ( ip=phrase.begin(); ip!=phrase.end(); ++ip )
616 const string& brick = *ip;
617 sint sabrinaCost;
618 map<string, sint>::const_iterator isc = SabrinaCosts.find( brick );
619 if ( isc != SabrinaCosts.end() )
620 sabrinaCost = (*isc).second;
621 else
622 sabrinaCost = 0;
623 phraseCost += sabrinaCost;
624 phraseStr += brick + " ";
627 // Find matching counterpart(s), only 1 per family
628 UsedCounterpartBrickFamiliesInPhrase.clear();
629 uint counterpartValue = getCompatibleCounterpartBrickForCost( phraseCost, phrase );
631 displayList( toString( "+%3u -%3u", phraseCost, counterpartValue ), phrase );
638 /*void getCompatiblePhraseByCounterpart( const string& counterpartBrick, vs& phrase )
640 sint sabrinaCost = SabrinaCosts[counterpartBrick];
642 // Assuming root brick cost is zero!
643 vs::const_iterator iob;
644 for ( iob=OptionBricks.begin(); iob!=OptionBricks.end(); ++iob )
646 // TODO: Find the highest cost that is lower or equal than the counterpart value
647 const string& ob = *iob;
648 if ( SabrinaCosts[ob] <= SabrinaCosts[counterpartBrick] )
649 break; // currently, take the first found
651 if ( iob != OptionBricks.end() )
653 string rb = getRootBrickForOptionOrCredit( *iob );
654 phrase.push_back( rb );
655 phrase.push_back( *iob );
656 phrase.push_back( counterpartBrick );
657 nldebug( "%s %s %s: +%u -%u", rb.c_str(), (*iob).c_str(), counterpartBrick.c_str(),
658 SabrinaCosts[rb]+SabrinaCosts[*iob], SabrinaCosts[counterpartBrick] );
660 else
661 nlwarning( "No matching phrase for counterpart %s", counterpartBrick.c_str() );
666 * Clear the form to reuse it (and all contents below node)
668 void clearSheet( CForm *form, UFormElm* node )
670 ((CFormElm*)node)->clean();
671 form->clean();
679 inline void explodeBrickAndParameters( const string& brickAndParams, vs& bricks )
681 explode( brickAndParams, " ", bricks );
688 string getBrickType( const string& brick )
690 if ( brick.size() < 4 )
691 return "INVALID TYPE in " + brick;
692 else
694 switch ( brick[brick.size()-getBrickTypeLetterRPos(const_cast<string&>(brick))] )
696 case 'P': return "Root";
697 break;
698 case 'E': return "Effect";
699 break;
700 case 'O': return "Option";
701 break;
702 case 'M': return "Modifier";
703 break;
704 case 'C': return "Credit";
705 break;
706 default:
707 return "INVALID TYPE in " + brick;
713 //-----------------------------------------------
714 // printBrickInfo
716 //-----------------------------------------------
717 void printBrickInfo( FILE *htmlfile, const string& brick, const string& grammarError, sint& sabrinaCost, uint& minSkillValue, string& minSkill )
719 minSkill.clear();
720 string b = brick;
721 strupr( b );
722 string brickType = getBrickType( b );
723 sint sc = (brickType=="Credit") ? -abs( SabrinaCosts[b] ) : SabrinaCosts[b];
724 CBrickInfo& bInfo = BrickInfo[b];
725 fprintf( htmlfile, "<LI><B>%s %s</B> %s<BR>\n", brickType.c_str(), b.c_str(), bInfo.Text.c_str() );
726 if ( ! grammarError.empty() )
728 fprintf( htmlfile, "<FONT COLOR=\"RED\">%s</FONT><BR>\n", grammarError.c_str() );
730 else
732 fprintf( htmlfile, "Sabrina Cost: %d <BR>\n", sc );
733 if( !bInfo.LearnSkills.empty() )
735 fprintf( htmlfile, "Skills required: %s<BR>\n", bInfo.LearnSkills.c_str() );
737 if( bInfo.Props.size() )
739 fprintf( htmlfile, "Properties:" );
740 for ( vs::const_iterator ip = bInfo.Props.begin(); ip!=bInfo.Props.end(); ++ip )
742 fprintf( htmlfile, " %s", (*ip) );
746 fprintf( htmlfile, "</LI>\n" );
748 // Calculate sabrina cost & skill value
749 sabrinaCost = sc;
750 if ( bInfo.LearnSkills.empty() )
751 minSkillValue = 0;
752 else
754 minSkillValue = ~0;
755 vector<string> skillsAndValues;
756 explode( bInfo.LearnSkills, ":", skillsAndValues, true );
757 vector<uint> skillValues( skillsAndValues.size(), ~0 );
758 vector<string>::iterator isv;
759 for ( isv=skillsAndValues.begin(); isv!=skillsAndValues.end(); ++isv )
761 const string& sav = *isv;
762 string::size_type p = sav.find( ' ' );
763 if ( (p == string::npos) || (sav.size() == p+1) )
764 nlwarning( "Invalid LearnRequiresOneOfSkills value '%s'", sav.c_str() );
765 else
767 uint sv = atoi( sav.substr( p+1 ).c_str() );
768 skillValues[isv-skillsAndValues.begin()] = sv;
769 if ( sv < minSkillValue )
770 minSkillValue = sv;
774 for ( isv=skillsAndValues.begin(); isv!=skillsAndValues.end(); ++isv )
776 if ( skillValues[isv-skillsAndValues.begin()] == minSkillValue )
778 string& sav = *isv;
779 if ( (! sav.empty()) && (sav[0] != 'S') )
780 sav = 'S' + sav;
781 if ( minSkill.find( sav ) == string::npos )
783 if ( ! minSkill.empty() )
784 minSkill += ", ";
785 minSkill += sav;
791 } // printBrickInfo //
794 //-----------------------------------------------
795 // loadBrickGrammar
797 //-----------------------------------------------
798 void loadBrickGrammar()
800 uint nbRootBricks = 0;
801 vs::const_iterator ib;
802 for ( ib=AllBricks.begin(); ib!=AllBricks.end(); ++ib )
804 string brick = *ib;
805 strupr( brick );
806 if ( brick.size() >= 4 )
808 char brickType = brick[brick.size()-getBrickTypeLetterRPos(brick)];
810 /*// As the root bricks may be absent from the table, deduce them (obsolete)
811 if ( brickType == 'O' )
813 string rootBrick = getRootBrickForOptionOrCredit( brick );
814 if ( GrammarOptionCreditBrickFamilies.find( rootBrick ) == GrammarOptionCreditBrickFamilies.end() )
816 brick = rootBrick;
817 brickType = 'P';
819 else
821 continue;
825 // If not skipped by previous 'continue'
826 if ( (brickType == 'P') || (brickType == 'E') || (brickType == 'O' ) ) // root, effect, option
828 NLMISC::CSmartPtr<CForm> form = (CForm*)FormLoader->loadForm( (strlwr(static_cast<const string&>(brick))+"."+brSheetType).c_str() );
829 if ( ! form )
831 nlwarning( "Can't load sheet %s", ((strlwr(static_cast<const string&>(brick)))+"."+phSheetType).c_str() );
832 continue;
834 for ( uint i=0; i!=12; ++i )
836 string value;
837 form->getRootNode().getValueByName( value, toString( "Mandatory.f%u", i ).c_str() );
838 if ( (! value.empty()) && (value != "Unknown") )
840 GrammarMandatParamBrickFamilies[brick].push_back( value );
843 if ( brickType == 'O' )
845 for ( uint i=0; i!=4; ++i )
847 string value;
848 form->getRootNode().getValueByName( value, toString( "Parameter.f%u", i ).c_str() );
849 if ( (! value.empty()) && (value != "Unknown") )
851 GrammarMandatParamBrickFamilies[brick].push_back( value );
855 if ( brickType == 'P' ) // root
857 ++nbRootBricks;
858 for ( uint i=0; i!=32; ++i )
860 string value;
861 form->getRootNode().getValueByName( value, toString( "Optional.f%u", i ).c_str() );
862 if ( (! value.empty()) && (value != "Unknown") )
864 GrammarOptionCreditBrickFamilies[brick].push_back( value );
867 for ( uint i=0; i!=12; ++i )
869 string value;
870 form->getRootNode().getValueByName( value, toString( "Credit.f%u", i ).c_str() );
871 if ( (! value.empty()) && (value != "Unknown") )
873 GrammarOptionCreditBrickFamilies[brick].push_back( value );
879 else
881 nlwarning( "Invalid brick code %s", brick.c_str() );
884 nlinfo( "%u bricks have mandatory/parameter grammar rules", GrammarMandatParamBrickFamilies.size() );
885 nlinfo( "%u bricks have option/credit grammar rules", GrammarOptionCreditBrickFamilies.size() );
886 nlinfo( "Found or deduced %u root bricks", nbRootBricks );
888 } // loadBrickGrammar //
892 //-----------------------------------------------
893 // loadPhraseTitles
895 //-----------------------------------------------
896 void loadPhraseTitles()
898 STRING_MANAGER::TWorksheet worksheet;
899 STRING_MANAGER::loadExcelSheet( "r:/code/ryzom/translation/translated/sphrase_words_en.txt", worksheet );
900 uint cp, cn;
901 if ( worksheet.findCol( ucstring("sphrase ID"), cp ) && worksheet.findCol( ucstring("name"), cn ) )
903 for ( std::vector<STRING_MANAGER::TWorksheet::TRow>::iterator ip = worksheet.begin(); ip!=worksheet.end(); ++ip )
905 if ( ip == worksheet.begin() ) // skip first row
906 continue;
907 STRING_MANAGER::TWorksheet::TRow& row = *ip;
908 PhraseTitles.insert( make_pair( strlwr(row[cp].toString()), row[cn].toUtf8() ) );
911 else
912 nlwarning( "sphrase ID or name not found" );
914 nlinfo( "Loaded %u phrase titles", PhraseTitles.size() );
916 } // loadPhraseTitles //
919 //-----------------------------------------------
920 // loadBrickTitles
922 //-----------------------------------------------
923 void loadBrickTitles()
925 STRING_MANAGER::TWorksheet worksheet;
926 STRING_MANAGER::loadExcelSheet( "r:/code/ryzom/translation/translated/sbrick_words_en.txt", worksheet );
927 uint cp, cn, nbTitles = 0;
928 if ( worksheet.findCol( ucstring("sbrick ID"), cp ) && worksheet.findCol( ucstring("name"), cn ) )
930 for ( std::vector<STRING_MANAGER::TWorksheet::TRow>::iterator ip = worksheet.begin(); ip!=worksheet.end(); ++ip )
932 if ( ip == worksheet.begin() ) // skip first row
933 continue;
934 STRING_MANAGER::TWorksheet::TRow& row = *ip;
935 BrickInfo[strupr(row[cp].toString())].Text = row[cn].toUtf8();;
936 ++nbTitles;
939 else
940 nlwarning( "sbrick ID or name not found" );
942 nlinfo( "Loaded %u brick titles", nbTitles );
944 } // loadBrickTitles //
950 void getChildrenBricks( const string& brick, vs& chFamilies )
952 chFamilies = GrammarMandatParamBrickFamilies[brick];
959 void addError( string& errorStr, string& newError, uint& nbGrammarErrors )
961 if ( ! errorStr.empty() )
962 errorStr += "<BR>";
963 errorStr += newError;
964 ++nbGrammarErrors;
971 void checkOptionOrCreditCompatibility( string& errorStr, const string& currentBrick, const string& rootBrick, uint& nbGrammarErrors )
973 string brick = currentBrick;
974 strupr( brick );
975 if ( brick.size() >= 4 && brick[1]!='C' && brick[1]!='H') // C & H for craft and harvest
977 char brickType = brick[brick.size()-getBrickTypeLetterRPos(brick)];
978 if ( (brickType == 'O') || (brickType == 'C') )
980 string rootBrick = getRootBrickForOptionOrCredit( brick );
981 const vs& compatibleOptionOrCredits = GrammarOptionCreditBrickFamilies[rootBrick];
982 vs::const_iterator ic;
983 for ( ic=compatibleOptionOrCredits.begin(); ic!=compatibleOptionOrCredits.end(); ++ic )
985 if ( isFromBrickFamily( brick, (*ic) ) )
986 break;
988 if ( ic == compatibleOptionOrCredits.end() )
990 addError( errorStr, toString( "This family is not compatible with options/credits of root %s", rootBrick.c_str() ), nbGrammarErrors );
998 * Preconditions:
999 * - grammarErrors.size() == phrase.size()
1000 * - r < phrase.size()
1002 * Note: does not check that all bricks should have a different family
1004 void checkGrammar( const vs& phrase, uint& r, vs& grammarErrors, uint& nbGrammarErrors, const string& rootBrick, bool readNext=true )
1006 uint origR = r;
1007 string grammarBrick = phrase[origR];
1008 strupr( grammarBrick );
1010 // Check option/credit
1011 checkOptionOrCreditCompatibility( grammarErrors[r], phrase[r], rootBrick, nbGrammarErrors );
1013 // Check mandatory/parameter
1014 vs chFamilies;
1015 getChildrenBricks( grammarBrick, chFamilies );
1016 ++r;
1017 for ( vs::const_iterator icf=chFamilies.begin(); icf!=chFamilies.end(); ++icf )
1019 // Detect incomplete phrase
1020 if ( r >= phrase.size() )
1022 addError( grammarErrors[origR], "Missing mandatory/parameter " + (*icf) + " at the end", nbGrammarErrors );
1023 break;
1026 // Detect wrong brick family
1027 if ( isFromBrickFamily( phrase[r], (*icf) ) )
1029 // Check grammar using child as root
1030 checkGrammar( phrase, r, grammarErrors, nbGrammarErrors, phrase[r], false );
1032 else
1034 addError( grammarErrors[r], "Error: " + (*icf) + " expected (mandatory/parameter of " + grammarBrick + ")", nbGrammarErrors );
1035 ++r;
1039 // Next
1040 if ( readNext && (r < phrase.size()) )
1042 checkGrammar( phrase, r, grammarErrors, nbGrammarErrors, rootBrick );
1050 char getDocFileLetter( const string& sheetName )
1052 // skip abm_mt_, abm_ml_...
1053 char letter = 'a';
1054 uint nbUnderscoresToSkip = 2, nbUnderscoresFound = 0;
1055 for ( uint c=0; c!=sheetName.size(); ++c )
1057 if ( nbUnderscoresFound == nbUnderscoresToSkip )
1059 letter = sheetName[c];
1060 break;
1062 if ( sheetName[c] == '_' )
1063 ++nbUnderscoresFound;
1065 return tolower( letter );
1069 //-----------------------------------------------
1070 // testPhraseGrammarAndProduceDoc
1072 //-----------------------------------------------
1073 bool testPhraseGrammarAndProduceDoc( const string& sheetName, const vs& phrase )
1075 string filename = strlwr( sheetName ) + "." + phSheetType;
1076 string phraseStatus;
1077 bool isPhraseCorrect = true;
1078 const char *rejectedstr = "(grammatically invalid)";
1080 // Check grammar for this phrase
1081 vs grammarErrors( phrase.size() );
1082 uint nbGrammarErrors = 0, r = 0;
1083 checkGrammar( phrase, r, grammarErrors, nbGrammarErrors, phrase[0] );
1084 if ( nbGrammarErrors != 0 )
1086 InvalidPhrases.push_back( sheetName );
1087 isPhraseCorrect = false;
1088 phraseStatus = rejectedstr;
1091 // Look-up phrase title
1092 string phraseTitle = PhraseTitles[sheetName];
1094 // Output phrase description
1095 char letter = 'a';
1096 if ( (! MultipleDocFiles) && (sheetName.size() > 3) )
1098 letter = tolower( sheetName[3] );
1100 else
1102 letter = getDocFileLetter( sheetName );
1104 if ( letter < 'a' )
1105 letter = 'a';
1106 else if ( letter > 'z' )
1107 letter = 'z';
1108 FILE *htmlFile = PhraseDocFiles[letter - 'a'];
1109 sint sabrinaCost;
1110 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() );
1111 vector<string> minBrickSkills( phrase.size() );
1112 vector<uint> minBrickSkillValues( phrase.size(), 0 );
1113 string brickMinSkill, maxSkill;
1114 sint posCost = 0, negCost = 0, totalCost;
1115 uint maxSkillValue = 0, brickMinSkillValue;
1116 for ( uint i=0; i!=phrase.size(); ++i )
1118 printBrickInfo( htmlFile, phrase[i], grammarErrors[i], sabrinaCost, brickMinSkillValue, brickMinSkill );
1119 if ( sabrinaCost > 0 )
1120 posCost += sabrinaCost;
1121 else
1122 negCost += sabrinaCost;
1123 minBrickSkillValues[i] = brickMinSkillValue;
1124 minBrickSkills[i] = brickMinSkill;
1125 if ( brickMinSkillValue > maxSkillValue )
1126 maxSkillValue = brickMinSkillValue;
1128 for ( uint i=0; i!=phrase.size(); ++i )
1130 if ( minBrickSkillValues[i] == maxSkillValue )
1132 if ( maxSkill.find( minBrickSkills[i] ) == string::npos )
1134 if ( ! maxSkill.empty() )
1135 maxSkill += "; ";
1136 maxSkill += minBrickSkills[i];
1140 if ( phrase.size() > 1 )
1142 string effectOrOptionBrick = phrase[1];
1143 strupr( effectOrOptionBrick );
1144 if ( ! PhraseNames.insert( make_pair( sheetName, BrickInfo[effectOrOptionBrick].Text ) ).second )
1145 nlwarning( "Found duplicate phrase %s", sheetName.c_str() );
1147 Progression.insert( make_pair( maxSkillValue, make_pair( sheetName, maxSkill ) ) );
1148 totalCost = posCost + negCost;
1149 PhraseSabrinaCosts.insert( make_pair(sheetName,totalCost) );
1150 char *redbegin = "", *redend = "";
1151 if ( totalCost > 0 )
1153 map<string,bool>::const_iterator itCastable = PhraseCastable.find(sheetName);
1154 if( itCastable != PhraseCastable.end() )
1156 if( (*itCastable).second )
1158 redbegin = "<FONT COLOR=\"RED\">";
1159 redend = "</FONT>";
1160 PhrasesWithInvalidCost.push_back( sheetName );
1161 isPhraseCorrect = false;
1165 fprintf( htmlFile, "<LI>%s<B>Total sabrina cost: </B>+%d %d = %d%s</LI>\n", redbegin, posCost, negCost, totalCost, redend );
1166 fprintf( htmlFile, "<LI><B>Minimum skill value required: %d</B></LI>\n", maxSkillValue );
1167 fprintf( htmlFile, "</UL></P>\n" );
1168 if ( ! isPhraseCorrect )
1170 ++NbSheetsRejected;
1172 return isPhraseCorrect;
1174 } // testPhraseGrammarAndProduceDoc //
1183 inline bool isSeparator( char c )
1185 return (c == ' ') || (c == '\t');
1190 //-----------------------------------------------
1191 // produceDocFromExistingPhrases
1193 // - Phrases
1194 //-----------------------------------------------
1195 void produceDocFromExistingPhrases()
1197 vs files;
1198 CPath::getPathContent( PhrasePath, true, false, true, files );
1200 NbSheetsRead = 0;
1201 for ( vs::const_iterator ip=files.begin(); ip!=files.end(); ++ip )
1203 if ( CFile::getExtension( *ip ) == phSheetType )
1205 // Read george sheet
1206 NLMISC::CSmartPtr<UForm> form = (UForm*)FormLoader->loadForm( (*ip).c_str() );
1207 if ( ! form )
1208 nlerror( "Can't load sheet %s", (*ip).c_str() );
1210 // Get the bricks of the phrase
1211 vs phrase;
1212 for ( uint i=0; i!=100; ++i )
1214 string value;
1215 form->getRootNode().getValueByName( value, toString( "brick %u", i ).c_str() );
1216 if ( !value.empty() )
1218 strupr( value );
1219 phrase.push_back( CFile::getFilenameWithoutExtension( value ) );
1223 Phrases.insert( make_pair(CFile::getFilenameWithoutExtension( *ip ), phrase) );
1225 // look if phrase is castable
1226 bool castable;
1227 form->getRootNode().getValueByName( castable, "castable");
1228 PhraseCastable.insert( make_pair(CFile::getFilenameWithoutExtension( *ip ), castable) );
1230 // Test grammar and produce doc
1231 testPhraseGrammarAndProduceDoc( CFile::getFilenameWithoutExtension( *ip ), phrase );
1233 ++NbSheetsRead;
1236 nlinfo( "Total: %u phrases", NbSheetsRead );
1238 } // produceDocFromExistingPhrases //
1244 string getLink( const string& phrase )
1246 string res;
1247 if ( MultipleDocFiles && (! phrase.empty()) )
1249 res += DocFileName + "_" + getDocFileLetter( phrase ) + ".html";
1251 else
1253 res += DocFileName + ".html";
1255 res += "#" + phrase;
1256 //nlinfo( "%s", res.c_str() );
1257 return res;
1264 void usage(char *argv0, FILE *out)
1266 fprintf(out, "\n");
1267 fprintf(out, "Syntax: %s [-p <sheet path>] <bricksFilename> [-o <phrasePath>] [-b] [-d] [-m] [-n]\n", argv0);
1268 fprintf(out, "-o: output phrase path (or input if -d is set)\n");
1269 fprintf(out, "-b: produce doc about brick learning infos\n");
1270 fprintf(out, "-d: browse existing phrases in <phrasePath> (and subdirs) and produce doc\n");
1271 fprintf(out, "-m: multiple doc html files, alphabetically (use with -g,-c,-d with numerous phrases)\n");
1272 fprintf(out, "-n: no hypertext (don't produce links phrases)\n");
1274 fprintf(out, "\n");
1280 //-----------------------------------------------
1281 // makeIndexFile
1283 //-----------------------------------------------
1284 void makeIndexFile()
1286 FILE * indexFile = nlfopen( "_" + DocFileNameRoot + "_INDEX.html", "wt" );
1287 if( indexFile )
1289 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() );
1291 DocFileName = DocFileNameRoot + "_actions";
1293 if ( MultipleDocFiles )
1295 // One HTML file per alphabet letter
1296 for ( uint l=0; l!=26; ++l )
1298 string filename = toString( "%s_%c.html", DocFileName.c_str(), 'a'+l );
1299 PhraseDocFiles[l] = nlfopen( filename, "wt" );
1300 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() );
1301 fprintf( indexFile, ("<A HREF=\"" + filename + "\">" + (char)('A'+l) + "</A> ").c_str() );
1304 else
1306 // One single HTML file
1307 fprintf( indexFile, ("<A HREF=\"" + DocFileName + ".html\">Go to action details</A>").c_str() );
1308 PhraseDocFiles[0] = nlfopen( DocFileName + ".html", "wt" );
1309 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() );
1310 for ( uint l=1; l!=26; ++l )
1312 PhraseDocFiles[l] = PhraseDocFiles[0];
1315 fprintf( indexFile, ("<BR><A HREF=\"" + DocFileName + "__by_skill_value.html" + "\">Go to action by skill value</A>\n").c_str() );
1316 fprintf( indexFile, ("<BR><A HREF=\"" + DocFileName + "__by_skill_value_detail.html" + "\">Go to action by skill value (detail)</A>\n").c_str() );
1317 fprintf( indexFile, ("<BR><A HREF=\"" + DocFileName + "__by_skill.html" + "\">Go to action by skill</A><BR>\n").c_str() );
1319 if( GenerateBrickProgression )
1321 fprintf( indexFile, ("<BR><BR><A HREF=\"" + DocFileNameRoot + ".html" + "\">Go to brick list</A><BR>\n").c_str() );
1324 produceDocFromExistingPhrases();
1326 for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
1328 const string& phraseCode = (*ip).second.first;
1329 string link = Hypertext ? toString( "<A HREF=\"%s\">%s</A>", getLink(phraseCode).c_str(), phraseCode.c_str() ) : "<B>" + phraseCode + "</B>";
1330 PhraseCodeToLink.insert( make_pair(phraseCode,link) );
1333 // Summary (errors in phrases)
1334 fprintf( indexFile, "<BR><A NAME=\"summary\"></A>\n" );
1335 fprintf( indexFile, ("<FONT SIZE=\"20\">Summary of " + DocFileName + "</FONT><BR>\n").c_str() );
1336 if ( NbSheetsGenTries != 0 )
1337 fprintf( indexFile, "<P>%u valid sheets written on %u</P>\n", NbSheetsWritten, NbSheetsGenTries );
1338 if ( NbSheetsRead != 0 )
1339 fprintf( indexFile, "<P>%u sheets read</P>\n", NbSheetsRead );
1340 fprintf( indexFile, "<P>%u invalid sheets rejected", NbSheetsRejected );
1341 if ( ! PhrasesWithInvalidCost.empty() )
1343 fprintf( indexFile, "<P><B>Phrases with invalid sabrina cost:</B><BR>\n" );
1344 for ( vs::const_iterator iip=PhrasesWithInvalidCost.begin(); iip!=PhrasesWithInvalidCost.end(); ++iip )
1346 string link = Hypertext ? toString( "<A HREF=\"%s\">%s</A>", getLink(*iip).c_str(), (*iip).c_str() ) : "<B>" + (*iip) + "</B>";
1347 fprintf( indexFile, "%s<BR>\n", link.c_str() );
1349 fprintf( indexFile, "</P>\n" );
1351 else
1353 fprintf( indexFile, "<P><B>All phrases have valid sabrina cost.</B></P>\n" );
1355 if ( ! InvalidPhrases.empty() )
1357 fprintf( indexFile, "<P><B>Grammatically invalid phrases:</B><BR>\n" );
1358 for ( vs::const_iterator iip=InvalidPhrases.begin(); iip!=InvalidPhrases.end(); ++iip )
1360 string link = Hypertext ? toString( "<A HREF=\"%s\">%s</A>", getLink(*iip).c_str(), (*iip).c_str() ) : "<B>" + (*iip) + "</B>";
1361 fprintf( indexFile, "%s<BR>\n", link.c_str() );
1363 fprintf( indexFile, "</P>\n" );
1365 else
1367 fprintf( indexFile, "<P><B>All phrases are grammatically valid.</B></P>\n" );
1369 fprintf( indexFile, "</body></html>\n" );
1370 fclose( indexFile );
1372 if ( MultipleDocFiles )
1374 for ( uint l=0; l!=26; ++l )
1376 fprintf( PhraseDocFiles[l], "</body></html>\n" );
1377 fclose( PhraseDocFiles[l] );
1380 else
1382 fprintf( PhraseDocFiles[0], "</body></html>\n" );
1383 fclose( PhraseDocFiles[0] );
1387 } // makeIndexFile //
1390 //-----------------------------------------------
1391 // makeActionsBySkillGroupFile
1393 //-----------------------------------------------
1394 void makeActionsBySkillGroupFile()
1396 // progression by skill
1397 FILE * actionsBySkillGroupFile = nlfopen( DocFileName + "__by_skill.html", "wt" );
1398 if( actionsBySkillGroupFile )
1400 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() );
1401 fprintf( actionsBySkillGroupFile, "<BR><A NAME=\"by_skill_group\"></A>\n" );
1402 fprintf( actionsBySkillGroupFile, "<P><B>ACTIONS BY SKILL GROUP:</B><BR>\n<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n" );
1403 map<string, multimap<uint,string> > phrasesBySkill;
1404 for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
1406 const string& phraseCode = (*ip).second.first;
1407 string skillName = (*ip).second.second.substr(0,(*ip).second.second.find(" "));
1408 string skillValueStr = (*ip).second.second.substr((*ip).second.second.find(" ")+1,(*ip).second.second.size()-(*ip).second.second.find(" ")-1);
1409 uint skillValue = atoi(skillValueStr.c_str());
1411 map<string, multimap<uint,string> >::iterator it = phrasesBySkill.find(skillName);
1412 if( it != phrasesBySkill.end() )
1414 (*it).second.insert(make_pair(skillValue,phraseCode));
1416 else
1418 multimap<uint,string> m;
1419 m.insert(make_pair(skillValue,phraseCode));
1420 phrasesBySkill.insert( make_pair(skillName,m) );
1424 map<string, multimap<uint,string> >::iterator itPhrasesBySkill;
1425 for( itPhrasesBySkill = phrasesBySkill.begin(); itPhrasesBySkill != phrasesBySkill.end(); ++itPhrasesBySkill )
1427 CVectorSString dicoResult;
1428 Dico.lookup( (*itPhrasesBySkill).first, dicoResult, true );
1429 if( !dicoResult.empty() )
1430 fprintf( actionsBySkillGroupFile, "<tr><td><A HREF=\"#%s\">%s</A></td></tr>\n", (*itPhrasesBySkill).first.c_str(),dicoResult[0].c_str());
1431 else
1432 fprintf( actionsBySkillGroupFile, "<tr><td><A HREF=\"#%s\">%s</A></td></tr>\n", (*itPhrasesBySkill).first.c_str(),(*itPhrasesBySkill).first.c_str());
1434 for( itPhrasesBySkill = phrasesBySkill.begin(); itPhrasesBySkill != phrasesBySkill.end(); ++itPhrasesBySkill )
1436 CVectorSString dicoResult;
1437 Dico.lookup( (*itPhrasesBySkill).first, dicoResult, true );
1438 if( !dicoResult.empty() )
1439 fprintf( actionsBySkillGroupFile, "<tr><td><A NAME=\"%s\"><B>%s</B></A><BR></td></tr>\n", (*itPhrasesBySkill).first.c_str(), dicoResult[0].c_str() );
1440 else
1441 fprintf( actionsBySkillGroupFile, "<tr><td><A NAME=\"%s\"><B>%s</B></A><BR></td></tr>\n", (*itPhrasesBySkill).first.c_str(),(*itPhrasesBySkill).first.c_str() );
1443 multimap<uint,string>::iterator it;
1444 for( it = (*itPhrasesBySkill).second.begin(); it != (*itPhrasesBySkill).second.end(); ++it )
1446 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());
1449 fprintf( actionsBySkillGroupFile, "</tbody><table></P>\n" );
1450 fprintf( actionsBySkillGroupFile, "</body></html>\n" );
1451 fclose( actionsBySkillGroupFile );
1454 } // makeActionsBySkillGroupFile //
1458 //-----------------------------------------------
1459 // makeActionsBySkillValueFile
1461 //-----------------------------------------------
1462 void makeActionsBySkillValueFile()
1464 FILE * actionsBySkillValueFile = fopen( (DocFileName + "__by_skill_value.html").c_str(), "wt" );
1465 if( actionsBySkillValueFile )
1467 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() );
1469 // Progression (phrases sorted by skill value)
1470 fprintf( actionsBySkillValueFile, "<BR><A NAME=\"by_skill_value\"></A>\n" );
1471 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() );
1472 fprintf( actionsBySkillValueFile, "<tr><td><B>File</B></td><td><B>Name</B></td><td><B>Skill needed</B><BR></td></tr>\n");
1473 map<string,string> phraseCodeToLink;
1474 for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
1476 const string& phraseCode = (*ip).second.first;
1477 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() );
1479 fprintf( actionsBySkillValueFile, "</tbody><table></P>\n" );
1480 fprintf( actionsBySkillValueFile, "</body></html>\n" );
1481 fclose( actionsBySkillValueFile );
1484 } // makeActionsBySkillValueFile //
1487 //-----------------------------------------------
1488 // makeActionsBySkillValueDetailFile
1490 //-----------------------------------------------
1491 void makeActionsBySkillValueDetailFile()
1493 FILE * actionsBySkillValueDetailFile = nlfopen( DocFileName + "__by_skill_value_detail.html", "wt" );
1494 if( actionsBySkillValueDetailFile )
1496 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() );
1498 // Progression summary (phrases sorted by skill value)
1499 fprintf( actionsBySkillValueDetailFile, "<BR><A NAME=\"progression\"></A>\n" );
1500 fprintf( actionsBySkillValueDetailFile, "<P><B>ACTIONS BY SKILL VALUE:</B><BR>\n<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n" );
1501 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");
1503 set<string> effects;
1504 map<string,set<string> > effectAndModifiers;
1505 for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
1507 const string& phraseCode = (*ip).second.first;
1508 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]);
1510 msvs::iterator itPhrases = Phrases.find( phraseCode );
1511 if( itPhrases != Phrases.end() )
1513 string effect;
1514 uint modifierCount = 0;
1515 uint creditCount = 0;
1516 for( uint i = 0; i<(*itPhrases).second.size(); ++i )
1518 string brick = (*itPhrases).second[i];
1519 string color;
1520 switch ( brick[brick.size()-getBrickTypeLetterRPos(brick)] )
1522 case 'P': color = "Black";
1523 break;
1524 case 'E':
1526 color = "Brown";
1527 effects.insert(brick);
1528 if( effectAndModifiers.find(brick) == effectAndModifiers.end() )
1530 set<string> s;
1531 effectAndModifiers.insert( make_pair(brick,s) );
1533 effect = brick;
1535 break;
1536 case 'O': color = "Green";
1537 break;
1538 case 'M':
1540 color = "Blue";
1541 effectAndModifiers[effect].insert(brick);
1542 modifierCount++;
1544 break;
1545 case 'C': color = "Red"; creditCount++;
1546 break;
1547 default:
1548 color = "Black";
1550 string text = BrickInfo[brick].Text;
1551 if( text.empty() )
1553 text = strlwr(brick);
1554 nlwarning("%s not found in BrickInfo",brick.c_str());
1556 else
1558 if(text.find("$|sap")!=-1)
1560 text = text.substr(0,text.size()-5);
1561 string str = brick.substr(brick.size()-5,5);
1562 text += toString(atoi(str.c_str()));
1565 fprintf( actionsBySkillValueDetailFile, "<td><FONT COLOR=\"%s\" SIZE=2>%s</FONT></td>",color.c_str(),text.c_str());
1568 else
1570 nlerror("not found : %s",phraseCode.c_str());
1572 fprintf( actionsBySkillValueDetailFile, "</tr>\n");
1574 fprintf( actionsBySkillValueDetailFile, "</tbody><table></P>\n" );
1575 fprintf( actionsBySkillValueDetailFile, "</body></html>\n" );
1576 fclose( actionsBySkillValueDetailFile );
1579 } // makeActionsBySkillValueDetailFile //
1582 //-----------------------------------------------
1583 // validateBrick
1585 //-----------------------------------------------
1586 bool validateBrick( const string& brk )
1588 if(brk[1]=='C') return true;
1589 if(brk[1]=='F') return true;
1590 if(brk[1]=='H') return true;
1591 if(brk[1]=='M') return true;
1592 if(brk[1]=='S') return true;
1593 return false;
1595 } // validateBrick //
1599 //-----------------------------------------------
1600 // makeSkillTreeFile
1602 //-----------------------------------------------
1603 void makeSkillTreeFile( char filter, string skillFamily, bool withTraduction )
1605 vector<map<string,uint16> > skillsArray;
1606 skillsArray.resize(6); // 6 tranches de skill
1607 uint i;
1608 for( i = 0; i<SkillsTree.SkillsTree.size(); ++i )
1610 string skillCode = SkillsTree.SkillsTree[i].SkillCode;
1611 if( skillCode[1] == filter )
1613 uint sIdx = skillCode.length()-2; // -1 for 'S', -1 for 0
1614 skillsArray[sIdx].insert( make_pair(skillCode,SkillsTree.SkillsTree[i].MaxSkillValue) );
1618 uint16 maxLine = 0;
1619 for( i=0; i<skillsArray.size(); ++i )
1621 if( skillsArray[i].size() > maxLine )
1623 maxLine = skillsArray[i].size();
1627 string filename = skillFamily + "_skill_tree.html";
1628 string filenameWithTraduction = skillFamily + "_skill_tree_detailed.html";
1629 FILE * skillTreeFile;
1630 if( withTraduction )
1631 skillTreeFile = nlfopen( filenameWithTraduction, "wt" );
1632 else
1633 skillTreeFile = nlfopen( filename, "wt" );
1634 fprintf( skillTreeFile,"<html><head>\n");
1635 fprintf( skillTreeFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
1636 fprintf( skillTreeFile,"<title>SKILL TREE ( %s )</title>\n",skillFamily.c_str());
1637 fprintf( skillTreeFile,"</head><body>\n");
1638 if( withTraduction )
1639 fprintf( skillTreeFile,"<b>SKILL TREE ( %s )</b>\n",skillFamily.c_str());
1640 else
1641 fprintf( skillTreeFile,"<b>SKILL TREE ( %s )</b> [<A HREF=\"%s\">display traduction</A>]<BR>\n",skillFamily.c_str(),filenameWithTraduction.c_str());
1642 fprintf( skillTreeFile,"<table cellpadding=\"2\" cellspacing=\"2\" border=\"0\" style=\"text-align: left;\"><tbody>\n");
1643 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");
1645 uint j;
1646 // print line by line
1647 for( j=0; j<maxLine; ++j )
1649 fprintf( skillTreeFile,"<tr>");
1650 // for each column
1651 for( i=0; i<skillsArray.size(); ++i )
1653 uint p;
1654 map<string,uint16>::iterator itSkillcode;
1655 for( itSkillcode = skillsArray[i].begin(), p=0; itSkillcode != skillsArray[i].end() && p<j; ++itSkillcode,++p );
1656 if( itSkillcode != skillsArray[i].end() )
1658 if( withTraduction )
1660 CVectorSString dicoResult;
1661 Dico.lookup( (*itSkillcode).first, dicoResult, true );
1662 if(dicoResult.empty())
1663 fprintf( skillTreeFile,"<td>%s : ???</td>",(*itSkillcode).first.c_str());
1664 else
1665 fprintf( skillTreeFile,"<td>%s</td>",dicoResult[0].c_str());
1667 else
1668 fprintf( skillTreeFile,"<td>%s</td>",(*itSkillcode).first.c_str());
1670 else
1671 fprintf( skillTreeFile,"<td></td>");
1673 fprintf( skillTreeFile,"</tr>\n");
1676 fprintf( skillTreeFile, "</tbody><table></P>\n" );
1677 fprintf( skillTreeFile, "</body></html>\n" );
1678 fclose( skillTreeFile );
1680 } // makeSkillTreeFile //
1686 //-----------------------------------------------
1687 // MAIN
1689 //-----------------------------------------------
1690 int main(int argc, char* argv[])
1692 // parse command line
1693 const char *inputFilename = NULL;
1694 for ( uint i=1; (sint)i!=argc; i++ )
1696 const char *arg = argv[i];
1697 if ( arg[0] == '-' )
1699 switch ( arg[1] )
1701 case 'p':
1702 ++i;
1703 if ( (sint)i == argc )
1705 fprintf( stderr, "Missing <sheet path> after -p option\n" );
1706 usage( argv[0], stderr );
1707 exit( 0 );
1709 inputSheetPath = argv[i];
1710 break;
1711 case 'o':
1712 ++i;
1713 if ( (sint)i == argc )
1715 fprintf( stderr, "Missing <phrasePath> after -o option\n" );
1716 usage( argv[0], stderr );
1717 exit( 0 );
1719 PhrasePath = argv[i];
1720 if ( PhrasePath[PhrasePath.size()-1] != '/' )
1721 PhrasePath += '/';
1722 break;
1723 case 'b' :
1724 GenerateBrickProgression = true;
1725 break;
1726 case 'd':
1727 ProduceDocFromExistingPhrases = true;
1728 break;
1729 case 'm':
1730 MultipleDocFiles = true;
1731 break;
1732 case 'n':
1733 Hypertext = false;
1734 break;
1737 else
1739 if ( CFile::getExtension(arg) == "csv" )
1741 inputFilename = arg;
1743 else
1744 nlerror( "Unrecognized extension in %s", arg );
1749 Dico.init();
1751 loadSheetPath();
1752 FormLoader = UFormLoader::createLoader();
1753 CSheetId::init();
1755 CSheetId skillTreeSheet("skills.skill_tree");
1756 CSmartPtr<UForm> skillTreeForm = FormLoader->loadForm( "skills.skill_tree" );
1757 SkillsTree.readGeorges( skillTreeForm, skillTreeSheet );
1760 makeSkillTreeFile('C',"craft", false);
1761 makeSkillTreeFile('F',"fight", false);
1762 makeSkillTreeFile('H',"forage", false);
1763 makeSkillTreeFile('M',"magic", false);
1765 makeSkillTreeFile('C',"craft", true);
1766 makeSkillTreeFile('F',"fight", true);
1767 makeSkillTreeFile('H',"forage", true);
1768 makeSkillTreeFile('M',"magic", true);
1771 // Load bricks from the csv
1772 UseBricks = ProduceDocFromExistingPhrases;
1773 if ( UseBricks )
1775 if ( ! inputFilename )
1777 usage( argv[0], stderr );
1778 exit( 0 );
1780 loadBricks( inputFilename );
1784 // Phrases
1785 if ( ProduceDocFromExistingPhrases )
1787 loadBrickGrammar();
1788 loadBrickTitles();
1789 loadPhraseTitles();
1791 DocFileNameRoot = toString( "%s", CFile::getFilenameWithoutExtension( inputFilename ).c_str() );
1793 // index
1794 makeIndexFile();
1796 // progression by skill
1797 makeActionsBySkillGroupFile();
1799 // Progression (phrases sorted by skill value)
1800 makeActionsBySkillValueFile();
1802 // Progression (phrases sorted by skill value + detail)
1803 makeActionsBySkillValueDetailFile();
1808 if( GenerateBrickProgression )
1810 map<uint,map<string,set<string> > > levelToBrick;
1812 map<string,string> phraseToSkill;
1814 for ( map< uint, pair<string, string> >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
1816 const string& phraseCode = (*ip).second.first;
1818 string skillTmp = (*ip).second.second.c_str();
1820 phraseToSkill.insert( make_pair(phraseCode,skillTmp) );
1822 if(skillTmp.empty()==false)
1824 // get skill
1825 string skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
1827 // get level
1828 string levelStr;
1829 if( skillTmp.find(";") != -1 )
1831 sint idx = skillTmp.find_first_of(" ");
1832 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
1834 else
1836 sint idx = skillTmp.find_first_of(" ");
1837 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
1839 if(levelStr.find(".")!=-1) levelStr = levelStr.substr(0,levelStr.size()-1);
1840 uint level = atoi(levelStr.c_str());
1843 map<uint,map<string,set<string> > >::iterator itLvl = levelToBrick.find(level);
1844 if( itLvl == levelToBrick.end() )
1846 set<string> s;
1847 map<string,set<string> > mp;
1848 mp.insert(make_pair(skill,s));
1849 levelToBrick.insert(make_pair(level,mp));
1851 else
1853 if( (*itLvl).second.find(skill) == (*itLvl).second.end() )
1855 set<string> s;
1856 (*itLvl).second.insert( make_pair(skill,s) );
1860 msvs::iterator itPhrases = Phrases.find( phraseCode );
1861 if( itPhrases != Phrases.end() )
1863 string effect;
1864 for( uint i = 0; i<(*itPhrases).second.size(); ++i )
1866 string brick = (*itPhrases).second[i];
1868 if( levelToBrick[level][skill].find(brick) == levelToBrick[level][skill].end() )
1870 levelToBrick[level][skill].insert(brick);
1880 // get family & color
1881 map<string,string> brickToColor;
1882 map<string,string> brickToFamily;
1883 map<string, CBrickInfo>::iterator itBInf;
1884 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
1886 string brk = (*itBInf).first;
1888 if(!validateBrick(brk)) continue;
1890 string color;
1891 string family;
1892 if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='M' )
1894 color = "Blue";
1895 family = "Modifier";
1897 if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='C' )
1899 color = "Red";
1900 family = "Credit";
1902 if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='O' )
1904 color = "Green";
1905 family = "Option";
1907 if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='P' )
1909 color = "Black";
1910 family = "Root";
1912 if( brk[brk.size()-getBrickTypeLetterRPos(brk)] =='E' )
1914 color = "Brown";
1915 family = "Effect";
1918 brickToColor.insert(make_pair(brk,color));
1919 brickToFamily.insert(make_pair(brk,family));
1922 // get phrases where the brick can be found
1923 map<string,map<string,string> > brickToPhrases;
1924 msvs::iterator itPhrases;
1925 for( itPhrases=Phrases.begin(); itPhrases!=Phrases.end(); ++itPhrases )
1927 for( uint i = 0; i<(*itPhrases).second.size(); ++i )
1929 string brick = (*itPhrases).second[i];
1930 if( brickToPhrases.find(brick)==brickToPhrases.end() )
1932 map<string,string> m;
1934 m.insert(make_pair((*itPhrases).first,phraseToSkill[(*itPhrases).first]));
1935 brickToPhrases.insert(make_pair(brick,m));
1937 else
1939 brickToPhrases[brick].insert(make_pair((*itPhrases).first,phraseToSkill[(*itPhrases).first]));
1944 // get skill when a brick is learnt
1945 map<string,string> brickToLearnSkill;
1946 map<string,map<string,string> >::iterator itLearn;
1947 for( itLearn=brickToPhrases.begin(); itLearn!=brickToPhrases.end(); ++itLearn )
1949 string minSkill;
1950 uint minLevel = 250;
1952 mss::iterator itPh;
1953 for( itPh=(*itLearn).second.begin(); itPh!=(*itLearn).second.end(); ++itPh )
1955 string skillTmp = (*itPh).second;
1956 string levelStr;
1957 if( skillTmp.find(";") != -1 )
1959 sint idx = skillTmp.find_first_of(" ");
1960 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
1962 else
1964 sint idx = skillTmp.find_first_of(" ");
1965 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
1967 uint level = atoi(levelStr.c_str());
1969 if( level<minLevel || minSkill.empty() )
1971 minSkill = skillTmp;
1972 minLevel = level;
1976 brickToLearnSkill.insert(make_pair((*itLearn).first,minSkill));
1979 // PHRASES
1981 // write header and title bar
1982 string filename;
1983 filename = DocFileNameRoot + "_m.html";
1984 FILE * brickPhraseDocFile_m = nlfopen( filename, "wt" );
1985 fprintf( brickPhraseDocFile_m,"<html><head>\n");
1986 fprintf( brickPhraseDocFile_m,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
1987 fprintf( brickPhraseDocFile_m,"<title>Brick phrases</title>\n");
1988 fprintf( brickPhraseDocFile_m,"</head><body>\n");
1989 fprintf( brickPhraseDocFile_m,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n");
1991 filename = DocFileNameRoot + "_c.html";
1992 FILE * brickPhraseDocFile_c = nlfopen( filename, "wt" );
1993 fprintf( brickPhraseDocFile_c,"<html><head>\n");
1994 fprintf( brickPhraseDocFile_c,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
1995 fprintf( brickPhraseDocFile_c,"<title>Brick phrases</title>\n");
1996 fprintf( brickPhraseDocFile_c,"</head><body>\n");
1997 fprintf( brickPhraseDocFile_c,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n");
1999 filename = DocFileNameRoot + "_o.html";
2000 FILE * brickPhraseDocFile_o = nlfopen( filename, "wt" );
2001 fprintf( brickPhraseDocFile_o,"<html><head>\n");
2002 fprintf( brickPhraseDocFile_o,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2003 fprintf( brickPhraseDocFile_o,"<title>Brick phrases</title>\n");
2004 fprintf( brickPhraseDocFile_o,"</head><body>\n");
2005 fprintf( brickPhraseDocFile_o,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n");
2007 filename = DocFileNameRoot + "_p.html";
2008 FILE * brickPhraseDocFile_p = nlfopen( filename, "wt" );
2009 fprintf( brickPhraseDocFile_p,"<html><head>\n");
2010 fprintf( brickPhraseDocFile_p,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2011 fprintf( brickPhraseDocFile_p,"<title>Brick phrases</title>\n");
2012 fprintf( brickPhraseDocFile_p,"</head><body>\n");
2013 fprintf( brickPhraseDocFile_p,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n");
2015 filename = DocFileNameRoot + "_e.html";
2016 FILE * brickPhraseDocFile_e = nlfopen( filename, "wt" );
2017 fprintf( brickPhraseDocFile_e,"<html><head>\n");
2018 fprintf( brickPhraseDocFile_e,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2019 fprintf( brickPhraseDocFile_e,"<title>Brick phrases</title>\n");
2020 fprintf( brickPhraseDocFile_e,"</head><body>\n");
2021 fprintf( brickPhraseDocFile_e,"<table cellpadding=\"0\" cellspacing=\"1\" border=\"0\" style=\"text-align: left;\"><tbody>\n");
2023 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
2025 string brk = (*itBInf).first;
2027 if(!validateBrick(brk)) continue;
2029 string code = strlwr(brk.c_str());
2031 if(brickToFamily[brk]=="Modifier")
2032 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());
2033 if(brickToFamily[brk]=="Credit")
2034 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());
2035 if(brickToFamily[brk]=="Option")
2036 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());
2037 if(brickToFamily[brk]=="Effect")
2038 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());
2039 if(brickToFamily[brk]=="Root")
2040 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());
2042 map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk);
2043 if( itPhrases != brickToPhrases.end() )
2045 map<string,string>::iterator itPh;
2046 for( itPh=(*itPhrases).second.begin(); itPh!=(*itPhrases).second.end(); ++itPh )
2048 if(brickToFamily[brk]=="Modifier")
2049 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());
2050 if(brickToFamily[brk]=="Credit")
2051 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());
2052 if(brickToFamily[brk]=="Option")
2053 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());
2054 if(brickToFamily[brk]=="Effect")
2055 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());
2056 if(brickToFamily[brk]=="Root")
2057 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());
2061 fprintf( brickPhraseDocFile_m, "</tbody><table></P>\n" );
2062 fprintf( brickPhraseDocFile_m, "</body></html>\n" );
2063 fclose( brickPhraseDocFile_m );
2065 fprintf( brickPhraseDocFile_c, "</tbody><table></P>\n" );
2066 fprintf( brickPhraseDocFile_c, "</body></html>\n" );
2067 fclose( brickPhraseDocFile_c );
2069 fprintf( brickPhraseDocFile_o, "</tbody><table></P>\n" );
2070 fprintf( brickPhraseDocFile_o, "</body></html>\n" );
2071 fclose( brickPhraseDocFile_o );
2073 fprintf( brickPhraseDocFile_e, "</tbody><table></P>\n" );
2074 fprintf( brickPhraseDocFile_e, "</body></html>\n" );
2075 fclose( brickPhraseDocFile_e );
2077 fprintf( brickPhraseDocFile_p, "</tbody><table></P>\n" );
2078 fprintf( brickPhraseDocFile_p, "</body></html>\n" );
2079 fclose( brickPhraseDocFile_p );
2082 // CODE
2084 // write header and title bar
2085 filename = DocFileNameRoot + ".html";
2086 FILE * brickDocFile = nlfopen( filename, "wt" );
2087 fprintf( brickDocFile,"<html><head>\n");
2088 fprintf( brickDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2089 fprintf( brickDocFile,"<title>Bricks infos</title>\n");
2090 fprintf( brickDocFile,"</head><body>\n");
2091 fprintf( brickDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n");
2092 fprintf( brickDocFile,"<tr>\n");
2093 fprintf( brickDocFile,"<td><b>*Code*</b></td>\n");
2094 fprintf( brickDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str());
2095 fprintf( brickDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str());
2096 fprintf( brickDocFile,"<td><b>Required Skill Name</b></td>\n");
2097 fprintf( brickDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2098 fprintf( brickDocFile,"<td><b>Learn Skill Name</b></td>\n");
2099 fprintf( brickDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2100 fprintf( brickDocFile,"<td><b>Found In Phrases</b></td>\n");
2101 fprintf( brickDocFile,"</tr>\n");
2104 // write infos
2105 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
2107 string brk = (*itBInf).first;
2109 if(!validateBrick(brk)) continue;
2111 string skillTmp = (*itBInf).second.LearnSkills;
2112 string skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2113 CVectorSString dicoResult;
2114 Dico.lookup( skill, dicoResult, true );
2115 if(dicoResult.empty()) continue;
2117 // color
2118 string color = brickToColor[brk];
2120 // code
2121 string code = strlwr(brk.c_str());
2122 fprintf( brickDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str());
2124 // name
2125 string name = (*itBInf).second.Text;
2126 fprintf( brickDocFile, "<td>%s</td>\n",name.c_str());
2128 // family
2129 string family = brickToFamily[brk];
2130 fprintf( brickDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str());
2132 // required skill name
2133 fprintf( brickDocFile, "<td>%s</td>\n",dicoResult[0].c_str());
2135 // required skill value
2136 string levelStr;
2137 if( skillTmp.find(";") != -1 )
2139 sint idx = skillTmp.find_first_of(" ");
2140 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2142 else
2144 sint idx = skillTmp.find_first_of(" ");
2145 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2147 fprintf( brickDocFile, "<td>%s</td>\n",levelStr.c_str());
2149 // learn skill name
2150 string learnSkillTmp = brickToLearnSkill[brk];
2151 skill = learnSkillTmp.substr(0,learnSkillTmp.find_first_of(" "));
2152 fprintf( brickDocFile, "<td>%s</td>\n",skill.c_str());
2154 // learn skill value
2155 if( learnSkillTmp.find(";") != -1 )
2157 sint idx = learnSkillTmp.find_first_of(" ");
2158 levelStr = learnSkillTmp.substr(idx+1,learnSkillTmp.find_first_of(";")-idx-1);
2160 else
2162 sint idx = learnSkillTmp.find_first_of(" ");
2163 levelStr = learnSkillTmp.substr(idx+1,learnSkillTmp.size()-idx);
2165 fprintf( brickDocFile, "<td>%s</td>\n",levelStr.c_str());
2168 // phrase list
2169 fprintf( brickDocFile, "<td>");
2170 map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk);
2171 if( itPhrases != brickToPhrases.end() )
2173 map<string,string>::iterator itPh;
2174 uint i;
2175 for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i )
2177 if( MultipleDocFiles )
2178 fprintf( brickDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str());
2179 else
2180 fprintf( brickDocFile,"<A HREF=\"%s.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str());
2182 if( i==2 )
2184 char type = family[0];
2185 fprintf( brickDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str());
2189 fprintf( brickDocFile, "</td></tr>\n");
2191 fprintf( brickDocFile, "</tbody><table></P>\n" );
2192 fprintf( brickDocFile, "</body></html>\n" );
2193 fclose( brickDocFile );
2197 // NAME
2199 // write header and title bar
2200 filename = DocFileNameRoot + "_name.html";
2201 FILE * brickNameDocFile = nlfopen( filename, "wt" );
2202 fprintf( brickNameDocFile,"<html><head>\n");
2203 fprintf( brickNameDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2204 fprintf( brickNameDocFile,"<title>Bricks infos</title>\n");
2205 fprintf( brickNameDocFile,"</head><body>\n");
2206 fprintf( brickNameDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n");
2207 fprintf( brickNameDocFile,"<tr>\n");
2208 fprintf( brickNameDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str());
2209 fprintf( brickNameDocFile,"<td><b>*Name*</b></td>\n");
2210 fprintf( brickNameDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str());
2211 fprintf( brickNameDocFile,"<td><b>Required Skill Name</b></td>\n");
2212 fprintf( brickNameDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2213 fprintf( brickNameDocFile,"<td><b>Learn Skill Name</b></td>\n");
2214 fprintf( brickNameDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2215 fprintf( brickNameDocFile,"<td><b>Found In Phrases</b></td>\n");
2216 fprintf( brickNameDocFile,"</tr>\n");
2218 map<string,string> nameToCode;
2219 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
2221 string brk = (*itBInf).first;
2223 if(!validateBrick(brk)) continue;
2225 // code
2226 string code = strlwr(brk.c_str());
2228 // name
2229 string name = (*itBInf).second.Text;
2230 if( !name.empty())
2231 nameToCode.insert( make_pair(name,brk) );
2234 mss::iterator itNTC;
2235 for( itNTC=nameToCode.begin(); itNTC!=nameToCode.end(); ++itNTC )
2237 itBInf=BrickInfo.find((*itNTC).second);
2239 string brk = (*itBInf).first;
2241 if(!validateBrick(brk)) continue;
2243 string skillTmp = (*itBInf).second.LearnSkills;
2244 string skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2245 CVectorSString dicoResult;
2246 Dico.lookup( skill, dicoResult, true );
2247 if(dicoResult.empty()) continue;
2249 // color
2250 string color = brickToColor[brk];
2252 // code
2253 string code = strlwr(brk.c_str());
2254 fprintf( brickNameDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str());
2256 // name
2257 string name = (*itBInf).second.Text;
2258 fprintf( brickNameDocFile, "<td>%s</td>\n",name.c_str());
2260 // family
2261 string family = brickToFamily[brk];
2262 fprintf( brickNameDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str());
2264 // required skill name
2265 fprintf( brickNameDocFile, "<td>%s</td>\n",dicoResult[0].c_str());
2267 // required skill value
2268 string levelStr;
2269 if( skillTmp.find(";") != -1 )
2271 sint idx = skillTmp.find_first_of(" ");
2272 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2274 else
2276 sint idx = skillTmp.find_first_of(" ");
2277 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2279 fprintf( brickNameDocFile, "<td>%s</td>\n",levelStr.c_str());
2281 // learn skill name
2282 skillTmp = brickToLearnSkill[brk];
2283 skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2284 fprintf( brickNameDocFile, "<td>%s</td>\n",skill.c_str());
2286 // learn skill value
2287 if( skillTmp.find(";") != -1 )
2289 sint idx = skillTmp.find_first_of(" ");
2290 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2292 else
2294 sint idx = skillTmp.find_first_of(" ");
2295 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2297 fprintf( brickNameDocFile, "<td>%s</td>\n",levelStr.c_str());
2300 // phrase list
2301 fprintf( brickNameDocFile, "<td>");
2302 map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk);
2303 if( itPhrases != brickToPhrases.end() )
2305 map<string,string>::iterator itPh;
2306 uint i;
2307 for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i )
2309 if( MultipleDocFiles )
2310 fprintf( brickNameDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str());
2311 else
2312 fprintf( brickNameDocFile,"<A HREF=\"%s.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str());
2314 if( i==2 )
2316 char type = family[0];
2317 fprintf( brickNameDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str());
2321 fprintf( brickNameDocFile, "</td></tr>\n");
2325 fprintf( brickNameDocFile, "</tbody><table></P>\n" );
2326 fprintf( brickNameDocFile, "</body></html>\n" );
2327 fclose( brickNameDocFile );
2332 // FAMILY
2334 // write header and title bar
2335 filename = DocFileNameRoot + "_family.html";
2336 FILE * brickFamilyDocFile = nlfopen( filename, "wt" );
2337 fprintf( brickFamilyDocFile,"<html><head>\n");
2338 fprintf( brickFamilyDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2339 fprintf( brickFamilyDocFile,"<title>Bricks infos</title>\n");
2340 fprintf( brickFamilyDocFile,"</head><body>\n");
2341 fprintf( brickFamilyDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n");
2342 fprintf( brickFamilyDocFile,"<tr>\n");
2343 fprintf( brickFamilyDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str());
2344 fprintf( brickFamilyDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str());
2345 fprintf( brickFamilyDocFile,"<td><b>*Family*</b></td>\n");
2346 fprintf( brickFamilyDocFile,"<td><b>Required Skill Name</b></td>\n");
2347 fprintf( brickFamilyDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2348 fprintf( brickFamilyDocFile,"<td><b>Learn Skill Name</b></td>\n");
2349 fprintf( brickFamilyDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2350 fprintf( brickFamilyDocFile,"<td><b>Found In Phrases</b></td>\n");
2351 fprintf( brickFamilyDocFile,"</tr>\n");
2354 // write infos
2355 multimap<string,string> familyToCode;
2356 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
2358 string brk = (*itBInf).first;
2360 if(!validateBrick(brk)) continue;
2362 // family
2363 string family = brickToFamily[brk];
2365 familyToCode.insert( make_pair(family,brk) );
2368 multimap<string,string>::iterator itFTC;
2369 for( itFTC=familyToCode.begin(); itFTC!=familyToCode.end(); ++itFTC )
2371 itBInf=BrickInfo.find((*itFTC).second);
2373 string brk = (*itBInf).first;
2375 if(!validateBrick(brk)) continue;
2377 string skillTmp = (*itBInf).second.LearnSkills;
2378 string skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2379 CVectorSString dicoResult;
2380 Dico.lookup( skill, dicoResult, true );
2381 if(dicoResult.empty()) continue;
2383 // color
2384 string color = brickToColor[brk];
2386 // code
2387 string code = strlwr(brk.c_str());
2388 fprintf( brickFamilyDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str());
2390 // name
2391 string name = (*itBInf).second.Text;
2392 fprintf( brickFamilyDocFile, "<td>%s</td>\n",name.c_str());
2394 // family
2395 string family = brickToFamily[brk];
2396 fprintf( brickFamilyDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str());
2398 // required skill name
2399 fprintf( brickFamilyDocFile, "<td>%s</td>\n",dicoResult[0].c_str());
2401 // required skill value
2402 string levelStr;
2403 if( skillTmp.find(";") != -1 )
2405 sint idx = skillTmp.find_first_of(" ");
2406 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2408 else
2410 sint idx = skillTmp.find_first_of(" ");
2411 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2413 fprintf( brickFamilyDocFile, "<td>%s</td>\n",levelStr.c_str());
2415 // learn skill name
2416 skillTmp = brickToLearnSkill[brk];
2417 skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2418 fprintf( brickFamilyDocFile, "<td>%s</td>\n",skill.c_str());
2420 // learn skill value
2421 if( skillTmp.find(";") != -1 )
2423 sint idx = skillTmp.find_first_of(" ");
2424 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2426 else
2428 sint idx = skillTmp.find_first_of(" ");
2429 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2431 fprintf( brickFamilyDocFile, "<td>%s</td>\n",levelStr.c_str());
2434 // phrase list
2435 fprintf( brickFamilyDocFile, "<td>");
2436 map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk);
2437 if( itPhrases != brickToPhrases.end() )
2439 map<string,string>::iterator itPh;
2440 uint i;
2441 for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i )
2443 if( MultipleDocFiles )
2444 fprintf( brickFamilyDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str());
2445 else
2446 fprintf( brickFamilyDocFile,"<A HREF=\"%s.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str());
2448 if( i==2 )
2450 char type = family[0];
2451 fprintf( brickFamilyDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str());
2455 fprintf( brickFamilyDocFile, "</td></tr>\n");
2457 fprintf( brickFamilyDocFile, "</tbody><table></P>\n" );
2458 fprintf( brickFamilyDocFile, "</body></html>\n" );
2459 fclose( brickFamilyDocFile );
2464 // REQUIRED SKILL VALUE
2466 // write header and title bar
2467 filename = DocFileNameRoot + "_required_skill_value.html";
2468 FILE * brickRequiredDocFile = nlfopen( filename, "wt" );
2469 fprintf( brickRequiredDocFile,"<html><head>\n");
2470 fprintf( brickRequiredDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2471 fprintf( brickRequiredDocFile,"<title>Bricks infos</title>\n");
2472 fprintf( brickRequiredDocFile,"</head><body>\n");
2473 fprintf( brickRequiredDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n");
2474 fprintf( brickRequiredDocFile,"<tr>\n");
2475 fprintf( brickRequiredDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str());
2476 fprintf( brickRequiredDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str());
2477 fprintf( brickRequiredDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str());
2478 fprintf( brickRequiredDocFile,"<td><b>Required Skill Name</b></td>\n");
2479 fprintf( brickRequiredDocFile,"<td><b>*Required Skill Value*</b></td>\n");
2480 fprintf( brickRequiredDocFile,"<td><b>Learn Skill Name</b></td>\n");
2481 fprintf( brickRequiredDocFile,"<td><b><a href=\"%s_learn_skill_value.html\">Learn Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2482 fprintf( brickRequiredDocFile,"<td><b>Found In Phrases</b></td>\n");
2483 fprintf( brickRequiredDocFile,"</tr>\n");
2486 // write infos
2487 multimap<uint,string> requiredSkillValueToCode;
2488 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
2490 string brk = (*itBInf).first;
2492 if(!validateBrick(brk)) continue;
2494 // required skill value
2495 string skillTmp = (*itBInf).second.LearnSkills;
2496 string levelStr;
2497 if( skillTmp.find(";") != -1 )
2499 sint idx = skillTmp.find_first_of(" ");
2500 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2502 else
2504 sint idx = skillTmp.find_first_of(" ");
2505 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2507 uint level = atoi(levelStr.c_str());
2509 requiredSkillValueToCode.insert( make_pair(level,brk) );
2512 multimap<uint,string>::iterator itRTC;
2513 for( itRTC=requiredSkillValueToCode.begin(); itRTC!=requiredSkillValueToCode.end(); ++itRTC )
2515 itBInf=BrickInfo.find((*itRTC).second);
2517 string brk = (*itBInf).first;
2519 if(!validateBrick(brk)) continue;
2521 string skillTmp = (*itBInf).second.LearnSkills;
2522 string skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2523 CVectorSString dicoResult;
2524 Dico.lookup( skill, dicoResult, true );
2525 if(dicoResult.empty()) continue;
2527 // color
2528 string color = brickToColor[brk];
2530 // code
2531 string code = strlwr(brk.c_str());
2532 fprintf( brickRequiredDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str());
2534 // name
2535 string name = (*itBInf).second.Text;
2536 fprintf( brickRequiredDocFile, "<td>%s</td>\n",name.c_str());
2538 // family
2539 string family = brickToFamily[brk];
2540 fprintf( brickRequiredDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str());
2542 // required skill name
2543 fprintf( brickRequiredDocFile, "<td>%s</td>\n",dicoResult[0].c_str());
2545 // required skill value
2546 string levelStr;
2547 if( skillTmp.find(";") != -1 )
2549 sint idx = skillTmp.find_first_of(" ");
2550 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2552 else
2554 sint idx = skillTmp.find_first_of(" ");
2555 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2557 fprintf( brickRequiredDocFile, "<td>%s</td>\n",levelStr.c_str());
2559 // learn skill name
2560 skillTmp = brickToLearnSkill[brk];
2561 skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2562 fprintf( brickRequiredDocFile, "<td>%s</td>\n",skill.c_str());
2564 // learn skill value
2565 if( skillTmp.find(";") != -1 )
2567 sint idx = skillTmp.find_first_of(" ");
2568 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2570 else
2572 sint idx = skillTmp.find_first_of(" ");
2573 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2575 fprintf( brickRequiredDocFile, "<td>%s</td>\n",levelStr.c_str());
2578 // phrase list
2579 fprintf( brickRequiredDocFile, "<td>");
2580 map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk);
2581 if( itPhrases != brickToPhrases.end() )
2583 map<string,string>::iterator itPh;
2584 uint i;
2585 for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i )
2587 if( MultipleDocFiles )
2588 fprintf( brickRequiredDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str());
2589 else
2590 fprintf( brickRequiredDocFile,"<A HREF=\"%s.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str());
2592 if( i==2 )
2594 char type = family[0];
2595 fprintf( brickRequiredDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str());
2599 fprintf( brickRequiredDocFile, "</td></tr>\n");
2601 fprintf( brickRequiredDocFile, "</tbody><table></P>\n" );
2602 fprintf( brickRequiredDocFile, "</body></html>\n" );
2603 fclose( brickRequiredDocFile );
2607 // LEARN SKILL VALUE
2609 // write header and title bar
2610 filename = DocFileNameRoot + "_learn_skill_value.html";
2611 FILE * brickLearnDocFile = nlfopen( filename, "wt" );
2612 fprintf( brickLearnDocFile,"<html><head>\n");
2613 fprintf( brickLearnDocFile,"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
2614 fprintf( brickLearnDocFile,"<title>Bricks infos</title>\n");
2615 fprintf( brickLearnDocFile,"</head><body>\n");
2616 fprintf( brickLearnDocFile,"<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n");
2617 fprintf( brickLearnDocFile,"<tr>\n");
2618 fprintf( brickLearnDocFile,"<td><b><a href=\"%s.html\">Code</a></b></td>\n",DocFileNameRoot.c_str());
2619 fprintf( brickLearnDocFile,"<td><b><a href=\"%s_name.html\">Name</a></b></td>\n",DocFileNameRoot.c_str());
2620 fprintf( brickLearnDocFile,"<td><b><a href=\"%s_family.html\">Family</a></b></td>\n",DocFileNameRoot.c_str());
2621 fprintf( brickLearnDocFile,"<td><b>Required Skill Name</b></td>\n");
2622 fprintf( brickLearnDocFile,"<td><b><a href=\"%s_required_skill_value.html\">Required Skill Value</a></b></td>\n",DocFileNameRoot.c_str());
2623 fprintf( brickLearnDocFile,"<td><b>Learn Skill Name</b></td>\n");
2624 fprintf( brickLearnDocFile,"<td><b>*Learn Skill Value*</b></td>\n");
2625 fprintf( brickLearnDocFile,"<td><b>Found In Phrases</b></td>\n");
2626 fprintf( brickLearnDocFile,"</tr>\n");
2629 // write infos
2630 multimap<uint,string> learnSkillValueToCode;
2631 for( itBInf=BrickInfo.begin(); itBInf!=BrickInfo.end(); ++itBInf )
2633 string brk = (*itBInf).first;
2635 if(!validateBrick(brk)) continue;
2637 // learn skill value
2638 string skillTmp = brickToLearnSkill[brk];
2639 string levelStr;
2640 if( skillTmp.find(";") != -1 )
2642 sint idx = skillTmp.find_first_of(" ");
2643 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2645 else
2647 sint idx = skillTmp.find_first_of(" ");
2648 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2650 uint level = atoi(levelStr.c_str());
2652 learnSkillValueToCode.insert( make_pair(level,brk) );
2655 multimap<uint,string>::iterator itLTC;
2656 for( itLTC=learnSkillValueToCode.begin(); itLTC!=learnSkillValueToCode.end(); ++itLTC )
2658 itBInf=BrickInfo.find((*itLTC).second);
2660 string brk = (*itBInf).first;
2662 if(!validateBrick(brk)) continue;
2664 string skillTmp = (*itBInf).second.LearnSkills;
2665 string skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2666 CVectorSString dicoResult;
2667 Dico.lookup( skill, dicoResult, true );
2668 if(dicoResult.empty()) continue;
2670 // color
2671 string color = brickToColor[brk];
2673 // code
2674 string code = strlwr(brk.c_str());
2675 fprintf( brickLearnDocFile, "<tr><td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),code.c_str());
2677 // name
2678 string name = (*itBInf).second.Text;
2679 fprintf( brickLearnDocFile, "<td>%s</td>\n",name.c_str());
2681 // family
2682 string family = brickToFamily[brk];
2683 fprintf( brickLearnDocFile, "<td><FONT COLOR=\"%s\">%s</FONT></td>\n",color.c_str(),family.c_str());
2685 // required skill name
2686 fprintf( brickLearnDocFile, "<td>%s</td>\n",dicoResult[0].c_str());
2688 // required skill value
2689 string levelStr;
2690 if( skillTmp.find(";") != -1 )
2692 sint idx = skillTmp.find_first_of(" ");
2693 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2695 else
2697 sint idx = skillTmp.find_first_of(" ");
2698 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2700 fprintf( brickLearnDocFile, "<td>%s</td>\n",levelStr.c_str());
2702 // learn skill name
2703 skillTmp = brickToLearnSkill[brk];
2704 skill = skillTmp.substr(0,skillTmp.find_first_of(" "));
2705 fprintf( brickLearnDocFile, "<td>%s</td>\n",skill.c_str());
2707 // learn skill value
2708 if( skillTmp.find(";") != -1 )
2710 sint idx = skillTmp.find_first_of(" ");
2711 levelStr = skillTmp.substr(idx+1,skillTmp.find_first_of(";")-idx-1);
2713 else
2715 sint idx = skillTmp.find_first_of(" ");
2716 levelStr = skillTmp.substr(idx+1,skillTmp.size()-idx);
2718 fprintf( brickLearnDocFile, "<td>%s</td>\n",levelStr.c_str());
2721 // phrase list
2722 fprintf( brickLearnDocFile, "<td>");
2723 map<string,map<string,string> >::iterator itPhrases = brickToPhrases.find(brk);
2724 if( itPhrases != brickToPhrases.end() )
2726 map<string,string>::iterator itPh;
2727 uint i;
2728 for( itPh=(*itPhrases).second.begin(),i=0; itPh!=(*itPhrases).second.end() && i<2; ++itPh,++i )
2730 if( MultipleDocFiles )
2731 fprintf( brickLearnDocFile,"<A HREF=\"%s_%c.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first[7],(*itPh).first.c_str(),(*itPh).first.c_str());
2732 else
2733 fprintf( brickLearnDocFile,"<A HREF=\"%s.html#%s\">%s</A>,&nbsp&nbsp",DocFileName.c_str(),(*itPh).first.c_str(),(*itPh).first.c_str());
2735 if( i==2 )
2737 char type = family[0];
2738 fprintf( brickLearnDocFile,"[<A HREF=\"%s_%c.html#%s\">...</A>]",DocFileNameRoot.c_str(),type,brk.c_str());
2742 fprintf( brickLearnDocFile, "</td></tr>\n");
2744 fprintf( brickLearnDocFile, "</tbody><table></P>\n" );
2745 fprintf( brickLearnDocFile, "</body></html>\n" );
2746 fclose( brickLearnDocFile );
2751 return 0;
2753 } // main //