// Ryzom - MMORPG Framework
// 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 .
// 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
#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
#include
#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
#include
#include
#include
// stl
#include
\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 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 ] [-o ] [-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 (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, ("\n\nSummary of " + DocFileNameRoot + "\n\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], ("\n\n" + DocFileName + toString( " - %c", (char)('A'+l) ) + "\n\n").c_str() );
fprintf( indexFile, ("" + (char)('A'+l) + " ").c_str() );
}
}
else
{
// One single HTML file
fprintf( indexFile, ("Go to action details").c_str() );
PhraseDocFiles[0] = nlfopen( DocFileName + ".html", "wt" );
fprintf( PhraseDocFiles[0], ("\n\n" + DocFileName + "\n\n").c_str() );
for ( uint l=1; l!=26; ++l )
{
PhraseDocFiles[l] = PhraseDocFiles[0];
}
}
fprintf( indexFile, ("
Go to action by skill value\n").c_str() );
fprintf( indexFile, ("
Go to action by skill value (detail)\n").c_str() );
fprintf( indexFile, ("
Go to action by skill
\n").c_str() );
if( GenerateBrickProgression )
{
fprintf( indexFile, ("
Go to brick list
\n").c_str() );
}
produceDocFromExistingPhrases();
for ( map< uint, pair >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
{
const string& phraseCode = (*ip).second.first;
string link = Hypertext ? toString( "%s", getLink(phraseCode).c_str(), phraseCode.c_str() ) : "" + phraseCode + "";
PhraseCodeToLink.insert( make_pair(phraseCode,link) );
}
// Summary (errors in phrases)
fprintf( indexFile, "
\n" );
fprintf( indexFile, ("Summary of " + DocFileName + "
\n").c_str() );
if ( NbSheetsGenTries != 0 )
fprintf( indexFile, "%u valid sheets written on %u
\n", NbSheetsWritten, NbSheetsGenTries );
if ( NbSheetsRead != 0 )
fprintf( indexFile, "%u sheets read
\n", NbSheetsRead );
fprintf( indexFile, "%u invalid sheets rejected", NbSheetsRejected );
if ( ! PhrasesWithInvalidCost.empty() )
{
fprintf( indexFile, "
Phrases with invalid sabrina cost:
\n" );
for ( vs::const_iterator iip=PhrasesWithInvalidCost.begin(); iip!=PhrasesWithInvalidCost.end(); ++iip )
{
string link = Hypertext ? toString( "%s", getLink(*iip).c_str(), (*iip).c_str() ) : "" + (*iip) + "";
fprintf( indexFile, "%s
\n", link.c_str() );
}
fprintf( indexFile, "
\n" );
}
else
{
fprintf( indexFile, "All phrases have valid sabrina cost.
\n" );
}
if ( ! InvalidPhrases.empty() )
{
fprintf( indexFile, "Grammatically invalid phrases:
\n" );
for ( vs::const_iterator iip=InvalidPhrases.begin(); iip!=InvalidPhrases.end(); ++iip )
{
string link = Hypertext ? toString( "%s", getLink(*iip).c_str(), (*iip).c_str() ) : "" + (*iip) + "";
fprintf( indexFile, "%s
\n", link.c_str() );
}
fprintf( indexFile, "
\n" );
}
else
{
fprintf( indexFile, "All phrases are grammatically valid.
\n" );
}
fprintf( indexFile, "\n" );
fclose( indexFile );
if ( MultipleDocFiles )
{
for ( uint l=0; l!=26; ++l )
{
fprintf( PhraseDocFiles[l], "\n" );
fclose( PhraseDocFiles[l] );
}
}
else
{
fprintf( PhraseDocFiles[0], "\n" );
fclose( PhraseDocFiles[0] );
}
}
} // makeIndexFile //
//-----------------------------------------------
// makeActionsBySkillGroupFile
//
//-----------------------------------------------
void makeActionsBySkillGroupFile()
{
// progression by skill
FILE * actionsBySkillGroupFile = nlfopen( DocFileName + "__by_skill.html", "wt" );
if( actionsBySkillGroupFile )
{
fprintf( actionsBySkillGroupFile, ("\n\nProgression of " + DocFileName + "\n\n").c_str() );
fprintf( actionsBySkillGroupFile, "
\n" );
fprintf( actionsBySkillGroupFile, "ACTIONS BY SKILL GROUP:
\n
\n" );
map > phrasesBySkill;
for ( map< uint, pair >::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 >::iterator it = phrasesBySkill.find(skillName);
if( it != phrasesBySkill.end() )
{
(*it).second.insert(make_pair(skillValue,phraseCode));
}
else
{
multimap m;
m.insert(make_pair(skillValue,phraseCode));
phrasesBySkill.insert( make_pair(skillName,m) );
}
}
map >::iterator itPhrasesBySkill;
for( itPhrasesBySkill = phrasesBySkill.begin(); itPhrasesBySkill != phrasesBySkill.end(); ++itPhrasesBySkill )
{
CVectorSString dicoResult;
Dico.lookup( (*itPhrasesBySkill).first, dicoResult, true );
if( !dicoResult.empty() )
fprintf( actionsBySkillGroupFile, "%s |
\n", (*itPhrasesBySkill).first.c_str(),dicoResult[0].c_str());
else
fprintf( actionsBySkillGroupFile, "%s |
\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, "%s
|
\n", (*itPhrasesBySkill).first.c_str(), dicoResult[0].c_str() );
else
fprintf( actionsBySkillGroupFile, "%s
|
\n", (*itPhrasesBySkill).first.c_str(),(*itPhrasesBySkill).first.c_str() );
multimap::iterator it;
for( it = (*itPhrasesBySkill).second.begin(); it != (*itPhrasesBySkill).second.end(); ++it )
{
fprintf( actionsBySkillGroupFile, "%d | %s | %s
|
\n", (*it).first, PhraseCodeToLink[(*it).second].c_str(), PhraseTitles[(*it).second].c_str());
}
}
fprintf( actionsBySkillGroupFile, "\n" );
fprintf( actionsBySkillGroupFile, "\n" );
fclose( actionsBySkillGroupFile );
}
} // makeActionsBySkillGroupFile //
//-----------------------------------------------
// makeActionsBySkillValueFile
//
//-----------------------------------------------
void makeActionsBySkillValueFile()
{
FILE * actionsBySkillValueFile = fopen( (DocFileName + "__by_skill_value.html").c_str(), "wt" );
if( actionsBySkillValueFile )
{
fprintf( actionsBySkillValueFile, ("\n\nProgression of " + DocFileName + "\n\n").c_str() );
// Progression (phrases sorted by skill value)
fprintf( actionsBySkillValueFile, "
\n" );
fprintf( actionsBySkillValueFile, "ACTIONS BY SKILL VALUE: [detail]\n
\n",(DocFileName + "__by_skill_value_detail.html").c_str() );
fprintf( actionsBySkillValueFile, "File | Name | Skill needed
|
\n");
map phraseCodeToLink;
for ( map< uint, pair >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
{
const string& phraseCode = (*ip).second.first;
fprintf( actionsBySkillValueFile, "%s | %s | %s
|
\n", PhraseCodeToLink[phraseCode].c_str(), /*newbrickTitle.c_str(),*/ PhraseTitles[phraseCode].c_str(), (*ip).second.second.c_str() );
}
fprintf( actionsBySkillValueFile, "\n" );
fprintf( actionsBySkillValueFile, "\n" );
fclose( actionsBySkillValueFile );
}
} // makeActionsBySkillValueFile //
//-----------------------------------------------
// makeActionsBySkillValueDetailFile
//
//-----------------------------------------------
void makeActionsBySkillValueDetailFile()
{
FILE * actionsBySkillValueDetailFile = nlfopen( DocFileName + "__by_skill_value_detail.html", "wt" );
if( actionsBySkillValueDetailFile )
{
fprintf( actionsBySkillValueDetailFile, ("\n\nProgression of " + DocFileName + "\n\n").c_str() );
// Progression summary (phrases sorted by skill value)
fprintf( actionsBySkillValueDetailFile, "
\n" );
fprintf( actionsBySkillValueDetailFile, "ACTIONS BY SKILL VALUE:
\n
\n" );
fprintf( actionsBySkillValueDetailFile, "File | Name | Skill needed
| Sabrina cost | Bricks ... |
\n");
set effects;
map > effectAndModifiers;
for ( map< uint, pair >::const_iterator ip=Progression.begin(); ip!=Progression.end(); ++ip )
{
const string& phraseCode = (*ip).second.first;
fprintf( actionsBySkillValueDetailFile, "%s | %s | %s | %d | ",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 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, "%s | ",color.c_str(),text.c_str());
}
}
else
{
nlerror("not found : %s",phraseCode.c_str());
}
fprintf( actionsBySkillValueDetailFile, "
\n");
}
fprintf( actionsBySkillValueDetailFile, "\n" );
fprintf( actionsBySkillValueDetailFile, "\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