Merge pull request #348 from TES3MP/master

Add master commits up to 25 Nov 2017
new-script-api
David Cernat 7 years ago committed by GitHub
commit 0a35b897be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,8 +5,10 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "textcolours.hpp" #include <components/fontloader/fontloader.hpp>
#include <components/misc/utf8stream.hpp>
#include "textcolours.hpp"
namespace namespace
{ {
@ -154,8 +156,8 @@ MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text)
typedef TypesetBook::Ptr book; typedef TypesetBook::Ptr book;
JournalBooks::JournalBooks (JournalViewModel::Ptr model) : JournalBooks::JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding) :
mModel (model) mModel (model), mEncoding(encoding)
{ {
} }
@ -217,34 +219,82 @@ book JournalBooks::createQuestBook (const std::string& questName)
} }
book JournalBooks::createTopicIndexBook () book JournalBooks::createTopicIndexBook ()
{
bool isRussian = (mEncoding == ToUTF8::WINDOWS_1251);
BookTypesetter::Ptr typesetter = isRussian ? createCyrillicJournalIndex() : createLatinJournalIndex();
return typesetter->complete ();
}
BookTypesetter::Ptr JournalBooks::createLatinJournalIndex ()
{ {
BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250); BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250);
typesetter->setSectionAlignment (BookTypesetter::AlignCenter); typesetter->setSectionAlignment (BookTypesetter::AlignCenter);
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black); char ch = 'A';
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
for (int i = 0; i < 26; ++i) for (int i = 0; i < 26; ++i)
{ {
char ch = 'A' + i;
char buffer [32]; char buffer [32];
sprintf (buffer, "( %c )", ch); sprintf (buffer, "( %c )", ch);
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours(); const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic, BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic,
textColours.journalTopicOver, textColours.journalTopicOver,
textColours.journalTopicPressed, ch); textColours.journalTopicPressed, (uint32_t) ch);
if (i == 13) if (i == 13)
typesetter->sectionBreak (); typesetter->sectionBreak ();
typesetter->write (style, to_utf8_span (buffer)); typesetter->write (style, to_utf8_span (buffer));
typesetter->lineBreak (); typesetter->lineBreak ();
ch++;
} }
return typesetter->complete (); return typesetter;
}
BookTypesetter::Ptr JournalBooks::createCyrillicJournalIndex ()
{
BookTypesetter::Ptr typesetter = BookTypesetter::create (92, 250);
typesetter->setSectionAlignment (BookTypesetter::AlignCenter);
BookTypesetter::Style* body = typesetter->createStyle ("", MyGUI::Colour::Black);
unsigned char ch[2] = {0xd0, 0x90}; // CYRILLIC CAPITAL A is a 0xd090 in UTF-8
for (int i = 0; i < 32; ++i)
{
char buffer [32];
sprintf(buffer, "( %c%c )", ch[0], ch[1]);
Utf8Stream stream ((char*) ch);
uint32_t first = stream.peek();
const MWGui::TextColours& textColours = MWBase::Environment::get().getWindowManager()->getTextColours();
BookTypesetter::Style* style = typesetter->createHotStyle (body, textColours.journalTopic,
textColours.journalTopicOver,
textColours.journalTopicPressed, first);
// Words can not be started with these characters
if (i == 26 || i == 28)
continue;
if (i == 15)
typesetter->sectionBreak ();
typesetter->write (style, to_utf8_span (buffer));
typesetter->lineBreak ();
ch[1]++;
}
return typesetter;
} }
BookTypesetter::Ptr JournalBooks::createTypesetter () BookTypesetter::Ptr JournalBooks::createTypesetter ()

@ -4,6 +4,8 @@
#include "bookpage.hpp" #include "bookpage.hpp"
#include "journalviewmodel.hpp" #include "journalviewmodel.hpp"
#include <components/to_utf8/to_utf8.hpp>
namespace MWGui namespace MWGui
{ {
MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text); MWGui::BookTypesetter::Utf8Span to_utf8_span (char const * text);
@ -13,7 +15,7 @@ namespace MWGui
typedef TypesetBook::Ptr Book; typedef TypesetBook::Ptr Book;
JournalViewModel::Ptr mModel; JournalViewModel::Ptr mModel;
JournalBooks (JournalViewModel::Ptr model); JournalBooks (JournalViewModel::Ptr model, ToUTF8::FromType encoding);
Book createEmptyJournalBook (); Book createEmptyJournalBook ();
Book createJournalBook (); Book createJournalBook ();
@ -22,8 +24,12 @@ namespace MWGui
Book createQuestBook (const std::string& questName); Book createQuestBook (const std::string& questName);
Book createTopicIndexBook (); Book createTopicIndexBook ();
ToUTF8::FromType mEncoding;
private: private:
BookTypesetter::Ptr createTypesetter (); BookTypesetter::Ptr createTypesetter ();
BookTypesetter::Ptr createLatinJournalIndex ();
BookTypesetter::Ptr createCyrillicJournalIndex ();
}; };
} }

@ -6,6 +6,8 @@
#include <MyGUI_LanguageManager.h> #include <MyGUI_LanguageManager.h>
#include <components/translation/translation.hpp> #include <components/translation/translation.hpp>
#include <components/misc/stringops.hpp>
#include <components/misc/utf8stream.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp" #include "../mwbase/journal.hpp"
@ -305,18 +307,37 @@ struct JournalViewModelImpl : JournalViewModel
visitor (toUtf8Span (topic.getName())); visitor (toUtf8Span (topic.getName()));
} }
void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const
{ {
MWBase::Journal * journal = MWBase::Environment::get().getJournal(); MWBase::Journal * journal = MWBase::Environment::get().getJournal();
for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i) for (MWBase::Journal::TTopicIter i = journal->topicBegin (); i != journal->topicEnd (); ++i)
{ {
if (i->first [0] != Misc::StringUtils::toLower(character)) Utf8Stream stream (i->first.c_str());
uint32_t first = toUpper(stream.peek());
if (first != character)
continue; continue;
visitor (i->second.getName()); visitor (i->second.getName());
} }
}
static uint32_t toUpper(uint32_t ch)
{
// Russian alphabet
if (ch >= 0x0430 && ch < 0x0450)
ch -= 0x20;
// Cyrillic IO character
if (ch == 0x0451)
ch -= 0x50;
// Latin alphabet
if (ch >= 0x61 && ch < 0x80)
ch -= 0x20;
return ch;
} }
struct TopicEntryImpl : BaseEntry <MWDialogue::Topic::TEntryIter, TopicEntry> struct TopicEntryImpl : BaseEntry <MWDialogue::Topic::TEntryIter, TopicEntry>

@ -75,8 +75,8 @@ namespace MWGui
/// provides the name of the topic specified by its id /// provides the name of the topic specified by its id
virtual void visitTopicName (TopicId topicId, std::function <void (Utf8Span)> visitor) const = 0; virtual void visitTopicName (TopicId topicId, std::function <void (Utf8Span)> visitor) const = 0;
/// walks over the topics whose names start with the specified character providing the topics name /// walks over the topics whose names start with the character
virtual void visitTopicNamesStartingWith (char character, std::function < void (const std::string&) > visitor) const = 0; virtual void visitTopicNamesStartingWith (uint32_t character, std::function < void (const std::string&) > visitor) const = 0;
/// walks over the topic entries for the topic specified by its identifier /// walks over the topic entries for the topic specified by its identifier
virtual void visitTopicEntries (TopicId topicId, std::function <void (TopicEntry const &)> visitor) const = 0; virtual void visitTopicEntries (TopicId topicId, std::function <void (TopicEntry const &)> visitor) const = 0;

@ -100,8 +100,8 @@ namespace
return getWidget <MWGui::BookPage> (name); return getWidget <MWGui::BookPage> (name);
} }
JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList) JournalWindowImpl (MWGui::JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding)
: JournalBooks (Model), JournalWindow() : JournalBooks (Model, encoding), JournalWindow()
{ {
center(); center();
@ -161,6 +161,15 @@ namespace
Gui::ImageButton* showActiveButton = getWidget<Gui::ImageButton>(ShowActiveBTN); Gui::ImageButton* showActiveButton = getWidget<Gui::ImageButton>(ShowActiveBTN);
Gui::ImageButton* showAllButton = getWidget<Gui::ImageButton>(ShowAllBTN); Gui::ImageButton* showAllButton = getWidget<Gui::ImageButton>(ShowAllBTN);
Gui::ImageButton* questsButton = getWidget<Gui::ImageButton>(QuestsBTN); Gui::ImageButton* questsButton = getWidget<Gui::ImageButton>(QuestsBTN);
Gui::ImageButton* nextButton = getWidget<Gui::ImageButton>(NextPageBTN);
if (nextButton->getSize().width == 64)
{
// english button has a 7 pixel wide strip of garbage on its right edge
nextButton->setSize(64-7, nextButton->getSize().height);
nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height));
}
if (!questList) if (!questList)
{ {
// If tribunal is not installed (-> no options button), we still want the Topics button available, // If tribunal is not installed (-> no options button), we still want the Topics button available,
@ -176,6 +185,8 @@ namespace
showActiveButton->setVisible(false); showActiveButton->setVisible(false);
showAllButton->setVisible(false); showAllButton->setVisible(false);
questsButton->setVisible(false); questsButton->setVisible(false);
adjustButton(TopicsBTN);
} }
else else
{ {
@ -188,33 +199,24 @@ namespace
adjustButton(ShowActiveBTN); adjustButton(ShowActiveBTN);
adjustButton(OptionsBTN); adjustButton(OptionsBTN);
adjustButton(QuestsBTN); adjustButton(QuestsBTN);
} adjustButton(TopicsBTN);
int topicsWidth = getWidget<MyGUI::Widget>(TopicsBTN)->getSize().width;
Gui::ImageButton* nextButton = getWidget<Gui::ImageButton>(NextPageBTN); int cancelLeft = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left;
if (nextButton->getSize().width == 64) int cancelRight = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left + getWidget<MyGUI::Widget>(CancelBTN)->getSize().width;
{
// english button has a 7 pixel wide strip of garbage on its right edge
nextButton->setSize(64-7, nextButton->getSize().height);
nextButton->setImageCoord(MyGUI::IntCoord(0,0,64-7,nextButton->getSize().height));
}
adjustButton(TopicsBTN);
int topicsWidth = getWidget<MyGUI::Widget>(TopicsBTN)->getSize().width;
int cancelLeft = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left;
int cancelRight = getWidget<MyGUI::Widget>(CancelBTN)->getPosition().left + getWidget<MyGUI::Widget>(CancelBTN)->getSize().width;
getWidget<MyGUI::Widget>(QuestsBTN)->setPosition(cancelRight, getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().top); getWidget<MyGUI::Widget>(QuestsBTN)->setPosition(cancelRight, getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().top);
// Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button. // Usually Topics, Quests, and Cancel buttons have the 64px width, so we can place the Topics left-up from the Cancel button, and the Quests right-up from the Cancel button.
// But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button. // But in some installations, e.g. German one, the Topics button has the 128px width, so we should place it exactly left from the Quests button.
if (getWidget<MyGUI::Widget>(TopicsBTN)->getSize().width == 64) if (topicsWidth == 64)
{ {
getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top); getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(cancelLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top);
} }
else else
{ {
int questLeft = getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().left; int questLeft = getWidget<MyGUI::Widget>(QuestsBTN)->getPosition().left;
getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top); getWidget<MyGUI::Widget>(TopicsBTN)->setPosition(questLeft - topicsWidth, getWidget<MyGUI::Widget>(TopicsBTN)->getPosition().top);
}
} }
mQuestMode = false; mQuestMode = false;
@ -475,7 +477,7 @@ namespace
MWBase::Environment::get().getWindowManager()->playSound("book page"); MWBase::Environment::get().getWindowManager()->playSound("book page");
} }
void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId character) void notifyIndexLinkClicked (MWGui::TypesetBook::InteractiveId index)
{ {
setVisible (LeftTopicIndex, false); setVisible (LeftTopicIndex, false);
setVisible (RightTopicIndex, false); setVisible (RightTopicIndex, false);
@ -488,7 +490,7 @@ namespace
AddNamesToList add(list); AddNamesToList add(list);
mModel->visitTopicNamesStartingWith((char) character, add); mModel->visitTopicNamesStartingWith(index, add);
list->adjustSize(); list->adjustSize();
@ -643,9 +645,9 @@ namespace
} }
// glue the implementation to the interface // glue the implementation to the interface
MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList) MWGui::JournalWindow * MWGui::JournalWindow::create (JournalViewModel::Ptr Model, bool questList, ToUTF8::FromType encoding)
{ {
return new JournalWindowImpl (Model, questList); return new JournalWindowImpl (Model, questList, encoding);
} }
MWGui::JournalWindow::JournalWindow() MWGui::JournalWindow::JournalWindow()

@ -3,6 +3,8 @@
#include "windowbase.hpp" #include "windowbase.hpp"
#include <components/to_utf8/to_utf8.hpp>
#include <memory> #include <memory>
namespace MWBase { class WindowManager; } namespace MWBase { class WindowManager; }
@ -16,7 +18,7 @@ namespace MWGui
JournalWindow(); JournalWindow();
/// construct a new instance of the one JournalWindow implementation /// construct a new instance of the one JournalWindow implementation
static JournalWindow * create (std::shared_ptr <JournalViewModel> Model, bool questList); static JournalWindow * create (std::shared_ptr <JournalViewModel> Model, bool questList, ToUTF8::FromType encoding);
/// destroy this instance of the JournalWindow implementation /// destroy this instance of the JournalWindow implementation
virtual ~JournalWindow () {}; virtual ~JournalWindow () {};

@ -204,6 +204,7 @@ namespace MWGui
, mRestAllowed(true) , mRestAllowed(true)
, mFallbackMap(fallbackMap) , mFallbackMap(fallbackMap)
, mShowOwned(0) , mShowOwned(0)
, mEncoding(encoding)
, mVersionDescription(versionDescription) , mVersionDescription(versionDescription)
{ {
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
@ -357,7 +358,7 @@ namespace MWGui
mGuiModeStates[GM_Console] = GuiModeState(mConsole); mGuiModeStates[GM_Console] = GuiModeState(mConsole);
bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds"); bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds");
JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList); JournalWindow* journal = JournalWindow::create(JournalViewModel::create (), questList, mEncoding);
mWindows.push_back(journal); mWindows.push_back(journal);
mGuiModeStates[GM_Journal] = GuiModeState(journal); mGuiModeStates[GM_Journal] = GuiModeState(journal);
mGuiModeStates[GM_Journal].mCloseSound = "book close"; mGuiModeStates[GM_Journal].mCloseSound = "book close";
@ -2115,5 +2116,4 @@ namespace MWGui
for (unsigned int i=0; i<mWindows.size(); ++i) for (unsigned int i=0; i<mWindows.size(); ++i)
mWindows[i]->setVisible(visible); mWindows[i]->setVisible(visible);
} }
} }

@ -531,6 +531,8 @@ namespace MWGui
int mShowOwned; int mShowOwned;
ToUTF8::FromType mEncoding;
std::string mVersionDescription; std::string mVersionDescription;
MWGui::TextColours mTextColours; MWGui::TextColours mTextColours;

@ -4,6 +4,7 @@
#include <iostream> #include <iostream>
#include <osg/PositionAttitudeTransform> #include <osg/PositionAttitudeTransform>
#include <osg/ComputeBoundsVisitor>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/esm/projectilestate.hpp> #include <components/esm/projectilestate.hpp>
@ -202,6 +203,12 @@ namespace MWWorld
osg::ref_ptr<osg::Node> projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo); osg::ref_ptr<osg::Node> projectile = mResourceSystem->getSceneManager()->getInstance(model, attachTo);
osg::ref_ptr<osg::ComputeBoundsVisitor> boundVisitor = new osg::ComputeBoundsVisitor();
projectile->accept(*boundVisitor.get());
osg::BoundingBox bb = boundVisitor->getBoundingBox();
state.mNode->setPivotPoint(bb.center());
if (state.mIdMagic.size() > 1) if (state.mIdMagic.size() > 1)
for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter) for (size_t iter = 1; iter != state.mIdMagic.size(); ++iter)
{ {
@ -316,6 +323,7 @@ namespace MWWorld
state.mIdArrow = projectile.getCellRef().getRefId(); state.mIdArrow = projectile.getCellRef().getRefId();
state.mCasterHandle = actor; state.mCasterHandle = actor;
state.mAttackStrength = attackStrength; state.mAttackStrength = attackStrength;
state.mThrown = projectile.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown;
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId()); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
MWWorld::Ptr ptr = ref.getPtr(); MWWorld::Ptr ptr = ref.getPtr();
@ -378,7 +386,6 @@ namespace MWWorld
static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("fTargetSpellMaxSpeed")->getFloat(); .find("fTargetSpellMaxSpeed")->getFloat();
float speed = fTargetSpellMaxSpeed * it->mSpeed; float speed = fTargetSpellMaxSpeed * it->mSpeed;
osg::Vec3f direction = orient * osg::Vec3f(0,1,0); osg::Vec3f direction = orient * osg::Vec3f(0,1,0);
direction.normalize(); direction.normalize();
osg::Vec3f pos(it->mNode->getPosition()); osg::Vec3f pos(it->mNode->getPosition());
@ -458,7 +465,22 @@ namespace MWWorld
osg::Vec3f newPos = pos + it->mVelocity * duration; osg::Vec3f newPos = pos + it->mVelocity * duration;
osg::Quat orient; osg::Quat orient;
orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity);
if (it->mThrown)
orient.set(
osg::Matrixd::rotate(it->mEffectAnimationTime->getTime() * -10.0,osg::Vec3f(0,0,1)) *
osg::Matrixd::rotate(osg::PI / 2.0,osg::Vec3f(0,1,0)) *
osg::Matrixd::rotate(-1 * osg::PI / 2.0,osg::Vec3f(1,0,0)) *
osg::Matrixd::inverse(
osg::Matrixd::lookAt(
osg::Vec3f(0,0,0),
it->mVelocity,
osg::Vec3f(0,0,1))
)
);
else
orient.makeRotate(osg::Vec3f(0,1,0), it->mVelocity);
it->mNode->setAttitude(orient); it->mNode->setAttitude(orient);
it->mNode->setPosition(newPos); it->mNode->setPosition(newPos);
@ -596,6 +618,7 @@ namespace MWWorld
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
MWWorld::Ptr ptr = ref.getPtr(); MWWorld::Ptr ptr = ref.getPtr();
model = ptr.getClass().getModel(ptr); model = ptr.getClass().getModel(ptr);
state.mThrown = ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown;
} }
catch(...) catch(...)
{ {

@ -112,6 +112,7 @@ namespace MWWorld
osg::Vec3f mVelocity; osg::Vec3f mVelocity;
float mAttackStrength; float mAttackStrength;
bool mThrown;
}; };
std::vector<MagicBoltState> mMagicBolts; std::vector<MagicBoltState> mMagicBolts;

@ -18,6 +18,11 @@ public:
{ {
} }
Utf8Stream (const char * str) :
cur ((unsigned char*) str), nxt ((unsigned char*) str), end ((unsigned char*) str + strlen(str)), val(Utf8Stream::sBadChar())
{
}
Utf8Stream (std::pair <Point, Point> range) : Utf8Stream (std::pair <Point, Point> range) :
cur (range.first), nxt (range.first), end (range.second), val(Utf8Stream::sBadChar()) cur (range.first), nxt (range.first), end (range.second), val(Utf8Stream::sBadChar())
{ {

Loading…
Cancel
Save