From f2c6907244a25949094dfe67529ec53992e44a91 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Thu, 20 Dec 2012 23:16:34 +0000 Subject: [PATCH] Added in text escape sequences for dialogue, messageboxes and books. builtins are placeholders, global variables work --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 +- apps/openmw/mwgui/formatting.cpp | 12 ++ apps/openmw/mwscript/interpretercontext.cpp | 14 ++ apps/openmw/mwscript/interpretercontext.hpp | 4 + apps/openmw/mwworld/globals.cpp | 11 + apps/openmw/mwworld/globals.hpp | 3 + apps/openmw/mwworld/worldimp.cpp | 5 + apps/openmw/mwworld/worldimp.hpp | 2 + components/CMakeLists.txt | 2 +- components/interpreter/context.hpp | 4 + components/interpreter/defines.cpp | 200 ++++++++++++++++++ components/interpreter/defines.hpp | 12 ++ components/interpreter/miscopcodes.hpp | 4 +- 14 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 components/interpreter/defines.cpp create mode 100644 components/interpreter/defines.hpp diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 40ebde246..0be732790 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -133,6 +133,8 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. + + virtual std::vector getGlobals () const = 0; virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 80316c0f5..26d5af202 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -155,7 +156,9 @@ namespace MWDialogue } parseText (info->mResponse); - win->addText (info->mResponse); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); mLastTopic = it->mId; mLastDialogue = *info; @@ -267,7 +270,8 @@ namespace MWDialogue else win->addTitle (topic); - win->addText (info->mResponse); + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); @@ -411,7 +415,9 @@ namespace MWDialogue mIsInChoice = false; std::string text = info->mResponse; parseText (text); - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (text); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); executeScript (info->mResultScript); mLastTopic = mLastTopic; mLastDialogue = *info; diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 53c23c25d..273034edd 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -1,5 +1,10 @@ #include "formatting.hpp" +#include + +#include "../mwscript/interpretercontext.hpp" +#include "../mwworld/ptr.hpp" + #include #include @@ -68,6 +73,9 @@ std::vector BookTextParser::split(std::string text, const int width { std::vector result; + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesDialog(text, interpreterContext); + boost::algorithm::replace_all(text, "
", "\n"); boost::algorithm::replace_all(text, "

", "\n\n"); @@ -167,6 +175,10 @@ std::vector BookTextParser::split(std::string text, const int width MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) { + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesDialog(text, interpreterContext); + + mParent = parent; mWidth = width; mHeight = 0; diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 577ad008f..4ea984f9c 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -174,6 +174,20 @@ namespace MWScript MWBase::Environment::get().getWorld()->getGlobalVariable (name).mFloat = value; } + std::vector InterpreterContext::getGlobals () const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getGlobals(); + + } + + char InterpreterContext::getGlobalType (const std::string& name) const + { + MWBase::World *world = MWBase::Environment::get().getWorld(); + return world->getGlobalVariableType(name); + } + + bool InterpreterContext::isScriptRunning (const std::string& name) const { return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name); diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 6d97f7949..15578aa24 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -75,6 +75,10 @@ namespace MWScript virtual void setGlobalLong (const std::string& name, int value); virtual void setGlobalFloat (const std::string& name, float value); + + virtual std::vector getGlobals () const; + + virtual char getGlobalType (const std::string& name) const; virtual bool isScriptRunning (const std::string& name) const; diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 76dede5a3..f010661b9 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -7,6 +7,17 @@ namespace MWWorld { + std::vector Globals::getGlobals () const + { + std::vector retval; + Collection::const_iterator it; + for(it = mVariables.begin(); it != mVariables.end(); ++it){ + retval.push_back(it->first); + } + + return retval; + } + Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); diff --git a/apps/openmw/mwworld/globals.hpp b/apps/openmw/mwworld/globals.hpp index c7aee5f93..681bd560e 100644 --- a/apps/openmw/mwworld/globals.hpp +++ b/apps/openmw/mwworld/globals.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWWORLD_GLOBALS_H #define GAME_MWWORLD_GLOBALS_H +#include #include #include @@ -53,6 +54,8 @@ namespace MWWorld char getType (const std::string& name) const; ///< If there is no global variable with this name, ' ' is returned. + + std::vector getGlobals () const; }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f0b2efcec..88ad917c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -296,6 +296,11 @@ namespace MWWorld return mGlobalVariables->getType (name); } + std::vector World::getGlobals () const + { + return mGlobalVariables->getGlobals(); + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 0962c292c..15b13256a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -153,6 +153,8 @@ namespace MWWorld virtual char getGlobalVariableType (const std::string& name) const; ///< Return ' ', if there is no global variable with this name. + + virtual std::vector getGlobals () const; virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name. diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 29d6f46cd..bff99a69c 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -59,7 +59,7 @@ add_component_dir (compiler add_component_dir (interpreter context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes - miscopcodes opcodes runtime scriptopcodes spatialopcodes types + miscopcodes opcodes runtime scriptopcodes spatialopcodes types defines ) include_directories(${BULLET_INCLUDE_DIRS}) diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 4221da36e..2cfc1c03d 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -49,6 +49,10 @@ namespace Interpreter virtual void setGlobalFloat (const std::string& name, float value) = 0; + virtual std::vector getGlobals () const = 0; + + virtual char getGlobalType (const std::string& name) const = 0; + virtual bool isScriptRunning (const std::string& name) const = 0; virtual void startScript (const std::string& name) = 0; diff --git a/components/interpreter/defines.cpp b/components/interpreter/defines.cpp new file mode 100644 index 000000000..d5e3e3d0d --- /dev/null +++ b/components/interpreter/defines.cpp @@ -0,0 +1,200 @@ +#include "defines.hpp" + +#include +#include +#include +#include + +namespace Interpreter{ + + bool Check(const std::string str, const std::string escword, unsigned int* i, unsigned int* start){ + bool retval = str.find(escword) == 0; + if(retval){ + (*i) += escword.length(); + (*start) = (*i) + 1; + } + return retval; + } + + std::vector globals; + + bool longerStr(const std::string a, const std::string b){ + return a.length() > b.length(); + } + + std::string fixDefinesReal(std::string text, char eschar, Context& context){ + + unsigned int start = 0; + std::string retval = ""; + for(unsigned int i = 0; i < text.length(); i++){ + if(text[i] == eschar){ + retval += text.substr(start, i - start); + std::string temp = text.substr(i+1, 100); + transform(temp.begin(), temp.end(), temp.begin(), ::tolower); + + bool found; + + if( (found = Check(temp, "actionslideright", &i, &start))){ + retval += "PLACEHOLDER_ACTION_SLIDE_RIGHT"; + } + else if((found = Check(temp, "actionreadymagic", &i, &start))){ + retval += "PLACEHOLDER_ACTION_READY_MAGIC"; + } + else if((found = Check(temp, "actionprevweapon", &i, &start))){ + retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; + } + else if((found = Check(temp, "actionnextweapon", &i, &start))){ + retval += "PLACEHOLDER_ACTION_PREV_WEAPON"; + } + else if((found = Check(temp, "actiontogglerun", &i, &start))){ + retval += "PLACEHOLDER_ACTION_TOGGLE_RUN"; + } + else if((found = Check(temp, "actionslideleft", &i, &start))){ + retval += "PLACEHOLDER_ACTION_TOGGLE_RUN"; + } + else if((found = Check(temp, "actionreadyitem", &i, &start))){ + retval += "PLACEHOLDER_ACTION_READY_ITEM"; + } + else if((found = Check(temp, "actionprevspell", &i, &start))){ + retval += "PLACEHOLDER_ACTION_PREV_SPELL"; + } + else if((found = Check(temp, "actionnextspell", &i, &start))){ + retval += "PLACEHOLDER_ACTION_NEXT_SPELL"; + } + else if((found = Check(temp, "actionrestmenu", &i, &start))){ + retval += "PLACEHOLDER_ACTION_REST_MENU"; + } + else if((found = Check(temp, "actionmenumode", &i, &start))){ + retval += "PLACEHOLDER_ACTION_MENU_MODE"; + } + else if((found = Check(temp, "actionactivate", &i, &start))){ + retval += "PLACEHOLDER_ACTION_ACTIVATE"; + } + else if((found = Check(temp, "actionjournal", &i, &start))){ + retval += "PLACEHOLDER_ACTION_JOURNAL"; + } + else if((found = Check(temp, "actionforward", &i, &start))){ + retval += "PLACEHOLDER_ACTION_FORWARD"; + } + else if((found = Check(temp, "pccrimelevel", &i, &start))){ + retval += "PLACEHOLDER_PC_CRIME_LEVEL"; + } + else if((found = Check(temp, "actioncrouch", &i, &start))){ + retval += "PLACEHOLDER_ACTION_CROUCH"; + } + else if((found = Check(temp, "actionjump", &i, &start))){ + retval += "PLACEHOLDER_ACTION_JUMP"; + } + else if((found = Check(temp, "actionback", &i, &start))){ + retval += "PLACEHOLDER_ACTION_BACK"; + } + else if((found = Check(temp, "actionuse", &i, &start))){ + retval += "PLACEHOLDER_ACTION_USE"; + } + else if((found = Check(temp, "actionrun", &i, &start))){ + retval += "PLACEHOLDER_ACTION_RUN"; + } + else if((found = Check(temp, "pcclass", &i, &start))){ + retval += "PLACEHOLDER_PC_CLASS"; + } + else if((found = Check(temp, "pcrace", &i, &start))){ + retval += "PLACEHOLDER_PC_RACE"; + } + else if((found = Check(temp, "pcname", &i, &start))){ + retval += "PLACEHOLDER_PC_NAME"; + } + else if((found = Check(temp, "cell", &i, &start))){ + retval += "PLACEHOLDER_CELL"; + } + + else if(eschar == '%'){ // In Dialogue, not messagebox + if( (found = Check(temp, "faction", &i, &start))){ + retval += "PLACEHOLDER_FACTION"; + } + else if((found = Check(temp, "nextpcrank", &i, &start))){ + retval += "PLACEHOLDER_NEXT_PC_RANK"; + } + else if((found = Check(temp, "pcnextrank", &i, &start))){ + retval += "PLACEHOLDER_PC_NEXT_RANK"; + } + else if((found = Check(temp, "pcrank", &i, &start))){ + retval += "PLACEHOLDER_PC_RANK"; + } + else if((found = Check(temp, "rank", &i, &start))){ + retval += "PLACEHOLDER_RANK"; + } + + else if((found = Check(temp, "class", &i, &start))){ + retval += "PLACEHOLDER_CLASS"; + } + else if((found = Check(temp, "race", &i, &start))){ + retval += "PLACEHOLDER_RACE"; + } + else if((found = Check(temp, "name", &i, &start))){ + retval += "PLACEHOLDER_NAME"; + } + } + else if(eschar == '^') { // In messagebox, not dialogue + + /* empty in messageboxes */ + if( (found = Check(temp, "faction", &i, &start))); + else if((found = Check(temp, "nextpcrank", &i, &start))); + else if((found = Check(temp, "pcnextrank", &i, &start))); + else if((found = Check(temp, "pcrank", &i, &start))); + else if((found = Check(temp, "rank", &i, &start))); + + /* uses pc in messageboxes */ + else if((found = Check(temp, "class", &i, &start))){ + retval += "PLACEHOLDER_CLASS"; + } + else if((found = Check(temp, "race", &i, &start))){ + retval += "PLACEHOLDER_RACE"; + } + else if((found = Check(temp, "name", &i, &start))){ + retval += "PLACEHOLDER_NAME"; + } + } + + /* Not a builtin, try global variables */ + if(!found){ + /* if list of globals is empty, grab it and sort it by descending string length */ + if(globals.empty()){ + globals = context.getGlobals(); + sort(globals.begin(), globals.end(), longerStr); + } + + for(unsigned int j = 0; j < globals.size(); j++){ + if((found = Check(temp, globals[j], &i, &start))){ + char type = context.getGlobalType(globals[j]); + + switch(type){ + case 's': retval += std::to_string(context.getGlobalShort(globals[j])); break; + case 'l': retval += std::to_string(context.getGlobalLong(globals[j])); break; + case 'f': retval += std::to_string(context.getGlobalFloat(globals[j])); break; + } + break; + } + } + } + + /* Not found */ + if(!found){ + /* leave unmodified */ + i += 1; + start = i; + retval += eschar; + } + } + } + retval += text.substr(start, text.length() - start); + return retval; + } + + std::string fixDefinesDialog(std::string text, Context& context){ + return fixDefinesReal(text, '%', context); + } + + std::string fixDefinesMsgBox(std::string text, Context& context){ + return fixDefinesReal(text, '^', context); + } +} diff --git a/components/interpreter/defines.hpp b/components/interpreter/defines.hpp new file mode 100644 index 000000000..731284661 --- /dev/null +++ b/components/interpreter/defines.hpp @@ -0,0 +1,12 @@ +#ifndef GAME_MWMECHANICS_DEFINES_H +#define GAME_MWMECHANICS_DEFINES_H + +#include +#include "context.hpp" + +namespace Interpreter{ + std::string fixDefinesDialog(std::string text, Context& context); + std::string fixDefinesMsgBox(std::string text, Context& context); +} + +#endif diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index 37c38fc30..1b4c823a0 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -10,6 +10,7 @@ #include "opcodes.hpp" #include "runtime.hpp" +#include "defines.hpp" namespace Interpreter { @@ -69,7 +70,8 @@ namespace Interpreter } } } - + + formattedMessage = fixDefinesMsgBox(formattedMessage, runtime.getContext()); return formattedMessage; }