forked from mirror/openmw-tes3mp
Fixed conflicts
Merge branch 'cs-windows' of https://github.com/Glorf/openmw Conflicts: apps/opencs/model/settings/usersettings.cpp apps/opencs/model/settings/usersettings.hpp apps/opencs/view/settings/usersettingsdialog.cppactorid
commit
f87eb67968
@ -0,0 +1,114 @@
|
|||||||
|
#include "windowpage.hpp"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QListView>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QRadioButton>
|
||||||
|
#include <QDockWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QStyle>
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#include <QPlastiqueStyle>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../../model/settings/usersettings.hpp"
|
||||||
|
#include "groupblock.hpp"
|
||||||
|
#include "toggleblock.hpp"
|
||||||
|
|
||||||
|
CSVSettings::WindowPage::WindowPage(QWidget *parent):
|
||||||
|
AbstractPage("Window Size", parent)
|
||||||
|
{
|
||||||
|
// Hacks to get the stylesheet look properly
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
QPlastiqueStyle *style = new QPlastiqueStyle;
|
||||||
|
//profilesComboBox->setStyle(style);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
setupUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVSettings::WindowPage::setupUi()
|
||||||
|
{
|
||||||
|
GroupBlockDef customWindowSize (QString ("Custom Window Size"));
|
||||||
|
GroupBlockDef definedWindowSize (QString ("Pre-Defined Window Size"));
|
||||||
|
GroupBlockDef windowSizeToggle (QString ("Window Size"));
|
||||||
|
CustomBlockDef windowSize (QString ("Window Size"));
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////
|
||||||
|
//custom window size properties
|
||||||
|
///////////////////////////////
|
||||||
|
|
||||||
|
//custom width
|
||||||
|
SettingsItemDef *widthItem = new SettingsItemDef ("Width", "640");
|
||||||
|
widthItem->widget = WidgetDef (Widget_LineEdit);
|
||||||
|
widthItem->widget.widgetWidth = 45;
|
||||||
|
|
||||||
|
//custom height
|
||||||
|
SettingsItemDef *heightItem = new SettingsItemDef ("Height", "480");
|
||||||
|
heightItem->widget = WidgetDef (Widget_LineEdit);
|
||||||
|
heightItem->widget.widgetWidth = 45;
|
||||||
|
heightItem->widget.caption = "x";
|
||||||
|
|
||||||
|
customWindowSize.properties << widthItem << heightItem;
|
||||||
|
customWindowSize.widgetOrientation = Orient_Horizontal;
|
||||||
|
customWindowSize.isVisible = false;
|
||||||
|
|
||||||
|
|
||||||
|
//pre-defined
|
||||||
|
SettingsItemDef *widthByHeightItem = new SettingsItemDef ("Window Size", "640x480");
|
||||||
|
WidgetDef widthByHeightWidget = WidgetDef (Widget_ComboBox);
|
||||||
|
widthByHeightWidget.widgetWidth = 90;
|
||||||
|
*(widthByHeightItem->valueList) << "640x480" << "800x600" << "1024x768" << "1440x900";
|
||||||
|
|
||||||
|
QStringList *widthProxy = new QStringList;
|
||||||
|
QStringList *heightProxy = new QStringList;
|
||||||
|
|
||||||
|
(*widthProxy) << "Width" << "640" << "800" << "1024" << "1440";
|
||||||
|
(*heightProxy) << "Height" << "480" << "600" << "768" << "900";
|
||||||
|
|
||||||
|
*(widthByHeightItem->proxyList) << widthProxy << heightProxy;
|
||||||
|
|
||||||
|
widthByHeightItem->widget = widthByHeightWidget;
|
||||||
|
|
||||||
|
definedWindowSize.properties << widthByHeightItem;
|
||||||
|
definedWindowSize.isProxy = true;
|
||||||
|
definedWindowSize.isVisible = false;
|
||||||
|
|
||||||
|
// window size toggle
|
||||||
|
windowSizeToggle.captions << "Pre-Defined" << "Custom";
|
||||||
|
windowSizeToggle.widgetOrientation = Orient_Vertical;
|
||||||
|
windowSizeToggle.isVisible = false;
|
||||||
|
|
||||||
|
//define a widget for each group in the toggle
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
windowSizeToggle.widgets << new WidgetDef (Widget_RadioButton);
|
||||||
|
|
||||||
|
windowSizeToggle.widgets.at(0)->isDefault = false;
|
||||||
|
|
||||||
|
windowSize.blockDefList << &windowSizeToggle << &definedWindowSize << &customWindowSize;
|
||||||
|
windowSize.defaultValue = "Custom";
|
||||||
|
|
||||||
|
QGridLayout *pageLayout = new QGridLayout(this);
|
||||||
|
|
||||||
|
setLayout (pageLayout);
|
||||||
|
|
||||||
|
mAbstractBlocks << buildBlock<ToggleBlock> (windowSize);
|
||||||
|
|
||||||
|
foreach (AbstractBlock *block, mAbstractBlocks)
|
||||||
|
{
|
||||||
|
connect (block, SIGNAL (signalUpdateSetting (const QString &, const QString &)),
|
||||||
|
this, SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVSettings::WindowPage::initializeWidgets (const CSMSettings::SettingMap &settings)
|
||||||
|
{
|
||||||
|
//iterate each item in each blocks in this section
|
||||||
|
//validate the corresponding setting against the defined valuelist if any.
|
||||||
|
for (AbstractBlockList::Iterator it_block = mAbstractBlocks.begin();
|
||||||
|
it_block != mAbstractBlocks.end(); ++it_block)
|
||||||
|
(*it_block)->updateSettings (settings);
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef WINDOWPAGE_H
|
||||||
|
#define WINDOWPAGE_H
|
||||||
|
|
||||||
|
#include "abstractpage.hpp"
|
||||||
|
|
||||||
|
class QGroupBox;
|
||||||
|
|
||||||
|
namespace CSVSettings {
|
||||||
|
|
||||||
|
class UserSettings;
|
||||||
|
class AbstractBlock;
|
||||||
|
|
||||||
|
class WindowPage : public AbstractPage
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
WindowPage(QWidget *parent = 0);
|
||||||
|
|
||||||
|
void setupUi();
|
||||||
|
void initializeWidgets (const CSMSettings::SettingMap &settings);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //WINDOWPAGE_H
|
@ -0,0 +1,238 @@
|
|||||||
|
#include "fontloader.hpp"
|
||||||
|
|
||||||
|
#include <OgreResourceGroupManager.h>
|
||||||
|
#include <OgreTextureManager.h>
|
||||||
|
|
||||||
|
#include <MyGUI_ResourceManager.h>
|
||||||
|
#include <MyGUI_FontManager.h>
|
||||||
|
#include <MyGUI_ResourceManualFont.h>
|
||||||
|
#include <MyGUI_XmlDocument.h>
|
||||||
|
#include <MyGUI_FactoryManager.h>
|
||||||
|
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
unsigned long utf8ToUnicode(const std::string& utf8)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
unsigned long unicode;
|
||||||
|
size_t todo;
|
||||||
|
unsigned char ch = utf8[i++];
|
||||||
|
if (ch <= 0x7F)
|
||||||
|
{
|
||||||
|
unicode = ch;
|
||||||
|
todo = 0;
|
||||||
|
}
|
||||||
|
else if (ch <= 0xBF)
|
||||||
|
{
|
||||||
|
throw std::logic_error("not a UTF-8 string");
|
||||||
|
}
|
||||||
|
else if (ch <= 0xDF)
|
||||||
|
{
|
||||||
|
unicode = ch&0x1F;
|
||||||
|
todo = 1;
|
||||||
|
}
|
||||||
|
else if (ch <= 0xEF)
|
||||||
|
{
|
||||||
|
unicode = ch&0x0F;
|
||||||
|
todo = 2;
|
||||||
|
}
|
||||||
|
else if (ch <= 0xF7)
|
||||||
|
{
|
||||||
|
unicode = ch&0x07;
|
||||||
|
todo = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::logic_error("not a UTF-8 string");
|
||||||
|
}
|
||||||
|
for (size_t j = 0; j < todo; ++j)
|
||||||
|
{
|
||||||
|
unsigned char ch = utf8[i++];
|
||||||
|
if (ch < 0x80 || ch > 0xBF)
|
||||||
|
throw std::logic_error("not a UTF-8 string");
|
||||||
|
unicode <<= 6;
|
||||||
|
unicode += ch & 0x3F;
|
||||||
|
}
|
||||||
|
if (unicode >= 0xD800 && unicode <= 0xDFFF)
|
||||||
|
throw std::logic_error("not a UTF-8 string");
|
||||||
|
if (unicode > 0x10FFFF)
|
||||||
|
throw std::logic_error("not a UTF-8 string");
|
||||||
|
|
||||||
|
return unicode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
|
||||||
|
FontLoader::FontLoader(ToUTF8::FromType encoding)
|
||||||
|
{
|
||||||
|
if (encoding == ToUTF8::WINDOWS_1252)
|
||||||
|
mEncoding = ToUTF8::CP437;
|
||||||
|
else
|
||||||
|
mEncoding = encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontLoader::loadAllFonts()
|
||||||
|
{
|
||||||
|
Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups ();
|
||||||
|
for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it)
|
||||||
|
{
|
||||||
|
Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "*.fnt");
|
||||||
|
for (Ogre::StringVector::iterator resource = resourcesInThisGroup->begin(); resource != resourcesInThisGroup->end(); ++resource)
|
||||||
|
{
|
||||||
|
loadFont(*resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} Point;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float u1; // appears unused, always 0
|
||||||
|
Point top_left;
|
||||||
|
Point top_right;
|
||||||
|
Point bottom_left;
|
||||||
|
Point bottom_right;
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
float u2; // appears unused, always 0
|
||||||
|
float kerning;
|
||||||
|
float ascent;
|
||||||
|
} GlyphInfo;
|
||||||
|
|
||||||
|
void FontLoader::loadFont(const std::string &fileName)
|
||||||
|
{
|
||||||
|
Ogre::DataStreamPtr file = Ogre::ResourceGroupManager::getSingleton().openResource(fileName);
|
||||||
|
|
||||||
|
float fontSize;
|
||||||
|
int one;
|
||||||
|
file->read(&fontSize, sizeof(fontSize));
|
||||||
|
|
||||||
|
file->read(&one, sizeof(int));
|
||||||
|
assert(one == 1);
|
||||||
|
file->read(&one, sizeof(int));
|
||||||
|
assert(one == 1);
|
||||||
|
|
||||||
|
char name_[284];
|
||||||
|
file->read(name_, sizeof(name_));
|
||||||
|
std::string name(name_);
|
||||||
|
|
||||||
|
GlyphInfo data[256];
|
||||||
|
file->read(data, sizeof(data));
|
||||||
|
file->close();
|
||||||
|
|
||||||
|
// Create the font texture
|
||||||
|
std::string bitmapFilename = "Fonts/" + std::string(name) + ".tex";
|
||||||
|
Ogre::DataStreamPtr bitmapFile = Ogre::ResourceGroupManager::getSingleton().openResource(bitmapFilename);
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
bitmapFile->read(&width, sizeof(int));
|
||||||
|
bitmapFile->read(&height, sizeof(int));
|
||||||
|
|
||||||
|
std::vector<Ogre::uchar> textureData;
|
||||||
|
textureData.resize(width*height*4);
|
||||||
|
bitmapFile->read(&textureData[0], width*height*4);
|
||||||
|
bitmapFile->close();
|
||||||
|
|
||||||
|
std::string textureName = name;
|
||||||
|
Ogre::Image image;
|
||||||
|
image.loadDynamicImage(&textureData[0], width, height, Ogre::PF_BYTE_RGBA);
|
||||||
|
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual(textureName,
|
||||||
|
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
|
||||||
|
Ogre::TEX_TYPE_2D,
|
||||||
|
width, height, 0, Ogre::PF_BYTE_RGBA);
|
||||||
|
texture->loadImage(image);
|
||||||
|
|
||||||
|
// Register the font with MyGUI
|
||||||
|
MyGUI::ResourceManualFont* font = static_cast<MyGUI::ResourceManualFont*>(
|
||||||
|
MyGUI::FactoryManager::getInstance().createObject("Resource", "ResourceManualFont"));
|
||||||
|
// We need to emulate loading from XML because the data members are private as of mygui 3.2.0
|
||||||
|
MyGUI::xml::Document xmlDocument;
|
||||||
|
MyGUI::xml::ElementPtr root = xmlDocument.createRoot("ResourceManualFont");
|
||||||
|
|
||||||
|
if (name.size() >= 5 && Misc::StringUtils::ciEqual(name.substr(0, 5), "magic"))
|
||||||
|
root->addAttribute("name", "Magic Cards");
|
||||||
|
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "century"))
|
||||||
|
root->addAttribute("name", "Century Gothic");
|
||||||
|
else if (name.size() >= 7 && Misc::StringUtils::ciEqual(name.substr(0, 7), "daedric"))
|
||||||
|
root->addAttribute("name", "Daedric");
|
||||||
|
else
|
||||||
|
return; // no point in loading it, since there is no way of using additional fonts
|
||||||
|
|
||||||
|
MyGUI::xml::ElementPtr defaultHeight = root->createChild("Property");
|
||||||
|
defaultHeight->addAttribute("key", "DefaultHeight");
|
||||||
|
defaultHeight->addAttribute("value", fontSize);
|
||||||
|
MyGUI::xml::ElementPtr source = root->createChild("Property");
|
||||||
|
source->addAttribute("key", "Source");
|
||||||
|
source->addAttribute("value", std::string(textureName));
|
||||||
|
MyGUI::xml::ElementPtr codes = root->createChild("Codes");
|
||||||
|
|
||||||
|
for(int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
int x1 = data[i].top_left.x*width;
|
||||||
|
int y1 = data[i].top_left.y*height;
|
||||||
|
int w = data[i].top_right.x*width - x1;
|
||||||
|
int h = data[i].bottom_left.y*height - y1;
|
||||||
|
|
||||||
|
ToUTF8::Utf8Encoder encoder(mEncoding);
|
||||||
|
unsigned long unicodeVal = utf8ToUnicode(encoder.getUtf8(std::string(1, (unsigned char)(i))));
|
||||||
|
|
||||||
|
MyGUI::xml::ElementPtr code = codes->createChild("Code");
|
||||||
|
code->addAttribute("index", unicodeVal);
|
||||||
|
code->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||||
|
+ MyGUI::utility::toString(y1) + " "
|
||||||
|
+ MyGUI::utility::toString(w) + " "
|
||||||
|
+ MyGUI::utility::toString(h));
|
||||||
|
code->addAttribute("advance", data[i].width);
|
||||||
|
code->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||||
|
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||||
|
|
||||||
|
// ASCII vertical bar, use this as text input cursor
|
||||||
|
if (i == 124)
|
||||||
|
{
|
||||||
|
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||||
|
cursorCode->addAttribute("index", MyGUI::FontCodeType::Cursor);
|
||||||
|
cursorCode->addAttribute("coord", MyGUI::utility::toString(x1) + " "
|
||||||
|
+ MyGUI::utility::toString(y1) + " "
|
||||||
|
+ MyGUI::utility::toString(w) + " "
|
||||||
|
+ MyGUI::utility::toString(h));
|
||||||
|
cursorCode->addAttribute("advance", data[i].width);
|
||||||
|
cursorCode->addAttribute("bearing", MyGUI::utility::toString(data[i].kerning) + " "
|
||||||
|
+ MyGUI::utility::toString((fontSize-data[i].ascent)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are required as well, but the fonts don't provide them
|
||||||
|
for (int i=0; i<3; ++i)
|
||||||
|
{
|
||||||
|
MyGUI::FontCodeType::Enum type;
|
||||||
|
if(i == 0)
|
||||||
|
type = MyGUI::FontCodeType::Selected;
|
||||||
|
else if (i == 1)
|
||||||
|
type = MyGUI::FontCodeType::SelectedBack;
|
||||||
|
else if (i == 2)
|
||||||
|
type = MyGUI::FontCodeType::NotDefined;
|
||||||
|
|
||||||
|
MyGUI::xml::ElementPtr cursorCode = codes->createChild("Code");
|
||||||
|
cursorCode->addAttribute("index", type);
|
||||||
|
cursorCode->addAttribute("coord", "0 0 0 0");
|
||||||
|
cursorCode->addAttribute("advance", "0");
|
||||||
|
cursorCode->addAttribute("bearing", "0 0");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
font->deserialization(root, MyGUI::Version(3,2,0));
|
||||||
|
|
||||||
|
MyGUI::ResourceManager::getInstance().addResource(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef MWGUI_FONTLOADER_H
|
||||||
|
#define MWGUI_FONTLOADER_H
|
||||||
|
|
||||||
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
|
||||||
|
namespace MWGui
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and Ogre
|
||||||
|
class FontLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FontLoader (ToUTF8::FromType encoding);
|
||||||
|
void loadAllFonts ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ToUTF8::FromType mEncoding;
|
||||||
|
|
||||||
|
void loadFont (const std::string& fileName);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,23 +1,337 @@
|
|||||||
#include "aiwander.hpp"
|
#include "aiwander.hpp"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
#include "movement.hpp"
|
||||||
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MWMechanics::AiPackage * MWMechanics::AiWander::clone() const
|
#include "../mwworld/class.hpp"
|
||||||
{
|
#include "../mwworld/player.hpp"
|
||||||
return new AiWander(*this);
|
#include "../mwbase/world.hpp"
|
||||||
}
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
|
namespace
|
||||||
{
|
{
|
||||||
// Return completed
|
float sgn(float a)
|
||||||
return true;
|
{
|
||||||
|
if(a > 0)
|
||||||
|
return 1.0;
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::AiWander::getTypeId() const
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
return 0;
|
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
|
||||||
|
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
|
||||||
|
{
|
||||||
|
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
|
||||||
|
{
|
||||||
|
if(mIdle[counter] >= 127 || mIdle[counter] < 0)
|
||||||
|
mIdle[counter] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mDistance < 0)
|
||||||
|
mDistance = 0;
|
||||||
|
if(mDuration < 0)
|
||||||
|
mDuration = 0;
|
||||||
|
if(mDuration == 0)
|
||||||
|
mTimeOfDay = 0;
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
mStartTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
|
mPlayedIdle = 0;
|
||||||
|
mPathgrid = NULL;
|
||||||
|
mIdleChanceMultiplier =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
||||||
|
|
||||||
|
mStoredAvailableNodes = false;
|
||||||
|
mChooseAction = true;
|
||||||
|
mIdleNow = false;
|
||||||
|
mMoveNow = false;
|
||||||
|
mWalking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AiPackage * MWMechanics::AiWander::clone() const
|
||||||
|
{
|
||||||
|
return new AiWander(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AiWander::execute (const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
if(mDuration)
|
||||||
|
{
|
||||||
|
// End package if duration is complete or mid-night hits:
|
||||||
|
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
|
if(currentTime.getHour() >= mStartTime.getHour() + mDuration)
|
||||||
|
{
|
||||||
|
if(!mRepeat)
|
||||||
|
{
|
||||||
|
stopWalking(actor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mStartTime = currentTime;
|
||||||
|
}
|
||||||
|
else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())
|
||||||
|
{
|
||||||
|
if(!mRepeat)
|
||||||
|
{
|
||||||
|
stopWalking(actor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mStartTime = currentTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
|
||||||
|
if(!mStoredAvailableNodes)
|
||||||
|
{
|
||||||
|
mStoredAvailableNodes = true;
|
||||||
|
mPathgrid =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
|
||||||
|
|
||||||
|
mCellX = actor.getCell()->mCell->mData.mX;
|
||||||
|
mCellY = actor.getCell()->mCell->mData.mY;
|
||||||
|
|
||||||
|
if(!mPathgrid)
|
||||||
|
mDistance = 0;
|
||||||
|
else if(mPathgrid->mPoints.empty())
|
||||||
|
mDistance = 0;
|
||||||
|
|
||||||
|
if(mDistance)
|
||||||
|
{
|
||||||
|
mXCell = 0;
|
||||||
|
mYCell = 0;
|
||||||
|
if(actor.getCell()->mCell->isExterior())
|
||||||
|
{
|
||||||
|
mXCell = mCellX * ESM::Land::REAL_SIZE;
|
||||||
|
mYCell = mCellY * ESM::Land::REAL_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos);
|
||||||
|
npcPos[0] = npcPos[0] - mXCell;
|
||||||
|
npcPos[1] = npcPos[1] - mYCell;
|
||||||
|
|
||||||
|
for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++)
|
||||||
|
{
|
||||||
|
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY,
|
||||||
|
mPathgrid->mPoints[counter].mZ);
|
||||||
|
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
|
||||||
|
mAllowedNodes.push_back(mPathgrid->mPoints[counter]);
|
||||||
|
}
|
||||||
|
if(!mAllowedNodes.empty())
|
||||||
|
{
|
||||||
|
Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ);
|
||||||
|
float closestNode = npcPos.squaredDistance(firstNodePos);
|
||||||
|
unsigned int index = 0;
|
||||||
|
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
|
||||||
|
{
|
||||||
|
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
|
||||||
|
mAllowedNodes[counterThree].mZ);
|
||||||
|
float tempDist = npcPos.squaredDistance(nodePos);
|
||||||
|
if(tempDist < closestNode)
|
||||||
|
index = counterThree;
|
||||||
|
}
|
||||||
|
mCurrentNode = mAllowedNodes[index];
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mAllowedNodes.empty())
|
||||||
|
mDistance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||||
|
bool cellChange = actor.getCell()->mCell->mData.mX != mCellX || actor.getCell()->mCell->mData.mY != mCellY;
|
||||||
|
|
||||||
|
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
|
||||||
|
{
|
||||||
|
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
|
||||||
|
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||||
|
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||||
|
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
|
||||||
|
2.0 - 200))
|
||||||
|
{
|
||||||
|
stopWalking(actor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY)
|
||||||
|
{
|
||||||
|
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
|
||||||
|
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
|
||||||
|
// FIXME: This *should* pause the AiWander package instead of terminating it.
|
||||||
|
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
|
||||||
|
2.0 - 200))
|
||||||
|
{
|
||||||
|
stopWalking(actor);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles.
|
||||||
|
if(mDistance && (cellChange || (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)))
|
||||||
|
mDistance = 0;
|
||||||
|
|
||||||
|
if(mChooseAction)
|
||||||
|
{
|
||||||
|
mPlayedIdle = 0;
|
||||||
|
unsigned short idleRoll = 0;
|
||||||
|
|
||||||
|
for(unsigned int counter = 1; counter < mIdle.size(); counter++)
|
||||||
|
{
|
||||||
|
unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter];
|
||||||
|
unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier));
|
||||||
|
if(randSelect < idleChance && randSelect > idleRoll)
|
||||||
|
{
|
||||||
|
mPlayedIdle = counter;
|
||||||
|
idleRoll = randSelect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mPlayedIdle && mDistance)
|
||||||
|
{
|
||||||
|
mChooseAction = false;
|
||||||
|
mMoveNow = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander:
|
||||||
|
MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
|
mStartTime = currentTime;
|
||||||
|
playIdle(actor, mPlayedIdle + 1);
|
||||||
|
mChooseAction = false;
|
||||||
|
mIdleNow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mIdleNow)
|
||||||
|
{
|
||||||
|
if(!checkIdle(actor, mPlayedIdle + 1))
|
||||||
|
{
|
||||||
|
mPlayedIdle = 0;
|
||||||
|
mIdleNow = false;
|
||||||
|
mChooseAction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mMoveNow && mDistance)
|
||||||
|
{
|
||||||
|
if(!mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size());
|
||||||
|
Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ);
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point dest;
|
||||||
|
dest.mX = destNodePos[0] + mXCell;
|
||||||
|
dest.mY = destNodePos[1] + mYCell;
|
||||||
|
dest.mZ = destNodePos[2];
|
||||||
|
|
||||||
|
ESM::Pathgrid::Point start;
|
||||||
|
start.mX = pos.pos[0];
|
||||||
|
start.mY = pos.pos[1];
|
||||||
|
start.mZ = pos.pos[2];
|
||||||
|
|
||||||
|
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false);
|
||||||
|
|
||||||
|
if(mPathFinder.isPathConstructed())
|
||||||
|
{
|
||||||
|
// Remove this node as an option and add back the previously used node (stops NPC from picking the same node):
|
||||||
|
ESM::Pathgrid::Point temp = mAllowedNodes[randNode];
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||||
|
mAllowedNodes.push_back(mCurrentNode);
|
||||||
|
mCurrentNode = temp;
|
||||||
|
|
||||||
|
mMoveNow = false;
|
||||||
|
mWalking = true;
|
||||||
|
}
|
||||||
|
// Choose a different node and delete this one from possible nodes because it is uncreachable:
|
||||||
|
else
|
||||||
|
mAllowedNodes.erase(mAllowedNodes.begin() + randNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mWalking)
|
||||||
|
{
|
||||||
|
float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]);
|
||||||
|
MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle,false);
|
||||||
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1;
|
||||||
|
|
||||||
|
// Unclog path nodes by allowing the NPC to be a small distance away from the center. This way two NPCs can be
|
||||||
|
// at the same path node at the same time and both will complete instead of endlessly walking into eachother:
|
||||||
|
Ogre::Vector3 destNodePos(mCurrentNode.mX, mCurrentNode.mY, mCurrentNode.mZ);
|
||||||
|
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
|
||||||
|
actorPos[0] = actorPos[0] - mXCell;
|
||||||
|
actorPos[1] = actorPos[1] - mYCell;
|
||||||
|
float distance = actorPos.squaredDistance(destNodePos);
|
||||||
|
|
||||||
|
if(distance < 1200 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
|
||||||
|
{
|
||||||
|
stopWalking(actor);
|
||||||
|
mMoveNow = false;
|
||||||
|
mWalking = false;
|
||||||
|
mChooseAction = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AiWander::getTypeId() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||||
|
{
|
||||||
|
mPathFinder.clearPath();
|
||||||
|
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||||
|
{
|
||||||
|
if(idleSelect == 2)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1);
|
||||||
|
else if(idleSelect == 3)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle3", 0, 1);
|
||||||
|
else if(idleSelect == 4)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle4", 0, 1);
|
||||||
|
else if(idleSelect == 5)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle5", 0, 1);
|
||||||
|
else if(idleSelect == 6)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle6", 0, 1);
|
||||||
|
else if(idleSelect == 7)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle7", 0, 1);
|
||||||
|
else if(idleSelect == 8)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle8", 0, 1);
|
||||||
|
else if(idleSelect == 9)
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
|
||||||
|
{
|
||||||
|
if(idleSelect == 2)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2");
|
||||||
|
else if(idleSelect == 3)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle3");
|
||||||
|
else if(idleSelect == 4)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle4");
|
||||||
|
else if(idleSelect == 5)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle5");
|
||||||
|
else if(idleSelect == 6)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle6");
|
||||||
|
else if(idleSelect == 7)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle7");
|
||||||
|
else if(idleSelect == 8)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle8");
|
||||||
|
else if(idleSelect == 9)
|
||||||
|
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle9");
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 840 B After Width: | Height: | Size: 862 B |
Binary file not shown.
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.7 KiB |
Loading…
Reference in New Issue