@ -9,6 +9,7 @@
# include <components/esm_store/store.hpp>
# include <components/esm_store/store.hpp>
# include "../mwworld/class.hpp"
# include "../mwworld/class.hpp"
# include "../mwworld/environment.hpp"
# include "../mwworld/environment.hpp"
# include "../mwworld/world.hpp"
# include "../mwworld/world.hpp"
@ -16,6 +17,10 @@
# include "../mwworld/player.hpp"
# include "../mwworld/player.hpp"
# include "../mwinput/inputmanager.hpp"
# include "../mwinput/inputmanager.hpp"
# include "../mwgui/dialogue.hpp"
# include "../mwgui/window_manager.hpp"
# include "journal.hpp"
# include <iostream>
# include <iostream>
@ -31,6 +36,7 @@ namespace
return lowerCase ;
return lowerCase ;
}
}
template < typename T1 , typename T2 >
template < typename T1 , typename T2 >
bool selectCompare ( char comp , T1 value1 , T2 value2 )
bool selectCompare ( char comp , T1 value1 , T2 value2 )
{
{
@ -115,6 +121,14 @@ namespace
namespace MWDialogue
namespace MWDialogue
{
{
//helper function
std : : string : : size_type find_str_ci ( const std : : string & str , const std : : string & substr , size_t pos )
{
return toLower ( str ) . find ( toLower ( substr ) , pos ) ;
}
bool DialogueManager : : isMatching ( const MWWorld : : Ptr & actor ,
bool DialogueManager : : isMatching ( const MWWorld : : Ptr & actor ,
const ESM : : DialInfo : : SelectStruct & select ) const
const ESM : : DialInfo : : SelectStruct & select ) const
{
{
@ -126,7 +140,7 @@ namespace MWDialogue
std : : string name = select . selectRule . substr ( 5 ) ;
std : : string name = select . selectRule . substr ( 5 ) ;
// TODO types 4, 5, 6, 7, 8, 9, A, B, C
// TODO types 4, 5, 6, 7, 8, 9, A, B, C
//new TOTO: 5,6,9
switch ( type )
switch ( type )
{
{
case ' 1 ' : // function
case ' 1 ' : // function
@ -173,6 +187,116 @@ namespace MWDialogue
return true ;
return true ;
case ' 4 ' : //journal
if ( select . type = = ESM : : VT_Int )
{
//std::cout << "vtint: " << select.i << std::endl;
bool isInJournal ;
if ( mEnvironment . mJournal - > begin ( ) ! = mEnvironment . mJournal - > end ( ) )
{
for ( std : : deque < MWDialogue : : StampedJournalEntry > : : const_iterator it = mEnvironment . mJournal - > begin ( ) ; it ! = mEnvironment . mJournal - > end ( ) ; it + + )
{
if ( it - > mTopic = = name ) isInJournal = true ;
}
}
else
isInJournal = false ;
if ( ! selectCompare < int , int > ( comp , int ( isInJournal ) , select . i ) ) return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
case ' 7 ' : // not ID
if ( select . type = = ESM : : VT_String | | select . type = = ESM : : VT_Int ) //bug in morrowind here? it's not a short, it's a string
{
int isID = int ( toLower ( name ) = = toLower ( MWWorld : : Class : : get ( actor ) . getId ( actor ) ) ) ;
if ( selectCompare < int , int > ( comp , ! isID , select . i ) ) return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
case ' 8 ' : // not faction
if ( select . type = = ESM : : VT_Int )
{
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * npc = actor . get < ESM : : NPC > ( ) ;
int isFaction = int ( toLower ( npc - > base - > faction ) = = toLower ( name ) ) ;
if ( selectCompare < int , int > ( comp , ! isFaction , select . i ) )
return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
case ' 9 ' : // not class
if ( select . type = = ESM : : VT_Int )
{
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * npc = actor . get < ESM : : NPC > ( ) ;
int isClass = int ( toLower ( npc - > base - > cls ) = = toLower ( name ) ) ;
if ( selectCompare < int , int > ( comp , ! isClass , select . i ) )
return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
case ' A ' : //not Race
if ( select . type = = ESM : : VT_Int )
{
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * npc = actor . get < ESM : : NPC > ( ) ;
int isRace = int ( toLower ( npc - > base - > race ) = = toLower ( name ) ) ;
//std::cout << "isRace"<<isRace; mEnvironment.mWorld
if ( selectCompare < int , int > ( comp , ! isRace , select . i ) )
return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
case ' B ' : //not Cell
if ( select . type = = ESM : : VT_Int )
{
int isCell = int ( toLower ( actor . getCell ( ) - > cell - > name ) = = toLower ( name ) ) ;
if ( selectCompare < int , int > ( comp , ! isCell , select . i ) )
return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
case ' C ' : //not local
if ( select . type = = ESM : : VT_Short | | select . type = = ESM : : VT_Int | |
select . type = = ESM : : VT_Long )
{
if ( checkLocal ( comp , toLower ( name ) , select . i , actor ,
mEnvironment . mWorld - > getStore ( ) ) )
return false ;
}
else if ( select . type = = ESM : : VT_Float )
{
if ( checkLocal ( comp , toLower ( name ) , select . f , actor ,
mEnvironment . mWorld - > getStore ( ) ) )
return false ;
}
else
throw std : : runtime_error (
" unsupported variable type in dialogue info select " ) ;
return true ;
default :
default :
std : : cout < < " unchecked select: " < < type < < " " < < comp < < " " < < name < < std : : endl ;
std : : cout < < " unchecked select: " < < type < < " " < < comp < < " " < < name < < std : : endl ;
@ -184,11 +308,13 @@ namespace MWDialogue
bool DialogueManager : : isMatching ( const MWWorld : : Ptr & actor , const ESM : : DialInfo & info ) const
bool DialogueManager : : isMatching ( const MWWorld : : Ptr & actor , const ESM : : DialInfo & info ) const
{
{
//bool return true;//does the actor knows the topic?
// actor id
// actor id
if ( ! info . actor . empty ( ) )
if ( ! info . actor . empty ( ) )
if ( toLower ( info . actor ) ! = MWWorld : : Class : : get ( actor ) . getId ( actor ) )
if ( toLower ( info . actor ) ! = MWWorld : : Class : : get ( actor ) . getId ( actor ) )
return false ;
return false ;
//NPC race
if ( ! info . race . empty ( ) )
if ( ! info . race . empty ( ) )
{
{
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * cellRef = actor . get < ESM : : NPC > ( ) ;
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * cellRef = actor . get < ESM : : NPC > ( ) ;
@ -200,6 +326,7 @@ namespace MWDialogue
return false ;
return false ;
}
}
//NPC class
if ( ! info . clas . empty ( ) )
if ( ! info . clas . empty ( ) )
{
{
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * cellRef = actor . get < ESM : : NPC > ( ) ;
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * cellRef = actor . get < ESM : : NPC > ( ) ;
@ -211,6 +338,7 @@ namespace MWDialogue
return false ;
return false ;
}
}
//NPC faction
if ( ! info . npcFaction . empty ( ) )
if ( ! info . npcFaction . empty ( ) )
{
{
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * cellRef = actor . get < ESM : : NPC > ( ) ;
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * cellRef = actor . get < ESM : : NPC > ( ) ;
@ -220,10 +348,32 @@ namespace MWDialogue
if ( toLower ( info . npcFaction ) ! = toLower ( cellRef - > base - > faction ) )
if ( toLower ( info . npcFaction ) ! = toLower ( cellRef - > base - > faction ) )
return false ;
return false ;
//check NPC rank
if ( cellRef - > base - > npdt52 . gold ! = - 10 )
{
if ( cellRef - > base - > npdt52 . rank < info . data . rank ) return false ;
}
else
{
if ( cellRef - > base - > npdt12 . rank < info . data . rank ) return false ;
}
}
}
// TODO check player faction
// TODO check player faction
//check gender
ESMS : : LiveCellRef < ESM : : NPC , MWWorld : : RefData > * npc = actor . get < ESM : : NPC > ( ) ;
if ( npc - > base - > flags & npc - > base - > Female )
{
if ( static_cast < int > ( info . data . gender ) = = 0 ) return false ;
}
else
{
if ( static_cast < int > ( info . data . gender ) = = 1 ) return false ;
}
// check cell
// check cell
if ( ! info . cell . empty ( ) )
if ( ! info . cell . empty ( ) )
if ( mEnvironment . mWorld - > getPlayer ( ) . getPlayer ( ) . getCell ( ) - > cell - > name ! = info . cell )
if ( mEnvironment . mWorld - > getPlayer ( ) . getPlayer ( ) . getCell ( ) - > cell - > name ! = info . cell )
@ -236,35 +386,72 @@ namespace MWDialogue
if ( ! isMatching ( actor , * iter ) )
if ( ! isMatching ( actor , * iter ) )
return false ;
return false ;
std : : cout
/*std::cout
< < " unchecked entries: " < < std : : endl
< < " unchecked entries: " < < std : : endl
< < " player faction: " < < info . pcFaction < < std : : endl
< < " player faction: " < < info . pcFaction < < std : : endl
< < " disposition: " < < info . data . disposition < < std : : endl
< < " disposition: " < < info . data . disposition < < std : : endl
< < " NPC rank: " < < static_cast < int > ( info . data . rank ) < < std : : endl
< < " NPC rank: " < < static_cast < int > ( info . data . rank ) < < std : : endl
< < " gender: " < < static_cast < int > ( info . data . gender ) < < std : : endl
< < " gender: " < < static_cast < int > ( info . data . gender ) < < std : : endl
< < " PC rank: " < < static_cast < int > ( info . data . PCrank ) < < std : : endl ;
< < " PC rank: " < < static_cast < int > ( info . data . PCrank ) < < std : : endl ; */
return true ;
return true ;
}
}
DialogueManager : : DialogueManager ( MWWorld : : Environment & environment ) : mEnvironment ( environment ) { }
DialogueManager : : DialogueManager ( MWWorld : : Environment & environment ) : mEnvironment ( environment ) { }
void DialogueManager : : addTopic ( std : : string topic )
{
knownTopics [ toLower ( topic ) ] = true ;
}
void DialogueManager : : startDialogue ( const MWWorld : : Ptr & actor )
void DialogueManager : : startDialogue ( const MWWorld : : Ptr & actor )
{
{
std : : cout < < " talking with " < < MWWorld : : Class : : get ( actor ) . getName ( actor ) < < std : : endl ;
std : : cout < < " talking with " < < MWWorld : : Class : : get ( actor ) . getName ( actor ) < < std : : endl ;
const ESM : : Dialogue * dialogue = mEnvironment . mWorld - > getStore ( ) . dialogs . find ( " hello " ) ;
//initialise the GUI
mEnvironment . mInputManager - > setGuiMode ( MWGui : : GM_Dialogue ) ;
MWGui : : DialogueWindow * win = mEnvironment . mWindowManager - > getDialogueWindow ( ) ;
win - > startDialogue ( MWWorld : : Class : : get ( actor ) . getName ( actor ) ) ;
for ( std : : vector < ESM : : DialInfo > : : const_iterator iter ( dialogue - > mInfo . begin ( ) ) ;
actorKnownTopics . clear ( ) ;
iter ! = dialogue - > mInfo . end ( ) ; + + iter )
ESMS : : RecListT < ESM : : Dialogue > : : MapType dialogueList = mEnvironment . mWorld - > getStore ( ) . dialogs . list ;
for ( ESMS : : RecListT < ESM : : Dialogue > : : MapType : : iterator it = dialogueList . begin ( ) ; it ! = dialogueList . end ( ) ; it + + )
{
ESM : : Dialogue ndialogue = it - > second ;
if ( ndialogue . type = = ESM : : Dialogue : : Type : : Topic )
{
for ( std : : vector < ESM : : DialInfo > : : const_iterator iter ( it - > second . mInfo . begin ( ) ) ;
iter ! = it - > second . mInfo . end ( ) ; + + iter )
{
{
if ( isMatching ( actor , * iter ) )
if ( isMatching ( actor , * iter ) )
{
{
// start dialogue
actorKnownTopics [ it - > first ] = iter - > response ;
std : : cout < < " found matching info record " < < std : : endl ;
if ( knownTopics . find ( toLower ( it - > first ) ) ! = knownTopics . end ( ) )
{
std : : cout < < " response: " < < iter - > response < < std : : endl ;
MWGui : : DialogueWindow * win = mEnvironment . mWindowManager - > getDialogueWindow ( ) ;
win - > addKeyword ( it - > first , iter - > response ) ;
//std::cout << it->first;
//std::cout << "match found!!";
break ;
}
}
}
}
}
//ESMS::RecListT<ESM::Dialogue>::MapType dialogueList = mEnvironment.mWorld->getStore().dialogs.list;
bool greetingFound = false ;
for ( ESMS : : RecListT < ESM : : Dialogue > : : MapType : : iterator it = dialogueList . begin ( ) ; it ! = dialogueList . end ( ) ; it + + )
{
ESM : : Dialogue ndialogue = it - > second ;
if ( ndialogue . type = = ESM : : Dialogue : : Type : : Greeting )
{
if ( greetingFound ) break ;
for ( std : : vector < ESM : : DialInfo > : : const_iterator iter ( it - > second . mInfo . begin ( ) ) ;
iter ! = it - > second . mInfo . end ( ) ; + + iter )
{
if ( isMatching ( actor , * iter ) )
{
if ( ! iter - > sound . empty ( ) )
if ( ! iter - > sound . empty ( ) )
{
{
// TODO play sound
// TODO play sound
@ -272,14 +459,53 @@ namespace MWDialogue
if ( ! iter - > resultScript . empty ( ) )
if ( ! iter - > resultScript . empty ( ) )
{
{
std : : cout < < " script: " < < iter - > resultScript < < std : : endl ;
//std::cout << "script: " << iter->resultScript << std::endl;
// TODO execute script
// TODO execute script
}
}
std : : string text = iter - > response ;
mEnvironment . mInputManager - > setGuiMode ( MWGui : : GM_Dialogue ) ;
std : : map < std : : string , std : : string > : : iterator it ;
for ( it = actorKnownTopics . begin ( ) ; it ! = actorKnownTopics . end ( ) ; it + + )
{
if ( find_str_ci ( text , it - > first , 0 ) ! = std : : string : : npos )
{
//std::cout << "fouuuuuuuuuuund";
knownTopics [ it - > first ] = true ;
MWGui : : DialogueWindow * win2 = mEnvironment . mWindowManager - > getDialogueWindow ( ) ;
win2 - > addKeyword ( it - > first , it - > second ) ;
}
}
win - > addText ( iter - > response ) ;
greetingFound = true ;
break ;
break ;
}
}
}
}
}
}
}
}
void DialogueManager : : keywordSelected ( std : : string keyword )
{
std : : string text = actorKnownTopics [ keyword ] ;
std : : map < std : : string , std : : string > : : iterator it ;
for ( it = actorKnownTopics . begin ( ) ; it ! = actorKnownTopics . end ( ) ; it + + )
{
if ( find_str_ci ( text , it - > first , 0 ) ! = std : : string : : npos )
{
knownTopics [ it - > first ] = true ;
MWGui : : DialogueWindow * win = mEnvironment . mWindowManager - > getDialogueWindow ( ) ;
win - > addKeyword ( it - > first , it - > second ) ;
}
}
}
void DialogueManager : : goodbyeSelected ( )
{
mEnvironment . mInputManager - > setGuiMode ( MWGui : : GM_Game ) ;
}
void DialogueManager : : questionAnswered ( std : : string answere )
{
std : : cout < < " and the ansere is... " < < answere ;
}
}
}