Merge remote-tracking branch 'scrawl/master'

This commit is contained in:
Marc Zinnschlag 2014-01-11 11:43:12 +01:00
commit 1b03eec63e
46 changed files with 390 additions and 154 deletions

View file

@ -6,6 +6,7 @@
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <OgreEntity.h>
#include <OgreCamera.h>
namespace CSVRender
{

View file

@ -112,6 +112,8 @@ namespace MWBase
OffenseType type, int arg=0) = 0;
/// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0;
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item) = 0;
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
/// @return was it illegal, and someone saw you doing it?
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed) = 0;

View file

@ -227,9 +227,6 @@ namespace MWBase
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), bool showInDialogueModeOnly = false) = 0;
virtual void staticMessageBox(const std::string& message) = 0;
virtual void removeStaticMessageBox() = 0;
virtual void enterPressed () = 0;
virtual void activateKeyPressed () = 0;
virtual int readPressedButton() = 0;
///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)

View file

@ -157,6 +157,10 @@ namespace MWBase
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.
virtual MWWorld::Ptr searchPtr (const std::string& name, bool activeOnly) = 0;
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.
virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0;
///< Return a pointer to a liveCellRef with the given Ogre handle.
@ -451,6 +455,11 @@ namespace MWBase
/// Update the value of some globals according to the world state, which may be used by dialogue entries.
/// This should be called when initiating a dialogue.
virtual void updateDialogueGlobals() = 0;
/// Moves all stolen items from \a ptr to the closest evidence chest.
virtual void confiscateStolenItems(const MWWorld::Ptr& ptr) = 0;
virtual void goToJail () = 0;
};
}

View file

@ -307,6 +307,17 @@ namespace MWClass
autoCalculateSkills(ref->mBase, data->mNpcStats);
}
if (data->mNpcStats.getFactionRanks().size())
{
static const int iAutoRepFacMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("iAutoRepFacMod")->getInt();
static const int iAutoRepLevMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("iAutoRepLevMod")->getInt();
int rank = data->mNpcStats.getFactionRanks().begin()->second;
data->mNpcStats.setReputation(iAutoRepFacMod * (rank+1) + iAutoRepLevMod * (data->mNpcStats.getLevel()-1));
}
data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mNpcStats.setAiSetting (MWMechanics::CreatureStats::AI_Hello, ref->mBase->mAiData.mHello);
@ -587,6 +598,10 @@ namespace MWClass
// NOTE: 'object' and/or 'attacker' may be empty.
// Attacking peaceful NPCs is a crime
if (ptr.getClass().getCreatureStats(ptr).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault);
if(!successful)
{
// TODO: Handle HitAttemptOnMe script function
@ -615,7 +630,13 @@ namespace MWClass
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
// something, alert the character controller, scripts, etc.
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
{
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
}
getCreatureStats(ptr).setAttacked(true);//used in CharacterController
if(object.isEmpty())

View file

@ -29,11 +29,12 @@ namespace MWGui
MyGUI::Button* backButton;
getWidget(backButton, "BackButton");
backButton->setCaptionWithReplacing("#{sMessageQuestionAnswer3}");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
MyGUI::Button* okButton;
getWidget(okButton, "OKButton");
okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", ""));
okButton->setCaptionWithReplacing("#{sMessageQuestionAnswer2}");
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
}

View file

@ -139,6 +139,7 @@ namespace MWGui
mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked);
mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked);
mCloseButton->eventKeyButtonPressed += MyGUI::newDelegate(this, &ContainerWindow::onKeyPressed);
mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked);
setCoord(200,0,600,300);
@ -234,11 +235,21 @@ namespace MWGui
mItemView->setModel (mSortModel);
MyGUI::InputManager::getInstance().setKeyFocusWidget(mCloseButton);
// Careful here. setTitle may cause size updates, causing itemview redraw, so make sure to do it last
// or we end up using a possibly invalid model.
setTitle(MWWorld::Class::get(container).getName(container));
}
void ContainerWindow::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char)
{
if (_key == MyGUI::KeyCode::Space)
onCloseButtonClicked(mCloseButton);
if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter)
onTakeAllButtonClicked(mTakeButton);
}
void ContainerWindow::close()
{
WindowBase::close();

View file

@ -75,6 +75,7 @@ namespace MWGui
void onCloseButtonClicked(MyGUI::Widget* _sender);
void onTakeAllButtonClicked(MyGUI::Widget* _sender);
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);
void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char);
/// @return is taking the item allowed?
bool onTakeItem(const ItemStack& item, int count);

View file

@ -257,7 +257,7 @@ namespace MWGui
{
if (mEffects.size() <= 0)
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}");
MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu11}");
return;
}

View file

@ -8,13 +8,12 @@
namespace MWGui
{
MessageBoxManager::MessageBoxManager ()
MessageBoxManager::MessageBoxManager (float timePerChar)
{
// TODO: fMessageTimePerChar
mMessageBoxSpeed = 0.1;
mInterMessageBoxe = NULL;
mStaticMessageBox = NULL;
mLastButtonPressed = -1;
mMessageBoxSpeed = timePerChar;
}
MessageBoxManager::~MessageBoxManager ()
@ -63,7 +62,8 @@ namespace MWGui
{
MessageBox *box = new MessageBox(*this, message);
box->mCurrentTime = 0;
box->mMaxTime = message.length()*mMessageBoxSpeed;
std::string realMessage = MyGUI::LanguageManager::getInstance().replaceTags(message);
box->mMaxTime = realMessage.length()*mMessageBoxSpeed;
if(stat)
mStaticMessageBox = box;
@ -127,12 +127,6 @@ namespace MWGui
mMessageBoxSpeed = speed;
}
void MessageBoxManager::okayPressed ()
{
if(mInterMessageBoxe != NULL)
mInterMessageBoxe->okayPressed();
}
int MessageBoxManager::readPressedButton ()
{
int pressed = mLastButtonPressed;
@ -333,23 +327,25 @@ namespace MWGui
}
}
}
void InteractiveMessageBox::okayPressed()
{
// Set key focus to "Ok" button
std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}"));
std::vector<MyGUI::Button*>::const_iterator button;
for(button = mButtons.begin(); button != mButtons.end(); ++button)
{
if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok)
{
buttonActivated(*button);
MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f);
MyGUI::InputManager::getInstance().setKeyFocusWidget(*button);
(*button)->eventKeyButtonPressed += MyGUI::newDelegate(this, &InteractiveMessageBox::onKeyPressed);
break;
}
}
}
void InteractiveMessageBox::onKeyPressed(MyGUI::Widget *_sender, MyGUI::KeyCode _key, MyGUI::Char _char)
{
if (_key == MyGUI::KeyCode::Return || _key == MyGUI::KeyCode::NumpadEnter || _key == MyGUI::KeyCode::Space)
buttonActivated(_sender);
}
void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed)

View file

@ -22,7 +22,7 @@ namespace MWGui
class MessageBoxManager
{
public:
MessageBoxManager ();
MessageBoxManager (float timePerChar);
~MessageBoxManager ();
void onFrame (float frameDuration);
void createMessageBox (const std::string& message, bool stat = false);
@ -33,7 +33,6 @@ namespace MWGui
bool removeMessageBox (MessageBox *msgbox);
void setMessageBoxSpeed (int speed);
void okayPressed();
int readPressedButton ();
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
@ -74,7 +73,6 @@ namespace MWGui
{
public:
InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector<std::string>& buttons);
void okayPressed ();
void mousePressed (MyGUI::Widget* _widget);
int readPressedButton ();
@ -82,6 +80,7 @@ namespace MWGui
private:
void buttonActivated (MyGUI::Widget* _widget);
void onKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char);
MessageBoxManager& mMessageBoxManager;
MyGUI::EditBox* mMessageWidget;

View file

@ -130,6 +130,14 @@ namespace MWGui
return;
}
// You can not train a skill above its governing attribute
const ESM::Skill* skill = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find(skillId);
if (pcStats.getSkill(skillId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase())
{
MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage17}");
return;
}
// increase skill
MWWorld::LiveCellRef<ESM::NPC> *playerRef = player.get<ESM::NPC>();

View file

@ -207,7 +207,8 @@ namespace MWGui
mConsole = new Console(w,h, mConsoleOnlyScripts);
trackWindow(mConsole, "console");
mJournal = JournalWindow::create(JournalViewModel::create ());
mMessageBoxManager = new MessageBoxManager();
mMessageBoxManager = new MessageBoxManager(
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fMessageTimePerChar")->getFloat());
mInventoryWindow = new InventoryWindow(mDragAndDrop);
mTradeWindow = new TradeWindow();
trackWindow(mTradeWindow, "barter");
@ -676,17 +677,6 @@ namespace MWGui
mMessageBoxManager->removeStaticMessageBox();
}
void WindowManager::enterPressed ()
{
mMessageBoxManager->okayPressed();
}
void WindowManager::activateKeyPressed ()
{
mMessageBoxManager->okayPressed();
mCountDialog->cancel();
}
int WindowManager::readPressedButton ()
{
return mMessageBoxManager->readPressedButton();

View file

@ -222,8 +222,6 @@ namespace MWGui
virtual void messageBox (const std::string& message, const std::vector<std::string>& buttons = std::vector<std::string>(), bool showInDialogueModeOnly = false);
virtual void staticMessageBox(const std::string& message);
virtual void removeStaticMessageBox();
virtual void enterPressed ();
virtual void activateKeyPressed ();
virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox)
virtual void onFrame (float frameDuration);

View file

@ -195,14 +195,7 @@ namespace MWInput
case A_Activate:
resetIdleTime();
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
{
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
toggleContainer ();
else
MWBase::Environment::get().getWindowManager()->activateKeyPressed();
}
else
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
activate();
break;
case A_Journal:
@ -511,13 +504,6 @@ namespace MWInput
mInputBinder->keyPressed (arg);
if((arg.keysym.sym == SDLK_RETURN || arg.keysym.sym == SDLK_KP_ENTER)
&& MWBase::Environment::get().getWindowManager()->isGuiMode())
{
// Pressing enter when a messagebox is prompting for "ok" will activate the ok button
MWBase::Environment::get().getWindowManager()->enterPressed();
}
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
if (kc != OIS::KC_UNASSIGNED)
@ -730,21 +716,6 @@ namespace MWInput
// .. but don't touch any other mode, except container.
}
void InputManager::toggleContainer()
{
if (MyGUI::InputManager::getInstance ().isModalAny())
return;
if(MWBase::Environment::get().getWindowManager()->isGuiMode())
{
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Container)
MWBase::Environment::get().getWindowManager()->popGuiMode();
else
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container);
}
}
void InputManager::toggleConsole()
{
if (MyGUI::InputManager::getInstance ().isModalAny())

View file

@ -173,7 +173,6 @@ namespace MWInput
void toggleSpell();
void toggleWeapon();
void toggleInventory();
void toggleContainer();
void toggleConsole();
void screenshot();
void toggleJournal();

View file

@ -525,7 +525,7 @@ namespace MWMechanics
ref.getPtr().getCellRef().mPos = ipos;
// TODO: Add AI to follow player and fight for him
// TODO: VFX_SummonStart, VFX_SummonEnd
creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
}
@ -581,7 +581,8 @@ namespace MWMechanics
if(timeLeft == 0.0f)
{
// If drowning, apply 3 points of damage per second
ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - 3.0f*duration);
static const float fSuffocationDamage = world->getStore().get<ESM::GameSetting>().find("fSuffocationDamage")->getFloat();
ptr.getClass().setActorHealth(ptr, stats.getHealth().getCurrent() - fSuffocationDamage*duration);
// Play a drowning sound as necessary for the player
if(ptr == world->getPlayerPtr())
@ -593,7 +594,10 @@ namespace MWMechanics
}
}
else
stats.setTimeToStartDrowning(20);
{
static const float fHoldBreathTime = world->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->getFloat();
stats.setTimeToStartDrowning(fHoldBreathTime);
}
}
void Actors::updateEquippedLight (const MWWorld::Ptr& ptr, float duration)

View file

@ -7,6 +7,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "creaturestats.hpp"
#include "npcstats.hpp"
@ -118,6 +119,17 @@ namespace MWMechanics
}
if( mTimer > 1)
{
if (actor.getClass().isNpc())
{
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->getInt();
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 100; // [0, 99]
if (roll < chance)
{
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
}
}
MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true);
mTimer = 0;
}

View file

@ -598,7 +598,12 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
const ESM::MagicEffect *effect;
effect = store.get<ESM::MagicEffect>().find(effectentry.mEffectID);
const ESM::Static* castStatic = store.get<ESM::Static>().find (effect->mCasting);
const ESM::Static* castStatic;
if (!effect->mCasting.empty())
castStatic = store.get<ESM::Static>().find (effect->mCasting);
else
castStatic = store.get<ESM::Static>().find ("VFX_DefaultCast");
mAnimation->addEffect("meshes\\" + castStatic->mModel, effect->mIndex);
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");

View file

@ -19,7 +19,7 @@
namespace
{
/// @return is \a ptr allowed to take/use \a item or is it a crime?
bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item)
bool isAllowedToUse (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, MWWorld::Ptr& victim)
{
const std::string& owner = item.getCellRef().mOwner;
bool isOwned = !owner.empty();
@ -33,6 +33,9 @@ namespace
isFactionOwned = true;
}
if (!item.getCellRef().mOwner.empty())
victim = MWBase::Environment::get().getWorld()->searchPtr(item.getCellRef().mOwner, true);
return (!isOwned && !isFactionOwned);
}
}
@ -752,11 +755,9 @@ namespace MWMechanics
bool MechanicsManager::sleepInBed(const MWWorld::Ptr &ptr, const MWWorld::Ptr &bed)
{
if (isAllowedToUse(ptr, bed))
return false;
MWWorld::Ptr victim;
if (!bed.getCellRef().mOwner.empty())
victim = MWBase::Environment::get().getWorld()->getPtr(bed.getCellRef().mOwner, true);
if (isAllowedToUse(ptr, bed, victim))
return false;
if(commitCrime(ptr, victim, OT_SleepingInOwnedBed))
{
@ -767,20 +768,26 @@ namespace MWMechanics
return false;
}
void MechanicsManager::objectOpened(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item)
{
MWWorld::Ptr victim;
if (isAllowedToUse(ptr, item, victim))
return;
commitCrime(ptr, victim, OT_Trespassing);
}
void MechanicsManager::itemTaken(const MWWorld::Ptr &ptr, const MWWorld::Ptr &item, int count)
{
if (isAllowedToUse(ptr, item))
return;
MWWorld::Ptr victim;
if (!item.getCellRef().mOwner.empty())
victim = MWBase::Environment::get().getWorld()->getPtr(item.getCellRef().mOwner, true);
if (isAllowedToUse(ptr, item, victim))
return;
commitCrime(ptr, victim, OT_Theft, item.getClass().getValue(item) * count);
}
bool MechanicsManager::commitCrime(const MWWorld::Ptr &ptr, const MWWorld::Ptr &victim, OffenseType type, int arg)
{
// TODO: expell from faction
if (ptr.getRefData().getHandle() != "player")
return false;
bool reported=false;
for (Actors::PtrControllerMap::const_iterator it = mActors.begin(); it != mActors.end(); ++it)
@ -797,10 +804,7 @@ namespace MWMechanics
// Actor has witnessed a crime. Will he report it?
// (not sure, is > 0 correct?)
if (it->first.getClass().getCreatureStats(it->first).getAiSetting(CreatureStats::AI_Alarm).getModified() > 0
// This is a bit inconsistent, but AFAIK assaulted NPCs can not report if they are alone
&& (type != OT_Assault || it->first != victim)
)
if (it->first.getClass().getCreatureStats(it->first).getAiSetting(CreatureStats::AI_Alarm).getModified() > 0)
{
// TODO: stats.setAlarmed(true) on NPCs within earshot
// fAlarmRadius ?
@ -830,10 +834,32 @@ namespace MWMechanics
else if (type == OT_Theft)
arg *= store.find("fCrimeStealing")->getFloat();
// TODO: In some cases (type == Assault), if no NPCs are within earshot, the report will have no effect.
// however other crime types seem to be always produce a bounty.
MWBase::Environment::get().getWindowManager()->messageBox("#{sCrimeMessage}");
ptr.getClass().getNpcStats(ptr).setBounty(ptr.getClass().getNpcStats(ptr).getBounty()
+ arg);
if (!victim.isEmpty())
{
int fight = 0;
// Increase in fight rating for each type of crime
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
fight = store.find("iFightTrespass")->getFloat();
else if (type == OT_Pickpocket)
fight = store.find("iFightPickpocket")->getInt();
else if (type == OT_Assault)
fight = store.find("iFightAttack")->getInt();
else if (type == OT_Murder)
fight = store.find("iFightKilling")->getInt();
else if (type == OT_Theft)
fight = store.find("fFightStealing")->getFloat();
// Not sure if this should be permanent?
fight = victim.getClass().getCreatureStats(victim).getAiSetting(CreatureStats::AI_Fight).getBase() + fight;
victim.getClass().getCreatureStats(victim).setAiSetting(CreatureStats::AI_Fight, fight);
}
// If committing a crime against a faction member, expell from the faction
if (!victim.isEmpty() && victim.getClass().isNpc())
{
@ -851,6 +877,9 @@ namespace MWMechanics
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer)
{
if (observer.getClass().getCreatureStats(observer).isDead())
return false;
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);

View file

@ -113,6 +113,8 @@ namespace MWMechanics
OffenseType type, int arg=0);
/// Utility to check if taking this item is illegal and calling commitCrime if so
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count);
/// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so
virtual void objectOpened (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item);
/// Attempt sleeping in a bed. If this is illegal, call commitCrime.
/// @return was it illegal, and someone saw you doing it?
virtual bool sleepInBed (const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed);

View file

@ -6,6 +6,7 @@
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "npcstats.hpp"
#include "creaturestats.hpp"
@ -45,6 +46,7 @@ namespace MWMechanics
resultMessage = "#{sLockImpossible}";
else
{
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, lock);
int roll = static_cast<float> (std::rand()) / RAND_MAX * 100;
if (roll <= x)
{
@ -86,6 +88,7 @@ namespace MWMechanics
resultMessage = "#{sTrapImpossible}";
else
{
MWBase::Environment::get().getMechanicsManager()->objectOpened(mActor, trap);
int roll = static_cast<float> (std::rand()) / RAND_MAX * 100;
if (roll <= x)
{

View file

@ -4,7 +4,7 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/actionteleport.hpp"
@ -57,6 +57,7 @@ namespace MWMechanics
ESM::EffectList reflectedEffects;
std::vector<ActiveSpells::Effect> appliedLastingEffects;
bool firstAppliedEffect = true;
bool anyHarmfulEffect = false;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt (effects.mList.begin());
effectIt!=effects.mList.end(); ++effectIt)
@ -77,6 +78,8 @@ namespace MWMechanics
float magnitudeMult = 1;
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful && target.getClass().isActor())
{
anyHarmfulEffect = true;
// If player is attempting to cast a harmful spell, show the target's HP bar
if (caster.getRefData().getHandle() == "player" && target != caster)
MWBase::Environment::get().getWindowManager()->setEnemy(target);
@ -167,7 +170,7 @@ namespace MWMechanics
}
}
else
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
// HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent.
// This was probably just done to have the effect visible in the magic menu for a while
@ -177,7 +180,7 @@ namespace MWMechanics
|| effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute
|| effectIt->mEffectID == ESM::MagicEffect::RestoreSkill
)
applyInstantEffect(target, EffectKey(*effectIt), magnitude);
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
{
@ -197,15 +200,17 @@ namespace MWMechanics
}
// Add VFX
const ESM::Static* castStatic;
if (!magicEffect->mHit.empty())
{
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
// Note: in case of non actor, a free effect should be fine as well
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
if (anim)
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
}
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find (magicEffect->mHit);
else
castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_DefaultHit");
bool loop = magicEffect->mData.mFlags & ESM::MagicEffect::ContinuousVfx;
// Note: in case of non actor, a free effect should be fine as well
MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(target);
if (anim)
anim->addEffect("meshes\\" + castStatic->mModel, magicEffect->mIndex, loop, "");
}
// TODO: For Area effects, launch a growing particle effect that applies the effect to more actors as it hits them. Best managed in World.
@ -218,9 +223,13 @@ namespace MWMechanics
if (appliedLastingEffects.size())
target.getClass().getCreatureStats(target).getActiveSpells().addSpell(mId, mStack, appliedLastingEffects,
mSourceName, caster.getRefData().getHandle());
if (anyHarmfulEffect && target.getClass().isActor()
&& target.getClass().getCreatureStats(target).getAiSetting(MWMechanics::CreatureStats::AI_Fight).getModified() <= 30)
MWBase::Environment::get().getMechanicsManager()->commitCrime(caster, target, MWBase::MechanicsManager::OT_Assault);
}
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, MWMechanics::EffectKey effect, float magnitude)
void CastSpell::applyInstantEffect(const MWWorld::Ptr &target, const MWWorld::Ptr &caster, MWMechanics::EffectKey effect, float magnitude)
{
short effectId = effect.mId;
if (!target.getClass().isActor())
@ -232,11 +241,13 @@ namespace MWMechanics
}
else if (effectId == ESM::MagicEffect::Open)
{
// TODO: This is a crime
if (target.getCellRef().mLockLevel <= magnitude)
{
if (target.getCellRef().mLockLevel > 0)
{
MWBase::Environment::get().getSoundManager()->playSound3D(target, "Open Lock", 1.f, 1.f);
MWBase::Environment::get().getMechanicsManager()->objectOpened(caster, target);
}
target.getCellRef().mLockLevel = 0;
}
else

View file

@ -19,12 +19,12 @@ namespace MWMechanics
inline int spellSchoolToSkill(int school)
{
std::map<int, int> schoolSkillMap; // maps spell school to skill id
schoolSkillMap[0] = 11; // alteration
schoolSkillMap[1] = 13; // conjuration
schoolSkillMap[3] = 12; // illusion
schoolSkillMap[2] = 10; // destruction
schoolSkillMap[4] = 14; // mysticism
schoolSkillMap[5] = 15; // restoration
schoolSkillMap[0] = ESM::Skill::Alteration;
schoolSkillMap[1] = ESM::Skill::Conjuration;
schoolSkillMap[3] = ESM::Skill::Illusion;
schoolSkillMap[2] = ESM::Skill::Destruction;
schoolSkillMap[4] = ESM::Skill::Mysticism;
schoolSkillMap[5] = ESM::Skill::Restoration;
assert(schoolSkillMap.find(school) != schoolSkillMap.end());
return schoolSkillMap[school];
}
@ -203,7 +203,7 @@ namespace MWMechanics
void inflict (const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
const ESM::EffectList& effects, ESM::RangeType range, bool reflected=false);
void applyInstantEffect (const MWWorld::Ptr& target, MWMechanics::EffectKey effect, float magnitude);
void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, MWMechanics::EffectKey effect, float magnitude);
};
}

View file

@ -226,11 +226,10 @@ namespace MWRender
mCamera->setPosition(0.f, 0.f, offset);
}
void Camera::setSneakOffset()
void Camera::setSneakOffset(float offset)
{
// TODO: iFirstPersonSneakDelta
if(mAnimation)
mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -9.8f));
mAnimation->addFirstPersonOffset(Ogre::Vector3(0.f, 0.f, -offset));
}
float Camera::getYaw()

View file

@ -87,7 +87,7 @@ namespace MWRender
/// As animation is tied to the camera, this needs
/// to be set each frame after the animation is
/// applied.
void setSneakOffset();
void setSneakOffset(float offset);
bool isFirstPerson() const
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }

View file

@ -4,6 +4,7 @@
#include <OgreSceneManager.h>
#include <OgreRoot.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreCamera.h>
#include <libs/openengine/ogre/selectionbuffer.hpp>

View file

@ -8,6 +8,7 @@
#include <OgreSubEntity.h>
#include <OgreMeshManager.h>
#include <OgreMaterialManager.h>
#include <OgreCamera.h>
#include "renderconst.hpp"

View file

@ -351,8 +351,10 @@ void RenderingManager::update (float duration, bool paused)
bool isInAir = !world->isOnGround(player);
bool isSwimming = world->isSwimming(player);
static const int i1stPersonSneakDelta = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("i1stPersonSneakDelta")->getInt();
if(isSneaking && !(isSwimming || isInAir))
mCamera->setSneakOffset();
mCamera->setSneakOffset(i1stPersonSneakDelta);
mOcclusionQuery->update(duration);

View file

@ -8,6 +8,7 @@
#include <OgreShadowCameraSetupLiSPSM.h>
#include <OgreShadowCameraSetupPSSM.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreCamera.h>
#include <extern/shiny/Main/Factory.hpp>

View file

@ -5,6 +5,7 @@
#include <OgreMeshManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreRoot.h>
#include <OgreCamera.h>
#include "sky.hpp"
#include "renderingmanager.hpp"

View file

@ -766,12 +766,7 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
world->teleportToClosestMarker(player, "prisonmarker");
player.getClass().getNpcStats(player).setBounty(0);
// TODO: pass time, change skills, show messagebox
// TODO: move stolen items to closest evidence chest
// iDaysinPrisonMod
world->goToJail();
}
};
@ -782,8 +777,7 @@ namespace MWScript
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
player.getClass().getNpcStats(player).setBounty(0);
// TODO: move stolen items to closest evidence chest
MWBase::Environment::get().getWorld()->confiscateStolenItems(player);
}
};

View file

@ -271,3 +271,15 @@ void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorl
}
}
void MWWorld::Cells::getInteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
{
for (std::map<std::string, Ptr::CellStore>::iterator iter = mInteriors.begin();
iter!=mInteriors.end(); ++iter)
{
Ptr ptr = getPtrAndCache (name, iter->second);
if (!ptr.isEmpty())
out.push_back(ptr);
}
}

View file

@ -56,6 +56,12 @@ namespace MWWorld
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
/// @note name must be lower case
void getExteriorPtrs (const std::string& name, std::vector<MWWorld::Ptr>& out);
/// Get all Ptrs referencing \a name in interior cells
/// @note Due to the current implementation of getPtr this only supports one Ptr per cell.
/// @note name must be lower case
void getInteriorPtrs (const std::string& name, std::vector<MWWorld::Ptr>& out);
};
}

View file

@ -165,7 +165,6 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot)
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{
const MWMechanics::NpcStats& stats = MWWorld::Class::get(actor).getNpcStats(actor);
MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor);
TSlots slots_;
initSlots (slots_);
@ -266,10 +265,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
case 0:
continue;
case 2:
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft, actor);
slots_[MWWorld::InventoryStore::Slot_CarriedLeft] = end();
break;
case 3:
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, actor);
// Prefer keeping twohanded weapon
break;
}
@ -392,7 +391,7 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
// Apply instant effects
MWMechanics::CastSpell cast(actor, actor);
if (magnitude)
cast.applyInstantEffect(actor, effectIt->mEffectID, magnitude);
cast.applyInstantEffect(actor, actor, effectIt->mEffectID, magnitude);
}
if (magnitude)

View file

@ -216,7 +216,7 @@ namespace MWWorld
mSky (true), mCells (mStore, mEsm),
mActivationDistanceOverride (mActivationDistanceOverride),
mFallback(fallbackMap), mPlayIntro(0), mTeleportEnabled(true), mLevitationEnabled(false),
mFacedDistance(FLT_MAX), mGodMode(false)
mFacedDistance(FLT_MAX), mGodMode(false), mGoToJail(false)
{
mPhysics = new PhysicsSystem(renderer);
mPhysEngine = mPhysics->getEngine();
@ -259,6 +259,9 @@ namespace MWWorld
void World::startNewGame()
{
mGoToJail = false;
mLevitationEnabled = true;
mTeleportEnabled = true;
mWorldScene->changeToVoid();
mStore.clearDynamic();
@ -485,8 +488,9 @@ namespace MWWorld
mLocalScripts.remove (ref);
}
Ptr World::getPtr (const std::string& name, bool activeOnly)
Ptr World::searchPtr (const std::string& name, bool activeOnly)
{
Ptr ret;
// the player is always in an active cell.
if (name=="player")
{
@ -514,12 +518,16 @@ namespace MWWorld
if (!activeOnly)
{
Ptr ptr = mCells.getPtr (lowerCaseName);
if (!ptr.isEmpty())
return ptr;
ret = mCells.getPtr (lowerCaseName);
}
return ret;
}
Ptr World::getPtr (const std::string& name, bool activeOnly)
{
Ptr ret = searchPtr(name, activeOnly);
if (!ret.isEmpty())
return ret;
throw std::runtime_error ("unknown ID: " + name);
}
@ -1267,6 +1275,9 @@ namespace MWWorld
mRendering->playVideo(mFallback.getFallbackString("Movies_New_Game"), true);
}
if (mGoToJail && !paused)
goToJail();
updateWeather(duration);
mWorldScene->update (duration, paused);
@ -2174,14 +2185,13 @@ namespace MWWorld
Ogre::Vector3 rot(ptr.getRefData().getPosition().rot);
// TODO: Why -rot.z, but not -rot.x?
// TODO: Why -rot.z, but not -rot.x? (note: same issue in MovementSolver::move)
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
orient = orient * Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X);
// This is just a guess, probably wrong
static float fProjectileMinSpeed = getStore().get<ESM::GameSetting>().find("fProjectileMinSpeed")->getFloat();
static float fProjectileMaxSpeed = getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->getFloat();
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * it->second.mSpeed;
static float fTargetSpellMaxSpeed = getStore().get<ESM::GameSetting>().find("fTargetSpellMaxSpeed")->getFloat();
float speed = fTargetSpellMaxSpeed * it->second.mSpeed;
Ogre::Vector3 direction = orient.yAxis();
direction.normalise();
@ -2447,4 +2457,115 @@ namespace MWWorld
mGlobalVariables->setInt("crimegoldturnin", turnIn);
mGlobalVariables->setInt("pchasturnin", (turnIn <= playerGold) ? 1 : 0);
}
void World::confiscateStolenItems(const Ptr &ptr)
{
Ogre::Vector3 playerPos;
if (!findInteriorPositionInWorldSpace(ptr.getCell(), playerPos))
playerPos = mPlayer->getLastKnownExteriorPosition();
MWWorld::Ptr closestChest;
float closestDistance = FLT_MAX;
std::vector<MWWorld::Ptr> chests;
mCells.getInteriorPtrs("stolen_goods", chests);
Ogre::Vector3 chestPos;
for (std::vector<MWWorld::Ptr>::iterator it = chests.begin(); it != chests.end(); ++it)
{
if (!findInteriorPositionInWorldSpace(it->getCell(), chestPos))
continue;
float distance = playerPos.squaredDistance(chestPos);
if (distance < closestDistance)
{
closestDistance = distance;
closestChest = *it;
}
}
if (!closestChest.isEmpty())
{
ContainerStore& store = ptr.getClass().getContainerStore(ptr);
for (ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (!it->getCellRef().mOwner.empty() && it->getCellRef().mOwner != "player")
{
closestChest.getClass().getContainerStore(closestChest).add(*it, it->getRefData().getCount(), closestChest);
store.remove(*it, it->getRefData().getCount(), ptr);
}
}
}
}
void World::goToJail()
{
if (!mGoToJail)
{
// Save for next update, since the player should be able to read the dialog text first
mGoToJail = true;
return;
}
else
{
mGoToJail = false;
MWWorld::Ptr player = getPlayerPtr();
teleportToClosestMarker(player, "prisonmarker");
int bounty = player.getClass().getNpcStats(player).getBounty();
player.getClass().getNpcStats(player).setBounty(0);
confiscateStolenItems(player);
int iDaysinPrisonMod = getStore().get<ESM::GameSetting>().find("iDaysinPrisonMod")->getInt();
int days = std::max(1, bounty / iDaysinPrisonMod);
advanceTime(days * 24);
std::set<int> skills;
for (int day=0; day<days; ++day)
{
int skill = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * ESM::Skill::Length;
skills.insert(skill);
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill);
if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak)
value.setBase(std::min(100, value.getBase()+1));
else
value.setBase(value.getBase()-1);
}
const Store<ESM::GameSetting>& gmst = getStore().get<ESM::GameSetting>();
std::string message;
if (days == 1)
message = gmst.find("sNotifyMessage42")->getString();
else
message = gmst.find("sNotifyMessage43")->getString();
std::stringstream dayStr;
dayStr << days;
if (message.find("%d") != std::string::npos)
message.replace(message.find("%d"), 2, dayStr.str());
for (std::set<int>::iterator it = skills.begin(); it != skills.end(); ++it)
{
std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString();
std::stringstream skillValue;
skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase();
std::string skillMsg = gmst.find("sNotifyMessage44")->getString();
if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security)
skillMsg = gmst.find("sNotifyMessage39")->getString();
if (skillMsg.find("%s") != std::string::npos)
skillMsg.replace(skillMsg.find("%s"), 2, skillName);
if (skillMsg.find("%d") != std::string::npos)
skillMsg.replace(skillMsg.find("%d"), 2, skillValue.str());
message += "\n" + skillMsg;
}
std::vector<std::string> buttons;
buttons.push_back("#{sOk}");
MWBase::Environment::get().getWindowManager()->messageBox(message, buttons);
}
}
}

View file

@ -151,6 +151,7 @@ namespace MWWorld
bool mTeleportEnabled;
bool mLevitationEnabled;
bool mGoToJail;
/// Called when \a object is moved to an inactive cell
void objectLeftActiveCell (MWWorld::Ptr object, MWWorld::Ptr movedPtr);
@ -232,6 +233,10 @@ namespace MWWorld
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.
virtual Ptr searchPtr (const std::string& name, bool activeOnly);
///< Return a pointer to a liveCellRef with the given name.
/// \param activeOnly do non search inactive cells.
virtual Ptr getPtrViaHandle (const std::string& handle);
///< Return a pointer to a liveCellRef with the given Ogre handle.
@ -536,6 +541,11 @@ namespace MWWorld
/// Update the value of some globals according to the world state, which may be used by dialogue entries.
/// This should be called when initiating a dialogue.
virtual void updateDialogueGlobals();
/// Moves all stolen items from \a ptr to the closest evidence chest.
virtual void confiscateStolenItems(const MWWorld::Ptr& ptr);
virtual void goToJail ();
};
}

View file

@ -277,6 +277,8 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata,
if (itr != sMaterialMap.end())
{
// a suitable material exists already - use it
sh::MaterialInstance* instance = sh::Factory::getInstance().getMaterialInstance(itr->second);
needTangents = !sh::retrieveValue<sh::StringValue>(instance->getProperty("normalMap"), instance).get().empty();
return itr->second;
}
// not found, create a new one

View file

@ -26,7 +26,6 @@
#include <algorithm>
#include <OgreTechnique.h>
#include <OgreRoot.h>
#include <OgreEntity.h>
#include <OgreSubEntity.h>
#include <OgreTagPoint.h>
@ -36,6 +35,9 @@
#include <OgreMeshManager.h>
#include <OgreSkeletonManager.h>
#include <OgreControllerManager.h>
#include <OgreMaterialManager.h>
#include <OgreCamera.h>
#include <OgreSceneManager.h>
#include <extern/shiny/Main/Factory.hpp>

View file

@ -281,6 +281,7 @@ namespace Terrain
// normal map (optional)
bool useNormalMap = mNormalMapping && !mLayerList[layerOffset+i].mNormalMap.empty() && !renderCompositeMap;
bool useParallax = useNormalMap && mParallaxMapping && layer.mParallax;
bool useSpecular = layer.mSpecular;
if (useNormalMap)
{
anyNormalMaps = true;
@ -292,8 +293,11 @@ namespace Terrain
sh::makeProperty (new sh::BooleanValue(useNormalMap)));
p->mShaderProperties.setProperty ("use_parallax_" + Ogre::StringConverter::toString(i),
sh::makeProperty (new sh::BooleanValue(useParallax)));
p->mShaderProperties.setProperty ("use_specular_" + Ogre::StringConverter::toString(i),
sh::makeProperty (new sh::BooleanValue(useSpecular)));
boost::hash_combine(normalMaps, useNormalMap);
boost::hash_combine(normalMaps, useNormalMap && layer.mParallax);
boost::hash_combine(normalMaps, useSpecular);
if (i+layerOffset > 0)
{

View file

@ -475,6 +475,7 @@ namespace Terrain
LayerInfo info;
info.mParallax = false;
info.mSpecular = false;
info.mDiffuseMap = "textures\\" + texture;
std::string texture_ = texture;
boost::replace_last(texture_, ".", "_nh.");
@ -491,6 +492,14 @@ namespace Terrain
info.mNormalMap = "textures\\" + texture_;
}
texture_ = texture;
boost::replace_last(texture_, ".", "_diffusespec.");
if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("textures\\" + texture_))
{
info.mDiffuseMap = "textures\\" + texture_;
info.mSpecular = true;
}
mLayerInfoMap[texture] = info;
return info;

View file

@ -16,6 +16,7 @@ namespace Terrain
std::string mDiffuseMap;
std::string mNormalMap;
bool mParallax; // Height info in normal map alpha channel?
bool mSpecular; // Specular info in diffuse map alpha channel?
};
/// We keep storage of terrain data abstract here since we need different implementations for game and editor

View file

@ -337,6 +337,7 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
float2 layerUV = float2(UV.x, 1.f-UV.y) * 16; // Reverse Y, required to get proper tangents
float2 thisLayerUV;
float4 normalTex;
float4 diffuseTex;
float3 eyeDir = normalize(cameraPos.xyz - worldPos);
#if PARALLAX
@ -358,19 +359,18 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
thisLayerUV += TSeyeDir.xy * ( normalTex.a * PARALLAX_SCALE + PARALLAX_BIAS );
#endif
#if IS_FIRST_PASS
#if @shIterator == 0
// first layer of first pass is the base layer and doesn't need a blend map
albedo = shSample(diffuseMap0, layerUV);
#else
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, thisLayerUV), blendValues@shPropertyString(blendmap_component_@shIterator));
#endif
diffuseTex = shSample(diffuseMap@shIterator, layerUV);
#if !@shPropertyBool(use_specular_@shIterator)
diffuseTex.a = 0;
#endif
#if @shIterator == 0
albedo = diffuseTex;
#else
#if @shIterator == 0
albedo = shSample(diffuseMap@shIterator, layerUV);
#else
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, thisLayerUV), blendValues@shPropertyString(blendmap_component_@shIterator));
#endif
albedo = shLerp(albedo, diffuseTex, blendValues@shPropertyString(blendmap_component_@shIterator));
#endif
#if !IS_FIRST_PASS
previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator);
#endif
@ -448,7 +448,7 @@ float2 blendUV = (UV - 0.5) * (16.0 / (16.0+1.0)) + 0.5;
float3 halfVec = normalize (light0Dir + eyeDir);
float3 specular = pow(max(dot(normal, halfVec), 0), 32) * lightSpec0;
shOutputColour(0).xyz += specular * (1.f-albedo.a) * shadow;
shOutputColour(0).xyz += specular * (albedo.a) * shadow;
#endif
#if FOG

View file

@ -11,7 +11,7 @@
</Widget>
<Widget type="TextBox" skin="NormalText" position="0 0 450 18" align="Right Top">
<Property key="TextAlign" value="Center"/>
<Property key="Caption" value="#{sSpells}"/>
<Property key="Caption" value="#{sServiceSpellsTitle}"/>
</Widget>

View file

@ -11,7 +11,7 @@
</Widget>
<Widget type="TextBox" skin="SandText" position="0 0 24 24" name="Travel" align="Right Top">
<Property key="TextAlign" value="Right"/>
<Property key="Caption" value="#D8C09A#{sTravel}"/>
<Property key="Caption" value="#D8C09A#{sServiceTravelTitle}"/>
</Widget>
@ -32,4 +32,4 @@
</Widget>
</MyGUI>
</MyGUI>

View file

@ -8,6 +8,7 @@
#include <OgreTextureManager.h>
#include <OgreTexture.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreCamera.h>
#include <extern/sdl4ogre/sdlwindowhelper.hpp>