From: Keith F. <ven...@us...> - 2005-05-14 14:21:30
|
Update of /cvsroot/planeshift/planeshift/src/server/bulkobjects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3936/server/bulkobjects Modified Files: dictionary.cpp dictionary.h psnpcdialog.cpp psnpcdialog.h Log Message: Refactored and restructured a lot of npc dialog code. The basics are working again but generalizations and trigger groups still need testing, which I plan to do this afternoon. Index: dictionary.cpp =================================================================== RCS file: /cvsroot/planeshift/planeshift/src/server/bulkobjects/dictionary.cpp,v retrieving revision 1.52 retrieving revision 1.53 diff -C2 -d -r1.52 -r1.53 *** dictionary.cpp 9 May 2005 07:37:41 -0000 1.52 --- dictionary.cpp 14 May 2005 14:21:19 -0000 1.53 *************** *** 109,119 **** } ! void NPCDialogDict::AddPhrase(const char *phrase, const char *synonym, const char *moreGeneral) { ! if (FindPhrase(phrase) != NULL) return; ! NPCDialogPhrase *newphrase = new NPCDialogPhrase; ! newphrase->phrase = phrase; newphrase->synonym = synonym; newphrase->moreGeneral = moreGeneral; --- 109,119 ---- } ! void NPCDialogDict::AddTerm(const char *term, const char *synonym, const char *moreGeneral) { ! if (FindTerm(term) != NULL) return; ! NpcTerm *newphrase = new NpcTerm; ! newphrase->term = term; newphrase->synonym = synonym; newphrase->moreGeneral = moreGeneral; *************** *** 123,135 **** void NPCDialogDict::FixMissingReferences() { ! BinaryRBIterator<NPCDialogPhrase> iter(&phrases); ! NPCDialogPhrase * phrase; ! for (phrase = iter.First(); phrase; phrase = ++iter) { ! if (phrase->synonym.Length()>0 && !FindPhrase(phrase->synonym)) ! AddPhrase(phrase->synonym, "", ""); ! if (phrase->moreGeneral.Length()>0 && !FindPhrase(phrase->moreGeneral)) ! AddPhrase(phrase->moreGeneral, "", ""); } } --- 123,135 ---- void NPCDialogDict::FixMissingReferences() { ! BinaryRBIterator<NpcTerm> iter(&phrases); ! NpcTerm * term; ! for (term = iter.First(); term; term = ++iter) { ! if (term->synonym.Length()>0 && !FindTerm(term->synonym)) ! AddTerm(term->synonym, "", ""); ! if (term->moreGeneral.Length()>0 && !FindTerm(term->moreGeneral)) ! AddTerm(term->moreGeneral, "", ""); } } *************** *** 143,147 **** if (!result.IsValid()) { ! CPrintf(CON_ERROR, "Cannot load phrases into dictionary from database.\n"); CPrintf(CON_ERROR, db->GetLastError()); return false; --- 143,147 ---- if (!result.IsValid()) { ! CPrintf(CON_ERROR, "Cannot load terms into dictionary from database.\n"); CPrintf(CON_ERROR, db->GetLastError()); return false; *************** *** 149,153 **** for (unsigned int i=0; i<result.Count(); i++) ! AddPhrase(result[i]["word"], result[i]["synonym_of"], result[i]["more_general"]); FixMissingReferences(); --- 149,153 ---- for (unsigned int i=0; i<result.Count(); i++) ! AddTerm(result[i]["word"], result[i]["synonym_of"], result[i]["more_general"]); FixMissingReferences(); *************** *** 180,185 **** } ! NPCDialogPhrase *found, key; ! key.phrase = word; found = phrases.Find(&key); --- 180,185 ---- } ! NpcTerm *found, key; ! key.term = word; found = phrases.Find(&key); *************** *** 189,193 **** { CPrintf(CON_WARNING, "Warning: Word %s in trigger '%s' is already a synonym for '%s'.\n", ! (const char *)found->phrase, (const char *)trigger, (const char *)found->synonym); --- 189,193 ---- { CPrintf(CON_WARNING, "Warning: Word %s in trigger '%s' is already a synonym for '%s'.\n", ! (const char *)found->term, (const char *)trigger, (const char *)found->synonym); *************** *** 197,202 **** { // add word ! found = new NPCDialogPhrase; ! found->phrase = word; // CPrintf(CON_DEBUG, "Adding %s.\n",(const char *)word); phrases.Insert(found,TREE_OWNS_DATA); --- 197,202 ---- { // add word ! found = new NpcTerm; ! found->term = word; // CPrintf(CON_DEBUG, "Adding %s.\n",(const char *)word); phrases.Insert(found,TREE_OWNS_DATA); *************** *** 224,228 **** for (unsigned int i=0; i<result.Count(); i++) { ! NPCDialogTriggerGroupEntry *newtge = new NPCDialogTriggerGroupEntry(result[i].GetInt("id"),result[i]["trigger_text"]); trigger_groups.Insert(newtge,TREE_OWNS_DATA); // TRUE means tree owns data --- 224,228 ---- for (unsigned int i=0; i<result.Count(); i++) { ! NpcTriggerGroupEntry *newtge = new NpcTriggerGroupEntry(result[i].GetInt("id"),result[i]["trigger_text"]); trigger_groups.Insert(newtge,TREE_OWNS_DATA); // TRUE means tree owns data *************** *** 249,256 **** for (unsigned int i=0; i<result2.Count(); i++) { ! NPCDialogTriggerGroupEntry *parent = trigger_groups_by_id.Get(result2[i].GetInt("equivalent_to_id"),NULL); if (parent) { ! NPCDialogTriggerGroupEntry *newtge = new NPCDialogTriggerGroupEntry(result2[i].GetInt("id"),result2[i]["trigger_text"],parent); trigger_groups.Insert(newtge,TREE_OWNS_DATA); // TRUE means tree owns data --- 249,256 ---- for (unsigned int i=0; i<result2.Count(); i++) { ! NpcTriggerGroupEntry *parent = trigger_groups_by_id.Get(result2[i].GetInt("equivalent_to_id"),NULL); if (parent) { ! NpcTriggerGroupEntry *newtge = new NpcTriggerGroupEntry(result2[i].GetInt("id"),result2[i]["trigger_text"],parent); trigger_groups.Insert(newtge,TREE_OWNS_DATA); // TRUE means tree owns data *************** *** 291,295 **** for (unsigned int i=0; i<result.Count(); i++) { ! NPCDialogTrigger *newtrig = new NPCDialogTrigger; if (!newtrig->Load(result[i])) --- 291,295 ---- for (unsigned int i=0; i<result.Count(); i++) { ! NpcTrigger *newtrig = new NpcTrigger; if (!newtrig->Load(result[i])) *************** *** 332,336 **** for (unsigned int i=0; i<result.Count(); i++) { ! NPCDialogResponse *newresp = new NPCDialogResponse; if (!newresp->Load(result[i])) --- 332,336 ---- for (unsigned int i=0; i<result.Count(); i++) { ! NpcResponse *newresp = new NpcResponse; if (!newresp->Load(result[i])) *************** *** 345,367 **** } ! NPCDialogPhrase * NPCDialogDict::FindPhrase(const char *phrase) { ! NPCDialogPhrase key; csString dc; ! dc = phrase; dc.Downcase(); ! key.phrase = dc; return phrases.Find(&key); } ! NPCDialogPhrase * NPCDialogDict::FindSynonym(const csString & phrase) { ! NPCDialogPhrase * phraseRec = FindPhrase(phrase); ! if (phraseRec == NULL) return NULL; ! if (phraseRec->synonym.Length() > 0) ! return FindPhrase(phraseRec->synonym); else ! return phraseRec; } --- 345,367 ---- } ! NpcTerm * NPCDialogDict::FindTerm(const char *term) { ! NpcTerm key; csString dc; ! dc = term; dc.Downcase(); ! key.term = dc; return phrases.Find(&key); } ! NpcTerm * NPCDialogDict::FindTermOrSynonym(const csString & term) { ! NpcTerm * termRec = FindTerm(term); ! if (termRec == NULL) return NULL; ! if (termRec->synonym.Length() > 0) ! return FindTerm(termRec->synonym); else ! return termRec; } *************** *** 383,387 **** }*/ ! NPCDialogResponse *NPCDialogDict::FindResponse(const char *area, const char *trigger, int faction, --- 383,387 ---- }*/ ! NpcResponse *NPCDialogDict::FindResponse(const char *area, const char *trigger, int faction, *************** *** 389,394 **** { CPrintf(CON_DEBUG, "Entering NPCDialogDict::FindResponse.\n"); ! NPCDialogTrigger *trig; ! NPCDialogTrigger key; key.area = area; --- 389,394 ---- { CPrintf(CON_DEBUG, "Entering NPCDialogDict::FindResponse.\n"); ! NpcTrigger *trig; ! NpcTrigger key; key.area = area; *************** *** 419,424 **** CPrintf(CON_DEBUG, "NPCDialogDict::FindResponse trigger: %s.\n", (const char*)trig->trigger); ! NPCDialogResponse *resp; ! NPCDialogResponse key2; key2.id = trig->responseID; // find the specified response --- 419,424 ---- CPrintf(CON_DEBUG, "NPCDialogDict::FindResponse trigger: %s.\n", (const char*)trig->trigger); ! NpcResponse *resp; ! NpcResponse key2; key2.id = trig->responseID; // find the specified response *************** *** 428,432 **** { CPrintf(CON_DEBUG, "Identified as error response.\n"); ! resp->type = NPCDialogResponse::ERROR_RESPONSE; } --- 428,432 ---- { CPrintf(CON_DEBUG, "Identified as error response.\n"); ! resp->type = NpcResponse::ERROR_RESPONSE; } *************** *** 445,449 **** } ! NPCDialogTrigger* newtrig = new NPCDialogTrigger; if (!newtrig->Load(result[0])) --- 445,449 ---- } ! NpcTrigger* newtrig = new NpcTrigger; if (!newtrig->Load(result[0])) *************** *** 468,472 **** } ! NPCDialogResponse *newresp = new NPCDialogResponse; if (!newresp->Load(result[0])) --- 468,472 ---- } ! NpcResponse *newresp = new NpcResponse; if (!newresp->Load(result[0])) *************** *** 481,485 **** ! bool NPCDialogTrigger::Load(iResultRow& row) { id = row.GetInt("id"); --- 481,485 ---- ! bool NpcTrigger::Load(iResultRow& row) { id = row.GetInt("id"); *************** *** 493,497 **** } ! bool NPCDialogResponse::Load(iResultRow& row) { id = row.GetInt("id"); --- 493,497 ---- } ! bool NpcResponse::Load(iResultRow& row) { id = row.GetInt("id"); *************** *** 509,513 **** them = row["pronoun_them"]; ! type = NPCDialogResponse::VALID_RESPONSE; // if a quest_id is specified in this response, --- 509,513 ---- them = row["pronoun_them"]; ! type = NpcResponse::VALID_RESPONSE; // if a quest_id is specified in this response, *************** *** 527,531 **** } ! const char *NPCDialogResponse::GetResponse() { if (active_quest == -1) --- 527,531 ---- } ! const char *NpcResponse::GetResponse() { if (active_quest == -1) *************** *** 546,550 **** } ! bool NPCDialogResponse::ParseResponseScript(unsigned int id,const char *xmlstr) { if (!xmlstr || strcmp(xmlstr,"")==0) --- 546,550 ---- } ! bool NpcResponse::ParseResponseScript(unsigned int id,const char *xmlstr) { if (!xmlstr || strcmp(xmlstr,"")==0) *************** *** 726,730 **** } ! void NPCDialogResponse::ExecuteScript(Client *client, gemNPC* target) { active_quest = -1; // not used by default --- 726,730 ---- } ! void NpcResponse::ExecuteScript(Client *client, gemNPC* target) { active_quest = -1; // not used by default *************** *** 739,743 **** } ! void NPCDialogResponse::SetActiveQuest(int max) { active_quest = psserver->rng->Get(max); --- 739,743 ---- } ! void NpcResponse::SetActiveQuest(int max) { active_quest = psserver->rng->Get(max); *************** *** 750,754 **** } ! bool SayResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { psString response = owner->GetResponse(); --- 750,754 ---- } ! bool SayResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { psString response = owner->GetResponse(); *************** *** 764,768 **** } ! bool ActionResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { who->SetAction(anim); --- 764,768 ---- } ! bool ActionResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { who->SetAction(anim); *************** *** 782,786 **** } ! bool VerifyQuestCompletedResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { bool avail = target->GetCharacterData()->CheckQuestCompleted(quest); --- 782,786 ---- } ! bool VerifyQuestCompletedResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { bool avail = target->GetCharacterData()->CheckQuestCompleted(quest); *************** *** 816,820 **** } ! bool VerifyQuestAssignedResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { bool avail = target->GetCharacterData()->CheckQuestAssigned(quest); --- 816,820 ---- } ! bool VerifyQuestAssignedResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { bool avail = target->GetCharacterData()->CheckQuestAssigned(quest); *************** *** 864,868 **** } ! bool AssignQuestResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { if (owner->GetActiveQuest() == -1) --- 864,868 ---- } ! bool AssignQuestResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { if (owner->GetActiveQuest() == -1) *************** *** 873,877 **** } ! bool CheckQuestTimeoutOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { owner->SetActiveQuest(quest_op->GetMaxQuests()); --- 873,877 ---- } ! bool CheckQuestTimeoutOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { owner->SetActiveQuest(quest_op->GetMaxQuests()); *************** *** 901,905 **** } ! bool CompleteQuestResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { if (!psserver->questmanager->Complete(quest,target)) --- 901,905 ---- } ! bool CompleteQuestResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { if (!psserver->questmanager->Complete(quest,target)) *************** *** 924,928 **** } ! bool GiveItemResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { csString ItemName; --- 924,928 ---- } ! bool GiveItemResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { csString ItemName; *************** *** 966,970 **** } ! bool RunScriptResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { ProgressionEvent *event = psserver->GetProgressionManager()->FindEvent(scriptname); --- 966,970 ---- } ! bool RunScriptResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { ProgressionEvent *event = psserver->GetProgressionManager()->FindEvent(scriptname); *************** *** 1093,1097 **** } ! bool TrainResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { if (CheckTraining(who, target, skill)) --- 1093,1097 ---- } ! bool TrainResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { if (CheckTraining(who, target, skill)) *************** *** 1115,1119 **** return true; } ! bool GuildAwardResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { psGuildInfo * guild = psserver->cachemanager.FindGuild(target->GetGuildID()); --- 1115,1119 ---- return true; } ! bool GuildAwardResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { psGuildInfo * guild = psserver->cachemanager.FindGuild(target->GetGuildID()); *************** *** 1158,1162 **** } ! bool OfferRewardResponseOp::Run(gemNPC *who, Client *target, NPCDialogResponse *owner) { psserver->questmanager->OfferRewardsToPlayer(target, offer); --- 1158,1162 ---- } ! bool OfferRewardResponseOp::Run(gemNPC *who, Client *target, NpcResponse *owner) { psserver->questmanager->OfferRewardsToPlayer(target, offer); *************** *** 1180,1184 **** } ! bool MoneyResponseOp::Run(gemNPC *who, Client *target,NPCDialogResponse *owner) { psCharacter * character = target->GetCharacterData(); --- 1180,1184 ---- } ! bool MoneyResponseOp::Run(gemNPC *who, Client *target,NpcResponse *owner) { psCharacter * character = target->GetCharacterData(); Index: dictionary.h =================================================================== RCS file: /cvsroot/planeshift/planeshift/src/server/bulkobjects/dictionary.h,v retrieving revision 1.27 retrieving revision 1.28 diff -C2 -d -r1.27 -r1.28 *** dictionary.h 9 May 2005 07:37:41 -0000 1.27 --- dictionary.h 14 May 2005 14:21:20 -0000 1.28 *************** *** 31,38 **** #define MAX_RESP 5 ! class NPCDialogPhrase; ! class NPCDialogTriggerGroupEntry; ! class NPCDialogTrigger; ! class NPCDialogResponse; class psSkillInfo; --- 31,38 ---- #define MAX_RESP 5 ! class NpcTerm; ! class NpcTriggerGroupEntry; ! class NpcTrigger; ! class NpcResponse; class psSkillInfo; *************** *** 40,48 **** { protected: ! BinaryRBTree<NPCDialogPhrase> phrases; ! BinaryRBTree<NPCDialogTriggerGroupEntry> trigger_groups; ! csHash<NPCDialogTriggerGroupEntry*> trigger_groups_by_id; ! BinaryRBTree<NPCDialogTrigger> triggers; ! BinaryRBTree<NPCDialogResponse> responses; BinaryRBTree<csString> disallowed_words; --- 40,48 ---- { protected: ! BinaryRBTree<NpcTerm> phrases; ! BinaryRBTree<NpcTriggerGroupEntry> trigger_groups; ! csHash<NpcTriggerGroupEntry*> trigger_groups_by_id; ! BinaryRBTree<NpcTrigger> triggers; ! BinaryRBTree<NpcResponse> responses; BinaryRBTree<csString> disallowed_words; *************** *** 54,58 **** /** If some phrases are mentioned in 'synonym' or 'moreGeneral' but do not have their own ! NPCDialogPhrase records, then the records are added */ void FixMissingReferences(); --- 54,58 ---- /** If some phrases are mentioned in 'synonym' or 'moreGeneral' but do not have their own ! NpcTerm records, then the records are added */ void FixMissingReferences(); *************** *** 61,66 **** void AddWords(csStringBase& trigger); ! /** Adds a new record to 'phrases' */ ! void AddPhrase(const char *phrase, const char* synonym, const char *moreGeneral); public: --- 61,66 ---- void AddWords(csStringBase& trigger); ! /** Adds a new record to 'terms' */ ! void AddTerm(const char *term, const char* synonym, const char *moreGeneral); public: *************** *** 69,84 **** bool Initialize(iDataConnection *db); ! /** Checks if 'phrase' is in the 'phrases' set. ! If this phrase has a synonym, then content of 'phrase' is replaced with this synonym. */ ! //bool IsValidWord(csString& phrase); ! ! /** Returns record of 'phrase' (or NULL) */ ! NPCDialogPhrase * FindPhrase(const char *phrase); ! ! /** Returns synonym of 'phrase' (or NULL). If 'phrase' has no synonym, then 'phrase' itself is returned */ ! NPCDialogPhrase * FindSynonym(const csString & phrase); ! NPCDialogResponse *FindResponse(const char *area, const char *trigger, int faction, --- 69,80 ---- bool Initialize(iDataConnection *db); + + /** Returns record of 'term' (or NULL if unknown) */ + NpcTerm * FindTerm(const char *term); ! /** Returns synonym of 'term' (or NULL if unknown). If 'term' is known but has no synonym, then 'term' itself is returned */ ! NpcTerm * FindTermOrSynonym(const csString & term); ! NpcResponse *FindResponse(const char *area, const char *trigger, int faction, *************** *** 93,100 **** /** A phrase recognized by the dialog system */ ! class NPCDialogPhrase { public: ! csString phrase; csString synonym; // If nonempty, phrase is translated to 'synonym' csString moreGeneral; // If nonempty, it specifies more general phrase than this --- 89,96 ---- /** A phrase recognized by the dialog system */ ! class NpcTerm { public: ! csString term; csString synonym; // If nonempty, phrase is translated to 'synonym' csString moreGeneral; // If nonempty, it specifies more general phrase than this *************** *** 103,124 **** // is used instead of it ! bool operator==(NPCDialogPhrase& other) const { ! return phrase==other.phrase; }; ! bool operator<(NPCDialogPhrase& other) const { ! return (strcmp(phrase,other.phrase)<0); }; }; ! class NPCDialogTriggerGroupEntry { public: int id; csString text; ! NPCDialogTriggerGroupEntry *parent; ! NPCDialogTriggerGroupEntry(int i,const char *txt,NPCDialogTriggerGroupEntry *myParent=0) { id = i; --- 99,120 ---- // is used instead of it ! bool operator==(NpcTerm& other) const { ! return term==other.term; }; ! bool operator<(NpcTerm& other) const { ! return (strcmp(term,other.term)<0); }; }; ! class NpcTriggerGroupEntry { public: int id; csString text; ! NpcTriggerGroupEntry *parent; ! NpcTriggerGroupEntry(int i,const char *txt,NpcTriggerGroupEntry *myParent=0) { id = i; *************** *** 126,134 **** parent = myParent; } ! bool operator<(NPCDialogTriggerGroupEntry& other) { return text < other.text; } ! bool operator==(NPCDialogTriggerGroupEntry& other) { return text == other.text; --- 122,130 ---- parent = myParent; } ! bool operator<(NpcTriggerGroupEntry& other) { return text < other.text; } ! bool operator==(NpcTriggerGroupEntry& other) { return text == other.text; *************** *** 136,140 **** }; ! class NPCDialogTrigger { public: --- 132,136 ---- }; ! class NpcTrigger { public: *************** *** 149,153 **** bool Load(iResultRow& row); ! bool operator==(NPCDialogTrigger& other) const { return (area==other.area && --- 145,149 ---- bool Load(iResultRow& row); ! bool operator==(NpcTrigger& other) const { return (area==other.area && *************** *** 158,162 **** }; ! bool operator<(NPCDialogTrigger& other) const { if (strcmp(area,other.area)<0) --- 154,158 ---- }; ! bool operator<(NpcTrigger& other) const { if (strcmp(area,other.area)<0) *************** *** 183,187 **** }; ! class NPCDialogResponse; class gemNPC; class gemActor; --- 179,183 ---- }; ! class NpcResponse; class gemNPC; class gemActor; *************** *** 200,204 **** virtual ~ResponseOperation() {}; virtual bool Load(iDocumentNode *node) = 0; ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner) = 0; const char *GetName() { return name; } }; --- 196,200 ---- virtual ~ResponseOperation() {}; virtual bool Load(iDocumentNode *node) = 0; ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner) = 0; const char *GetName() { return name; } }; *************** *** 209,213 **** * appropriate trigger is triggered. */ ! class NPCDialogResponse { public: --- 205,209 ---- * appropriate trigger is triggered. */ ! class NpcResponse { public: *************** *** 234,243 **** int GetActiveQuest() { return active_quest; } ! bool operator==(NPCDialogResponse& other) const { return id==other.id; }; ! bool operator<(NPCDialogResponse& other) const { return id<other.id; --- 230,239 ---- int GetActiveQuest() { return active_quest; } ! bool operator==(NpcResponse& other) const { return id==other.id; }; ! bool operator<(NpcResponse& other) const { return id<other.id; *************** *** 257,261 **** virtual ~SayResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 253,257 ---- virtual ~SayResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 272,276 **** virtual ~ActionResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 268,272 ---- virtual ~ActionResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 292,296 **** virtual ~VerifyQuestCompletedResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 288,292 ---- virtual ~VerifyQuestCompletedResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 311,315 **** virtual ~VerifyQuestAssignedResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 307,311 ---- virtual ~VerifyQuestAssignedResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 329,333 **** virtual ~AssignQuestResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); const char *GetTimeoutMsg() { return timeout_msg; } psQuest *GetQuest(int n) { return quest[n]; } --- 325,329 ---- virtual ~AssignQuestResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); const char *GetTimeoutMsg() { return timeout_msg; } psQuest *GetQuest(int n) { return quest[n]; } *************** *** 348,352 **** virtual ~CheckQuestTimeoutOp() {}; virtual bool Load(iDocumentNode *node) { return true; } ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 344,348 ---- virtual ~CheckQuestTimeoutOp() {}; virtual bool Load(iDocumentNode *node) { return true; } ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 365,369 **** virtual ~CompleteQuestResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 361,365 ---- virtual ~CompleteQuestResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 383,387 **** virtual ~GiveItemResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 379,383 ---- virtual ~GiveItemResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 401,405 **** virtual ~RunScriptResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 397,401 ---- virtual ~RunScriptResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 418,422 **** virtual ~TrainResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 414,418 ---- virtual ~TrainResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 433,437 **** virtual ~GuildAwardResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 429,433 ---- virtual ~GuildAwardResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 449,453 **** virtual ~OfferRewardResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 445,449 ---- virtual ~OfferRewardResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; *************** *** 465,469 **** virtual ~MoneyResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NPCDialogResponse *owner); }; --- 461,465 ---- virtual ~MoneyResponseOp() {}; virtual bool Load(iDocumentNode *node); ! virtual bool Run(gemNPC *who, Client *target,NpcResponse *owner); }; Index: psnpcdialog.cpp =================================================================== RCS file: /cvsroot/planeshift/planeshift/src/server/bulkobjects/psnpcdialog.cpp,v retrieving revision 1.45 retrieving revision 1.46 diff -C2 -d -r1.45 -r1.46 *** psnpcdialog.cpp 10 May 2005 06:01:45 -0000 1.45 --- psnpcdialog.cpp 14 May 2005 14:21:20 -0000 1.46 *************** *** 64,140 **** #include "psraceinfo.h" - #define MAX_GENER_OF_PHRASE 5 // Maximum number of generalizations for one phrase considered //---------------------------------------------------------------------------- - // class dlgGener - //---------------------------------------------------------------------------- - - void dlgGener::InitSent(int size) - { - sent.SetLength(size); - - for (int i=0; i < size; i++) - sent[i] = 0; - - CalcGrade(); - } - - void dlgGener::CalcGrade() - { - grade = 0; ! for (size_t i=0; i < sent.Length(); i++) ! grade += sent[i]*sent[i]; ! } ! ! bool dlgGener::FindNextGener(const csArray<csArray<NPCDialogPhrase*> > & possPhrases) { ! return FindNextGener(possPhrases, sent.Length()-1); ! } ! bool dlgGener::FindNextGener(const csArray<csArray<NPCDialogPhrase*> > & possPhrases, int pos) ! { ! if (sent[pos]+1 < (int) possPhrases[pos].Length()) ! { ! sent[pos]++; ! CalcGrade(); ! return true; ! } ! if (pos > 0) { ! sent[pos] = 0; ! return FindNextGener(possPhrases, pos-1); } ! else ! return false; } ! int dlgGener::cmpGen(const void *a, const void *b) { ! float gradeA = (*((dlgGener**)a))->grade; ! float gradeB = (*((dlgGener**)b))->grade; ! if (gradeA < gradeB) ! return -1; ! if (gradeA == gradeB) ! return 0; ! else ! return 1; ! } ! csString dlgGener::GetText(const csArray<csArray<NPCDialogPhrase*> > & possGenerOfPhrases) ! { ! csString text; ! for (size_t i=0; i < sent.Length(); i++) { ! if (i > 0) ! text += " "; ! ! text += possGenerOfPhrases[i][sent[i]]->phrase; } ! return text; } //---------------------------------------------------------------------------- NPCDialogDict *psNPCDialog::dict=NULL; --- 64,116 ---- #include "psraceinfo.h" //---------------------------------------------------------------------------- ! const csString& NpcTriggerSentence::GetString() { ! if (str.Length()) ! return str; ! for (size_t i=0; i<terms.Length(); i++) { ! str.Append(terms[i]->term); ! if (i<terms.Length()-1) ! str.Append(' '); } ! return str; } ! bool NpcTriggerSentence::GeneralizeTerm(NPCDialogDict *dict,size_t level) { ! if (level >= terms.Length()) ! return false; ! NpcTerm *term = terms[level]; ! if (!term) ! return false; ! if (term->moreGeneral.Length()) { ! NpcTerm *up = dict->FindTerm(term->moreGeneral); ! if (up) ! { ! terms[level] = up; ! return true; ! } ! else ! { ! Error3("NPC Dialog term <%s> specifies a more general term of <%s> which is not found.", ! term->term.GetData(), term->moreGeneral.GetData() ); ! } } ! return false; } + + + //---------------------------------------------------------------------------- + + NPCDialogDict *psNPCDialog::dict=NULL; *************** *** 152,156 **** } - //---------------------------------------------------------------------------- bool psNPCDialog::Initialize( iDataConnection *db ) { --- 128,131 ---- *************** *** 303,331 **** } ! void psNPCDialog::RecognizePhrases(const psString & text, dlgSentence & sent) { ! const int MAX_SENTENCE_LENGTH = 4; ! NPCDialogPhrase* phraseFound; WordArray words(text); int numWordsInPhrase = words.GetCount(); int firstWord=0; ! csString phrase; ! if (!dict) return; CPrintf(CON_DEBUG, "Recognizing phrases in '%s'\n", text.GetData()); ! while (firstWord<(int)words.GetCount() && sent.Length()<MAX_SENTENCE_LENGTH) { ! phrase = words.GetWords(firstWord, firstWord+numWordsInPhrase); ! phraseFound = dict->FindSynonym(phrase); ! if (phraseFound != NULL) { ! sent.Push(phraseFound); firstWord += numWordsInPhrase; numWordsInPhrase = words.GetCount() - firstWord; } else if (numWordsInPhrase > 1) ! numWordsInPhrase --; else { --- 278,308 ---- } ! void psNPCDialog::FilterKnownTerms(const psString & text, NpcTriggerSentence &trigger) { ! const size_t MAX_SENTENCE_LENGTH = 4; ! NpcTerm* term; ! WordArray words(text); int numWordsInPhrase = words.GetCount(); int firstWord=0; ! csString candidate; ! if (!dict) // Pointless to try if no dictionary loaded. ! return; CPrintf(CON_DEBUG, "Recognizing phrases in '%s'\n", text.GetData()); ! while (firstWord<(int)words.GetCount() && trigger.TermLength()<MAX_SENTENCE_LENGTH) { ! candidate = words.GetWords(firstWord, firstWord+numWordsInPhrase); ! term = dict->FindTermOrSynonym(candidate); ! if (term) { ! trigger.AddToSentence(term); firstWord += numWordsInPhrase; numWordsInPhrase = words.GetCount() - firstWord; } else if (numWordsInPhrase > 1) ! numWordsInPhrase--; else { *************** *** 335,398 **** } ! //debug output ! csString descr; ! for (size_t i=0; i < sent.Length(); i++) ! { ! if (i>0) ! descr += "','"; ! descr += sent[i]->phrase; ! } ! CPrintf(CON_DEBUG, "Phrases recognized: '%s'\n", descr.GetData()); ! } ! ! void psNPCDialog::FindAllGeneralizations(const dlgSentence & sent, csPDelArray<dlgGener> & gens, ! csArray<csArray<NPCDialogPhrase*> > & possGenerOfPhrases) ! { ! csArray<NPCDialogPhrase*> possGenerOfPhrase; ! NPCDialogPhrase* phrase; ! dlgGener gen; ! csArray<dlgGener*> genList; ! dlgGener **sortedGens; ! size_t i; ! ! // find possible generalizations of all phrases in our sentence ! for (i=0; i < sent.Length(); i++) ! { ! possGenerOfPhrase.DeleteAll(); ! phrase = sent[i]; ! while (true) ! { ! possGenerOfPhrase.Push(phrase); ! if (phrase->moreGeneral.Length()==0 || possGenerOfPhrase.Length()==MAX_GENER_OF_PHRASE) ! break; ! phrase = dict->FindPhrase(phrase->moreGeneral); ! assert(phrase); ! } ! possGenerOfPhrases.Push(possGenerOfPhrase); ! } ! ! // do all combinations of different generalizations ! gen.InitSent(sent.Length()); ! do ! { ! genList.Push(new dlgGener(gen)); ! } ! while (gen.FindNextGener(possGenerOfPhrases)); ! ! // now sort it by grade ! sortedGens = new dlgGener*[genList.Length()]; ! for (i = 0; i < genList.Length(); i++) ! sortedGens[i] = genList[i]; ! qsort(sortedGens, genList.Length(), sizeof(dlgGener*), dlgGener::cmpGen); ! gens.SetLength(genList.Length()); ! for (i = 0; i < genList.Length(); i++) ! gens[i] = sortedGens[i]; ! delete [] sortedGens; ! ! //debug output ! csString descr; ! for (i = 0; i < genList.Length(); i++) ! descr += " - '" + gens[i]->GetText(possGenerOfPhrases) + "'\n"; ! CPrintf(CON_DEBUG, "Possible generalizations:\n%s", descr.GetData()); } --- 312,316 ---- } ! CPrintf(CON_DEBUG, "Phrases recognized: '%s'\n", trigger.GetString().GetData()); } *************** *** 416,424 **** ! NPCDialogResponse *psNPCDialog::FindResponse(csStringBase& trigger,const char *text) { BinaryRBIterator<KnowledgeArea> loop(&knowareas); KnowledgeArea *area; ! NPCDialogResponse *resp = NULL; trigger.Downcase(); --- 334,342 ---- ! NpcResponse *psNPCDialog::FindResponse(csStringBase& trigger,const char *text) { BinaryRBIterator<KnowledgeArea> loop(&knowareas); KnowledgeArea *area; ! NpcResponse *resp = NULL; trigger.Downcase(); *************** *** 497,506 **** } ! NPCDialogResponse *psNPCDialog::Respond(const char * text,Client *client,bool use_exact) { ! NPCDialogResponse *resp; ! dlgSentence sent; ! csPDelArray<dlgGener> gens; ! csArray<csArray<NPCDialogPhrase*> > possGenerOfPhrases; psString pstext(text); --- 415,465 ---- } ! NpcResponse *psNPCDialog::FindOrGeneralizeTrigger(Client *client,NpcTriggerSentence& trigger,NpcTriggerSentence& generalized,size_t level) { ! NpcResponse *resp; ! ! csString generalized_copy = generalized.GetString(); ! resp = FindResponse( generalized_copy, trigger.GetString()); ! if (resp != NULL) ! { ! CPrintf(CON_DEBUG, "Found response to: '%s'\n", generalized.GetString().GetData()); ! ! int times; ! csTicks when; ! if (dialogHistory.EverSaid(client->GetPlayerID(), resp->id, when, times)) ! { ! return RepeatedResponse(trigger.GetString(), resp, when, times); ! } ! else ! dialogHistory.AddToHistory(client->GetPlayerID(), resp->id, csGetTicks() ); ! ! currentClient->SetLastResponse(resp->id); ! return resp; ! } ! else // Try a further generalizations at lower levels, then this level ! { ! if (level < trigger.TermLength()-1) ! { ! resp = FindOrGeneralizeTrigger(client,trigger,generalized,level+1); ! if (resp) ! return resp; ! } ! // Reset later words back to original so re-search covers all again ! for (size_t i=level+1; i<trigger.TermLength(); i++) ! generalized.Term(i) = trigger.Term(i); ! ! // Attempt to move up a level with this term ! generalized.GeneralizeTerm(dict,level); ! if (generalized.Term(level) == trigger.Term(level)) // no generalization possible, so give up at this level ! return NULL; ! else ! return FindOrGeneralizeTrigger(client,trigger,generalized,level); ! } ! } ! ! NpcResponse *psNPCDialog::Respond(const char * text,Client *client,bool use_exact) ! { ! NpcResponse *resp; ! NpcTriggerSentence trigger,generalized; psString pstext(text); *************** *** 512,529 **** return ErrorResponse(pstext); ! RecognizePhrases(pstext, sent); ! if (sent.Length() == 0) return ErrorResponse(pstext); ! FindAllGeneralizations(sent, gens, possGenerOfPhrases); ! resp = NULL; ! for (size_t i=0; i < gens.Length(); i++) { ! csStringFast<50> poss = gens[i]->GetText(possGenerOfPhrases); ! resp = FindResponse( poss, pstext.GetData()); if (resp != NULL) { csString txt = gens[i]->GetText(possGenerOfPhrases); ! CPrintf(CON_DEBUG, "Found response to: '%s'\n", txt.GetData()); int times; --- 471,490 ---- return ErrorResponse(pstext); ! FilterKnownTerms(pstext, trigger); ! if (trigger.TermLength() == 0) return ErrorResponse(pstext); ! resp = NULL; ! generalized = trigger; ! ! resp = FindOrGeneralizeTrigger(client,trigger,generalized,0); ! #if 0 ! while (generalized.GetString().Length()) { ! resp = FindResponse( generalized.GetString(), pstext.GetData()); if (resp != NULL) { csString txt = gens[i]->GetText(possGenerOfPhrases); ! CPrintf(CON_DEBUG, "Found response to: '%s'\n", generalized.GetString().GetData()); int times; *************** *** 539,544 **** break; } } ! if (resp == NULL) { --- 500,509 ---- break; } + else // Try a further generalization + { + } } ! #endif ! if (resp == NULL) { *************** *** 551,555 **** } ! NPCDialogResponse *psNPCDialog::FindXMLResponse(Client *client, csString trigger) { currentplayer = client->GetActor(); --- 516,520 ---- } ! NpcResponse *psNPCDialog::FindXMLResponse(Client *client, csString trigger) { currentplayer = client->GetActor(); *************** *** 559,563 **** } ! NPCDialogResponse *psNPCDialog::RepeatedResponse(const psString& text, NPCDialogResponse *resp, csTicks when, int times) { const char *time_description; --- 524,528 ---- } ! NpcResponse *psNPCDialog::RepeatedResponse(const psString& text, NpcResponse *resp, csTicks when, int times) { const char *time_description; *************** *** 585,597 **** } ! NPCDialogResponse *psNPCDialog::ErrorResponse(const psString & text) { AddBadText(text); psString error("error"); ! NPCDialogResponse * resp = FindResponse(error,text); return resp; } ! void psNPCDialog::UpdateAntecedents(NPCDialogResponse *resp) { // later this will need to be kept on a per player basis --- 550,562 ---- } ! NpcResponse *psNPCDialog::ErrorResponse(const psString & text) { AddBadText(text); psString error("error"); ! NpcResponse * resp = FindResponse(error,text); return resp; } ! void psNPCDialog::UpdateAntecedents(NpcResponse *resp) { // later this will need to be kept on a per player basis Index: psnpcdialog.h =================================================================== RCS file: /cvsroot/planeshift/planeshift/src/server/bulkobjects/psnpcdialog.h,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** psnpcdialog.h 14 Mar 2005 08:21:42 -0000 1.18 --- psnpcdialog.h 14 May 2005 14:21:20 -0000 1.19 *************** *** 39,43 **** struct iObjectRegistry; class NPCDialogDict; ! class NPCDialogResponse; class GemActor; --- 39,43 ---- struct iObjectRegistry; class NPCDialogDict; ! class NpcResponse; class GemActor; *************** *** 63,102 **** /** Sentence written by the user represented ! as sequence of known phrases */ ! typedef csArray<NPCDialogPhrase*> dlgSentence; ! ! /** Generalization of some dlgSentence. ! It has same length as the sentence but it can use more general phrases ! instead of those in the sentence. */ ! class dlgGener { - public: - void InitSent(int size); /** set to first possible generalization*/ - - /** Switches our generalization to the "next" one - this is used - to iterate over all possible generalizations */ - bool FindNextGener(const csArray<csArray<NPCDialogPhrase*> > & possPhrases); - - /** Returns generalization reprezented as sentence in natural language */ - csString GetText(const csArray<csArray<NPCDialogPhrase*> > & possGenerOfPhrases); - - static int cmpGen(const void *a, const void *b); - protected: ! ! void CalcGrade(); ! ! bool FindNextGener(const csArray<csArray<NPCDialogPhrase*> > & possPhrases, int pos); ! /** Each phrase in the sentence has one number in this array: ! this number is index in array of all possible generalizations ! of given phrase */ ! csArray <int> sent; ! ! /** How big is the generalization ? ! E.g. "give me fruit" is more general than "give me apple" */ ! float grade; }; /** * This class right now holds a simple circular MRU list --- 63,84 ---- /** Sentence written by the user represented ! as sequence of known terms */ ! class NpcTriggerSentence { protected: ! csArray<NpcTerm*> terms; // Not PArray because these ptrs are shared ! csString str; /// String version built from array ! public: ! NpcTriggerSentence() {}; ! void AddToSentence(NpcTerm *next_word) { terms.Push(next_word); str=""; } ! size_t TermLength() { return terms.Length(); } ! const csString& GetString(); ! void operator=(NpcTriggerSentence& other) { terms = other.terms; str=other.str; } ! NpcTerm*& Term(int i) { return terms[i]; } ! bool GeneralizeTerm(NPCDialogDict *dict,size_t level); }; + /** * This class right now holds a simple circular MRU list *************** *** 146,152 **** //void FindTriggerWords(const char *text,csString& trigger); ! NPCDialogResponse* FindResponse(csStringBase& trigger,const char *text); bool CheckPronouns(psString& text); ! void UpdateAntecedents(NPCDialogResponse *resp); void AddBadText(const char *text); --- 128,134 ---- //void FindTriggerWords(const char *text,csString& trigger); ! NpcResponse* FindResponse(csStringBase& trigger,const char *text); bool CheckPronouns(psString& text); ! void UpdateAntecedents(NpcResponse *resp); void AddBadText(const char *text); *************** *** 158,169 **** /** Recognizes phrases in the text and translates them to synonyms, Ignores any unrecognized phrases. Returns array of recognized phrases. */ ! void RecognizePhrases(const psString & text, dlgSentence & sent); ! ! /** Find generalizations of sentence */ ! void FindAllGeneralizations(const dlgSentence & sent, csPDelArray<dlgGener> & gens, ! csArray<csArray<NPCDialogPhrase*> > & possGenerOfPhrases); ! NPCDialogResponse * ErrorResponse(const psString & text); ! NPCDialogResponse * RepeatedResponse(const psString& text, NPCDialogResponse *resp, csTicks when, int times); public: --- 140,148 ---- /** Recognizes phrases in the text and translates them to synonyms, Ignores any unrecognized phrases. Returns array of recognized phrases. */ ! void FilterKnownTerms(const psString & text, NpcTriggerSentence &trigger); ! NpcResponse *FindOrGeneralizeTrigger(Client *client,NpcTriggerSentence& trigger,NpcTriggerSentence& generalized,size_t level); ! NpcResponse * ErrorResponse(const psString & text); ! NpcResponse * RepeatedResponse(const psString& text, NpcResponse *resp, csTicks when, int times); public: *************** *** 175,181 **** bool LoadKnowledgeAreas(int NPCID); ! NPCDialogResponse *Respond(const char * text,Client *client,bool use_exact); ! NPCDialogResponse* FindXMLResponse(Client *client, csString trigger); bool AddWord(const char *word); --- 154,160 ---- bool LoadKnowledgeAreas(int NPCID); ! NpcResponse *Respond(const char * text,Client *client,bool use_exact); ! NpcResponse* FindXMLResponse(Client *client, csString trigger); bool AddWord(const char *word); |