mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-30 09:06:43 +00:00
Merge remote-tracking branch 'scrawl/master'
This commit is contained in:
commit
144f6ca79a
15 changed files with 96 additions and 26 deletions
|
@ -109,12 +109,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
||||||
{
|
{
|
||||||
if (!paused)
|
if (!paused)
|
||||||
{
|
{
|
||||||
// global scripts
|
|
||||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
|
||||||
|
|
||||||
// local scripts
|
// local scripts
|
||||||
executeLocalScripts();
|
executeLocalScripts();
|
||||||
|
|
||||||
|
// global scripts
|
||||||
|
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,6 +129,8 @@ namespace MWClass
|
||||||
|
|
||||||
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
||||||
|
|
||||||
|
data->mCreatureStats.setNeedRecalcDynamicStats(false);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData(data.release());
|
ptr.getRefData().setCustomData(data.release());
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ namespace MWClass
|
||||||
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
||||||
customData.mSpawn = false;
|
customData.mSpawn = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
customData.mSpawn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureLevList::ensureCustomData(const MWWorld::Ptr &ptr) const
|
void CreatureLevList::ensureCustomData(const MWWorld::Ptr &ptr) const
|
||||||
|
|
|
@ -388,6 +388,8 @@ namespace MWClass
|
||||||
|
|
||||||
data->mNpcStats.setGoldPool(gold);
|
data->mNpcStats.setGoldPool(gold);
|
||||||
|
|
||||||
|
data->mNpcStats.setNeedRecalcDynamicStats(false);
|
||||||
|
|
||||||
// store
|
// store
|
||||||
ptr.getRefData().setCustomData (data.release());
|
ptr.getRefData().setCustomData (data.release());
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,8 @@ void CompanionWindow::onMessageBoxButtonClicked(int button)
|
||||||
"minimumprofit", mPtr.getClass().getNpcStats(mPtr).getProfit());
|
"minimumprofit", mPtr.getClass().getNpcStats(mPtr).getProfit());
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion);
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion);
|
||||||
MWBase::Environment::get().getDialogueManager()->startDialogue (mPtr);
|
// Important for Calvus' contract script to work properly
|
||||||
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ namespace MWGui
|
||||||
const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f);
|
const MyGUI::Colour linkHot (223/255.f, 201/255.f, 159/255.f);
|
||||||
const MyGUI::Colour linkNormal (150/255.f, 50/255.f, 30/255.f);
|
const MyGUI::Colour linkNormal (150/255.f, 50/255.f, 30/255.f);
|
||||||
const MyGUI::Colour linkActive (243/255.f, 237/255.f, 221/255.f);
|
const MyGUI::Colour linkActive (243/255.f, 237/255.f, 221/255.f);
|
||||||
for (std::map<std::string, int>::reverse_iterator it = mChoices.rbegin(); it != mChoices.rend(); ++it)
|
for (std::vector<std::pair<std::string, int> >::iterator it = mChoices.begin(); it != mChoices.end(); ++it)
|
||||||
{
|
{
|
||||||
Choice* link = new Choice(it->second);
|
Choice* link = new Choice(it->second);
|
||||||
mLinks.push_back(link);
|
mLinks.push_back(link);
|
||||||
|
@ -600,7 +600,7 @@ namespace MWGui
|
||||||
|
|
||||||
void DialogueWindow::addChoice(const std::string& choice, int id)
|
void DialogueWindow::addChoice(const std::string& choice, int id)
|
||||||
{
|
{
|
||||||
mChoices[choice] = id;
|
mChoices.push_back(std::make_pair(choice, id));
|
||||||
updateHistory();
|
updateHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ namespace MWGui
|
||||||
bool mGoodbye;
|
bool mGoodbye;
|
||||||
|
|
||||||
std::vector<DialogueText*> mHistoryContents;
|
std::vector<DialogueText*> mHistoryContents;
|
||||||
std::map<std::string, int> mChoices;
|
std::vector<std::pair<std::string, int> > mChoices;
|
||||||
|
|
||||||
std::vector<Link*> mLinks;
|
std::vector<Link*> mLinks;
|
||||||
std::map<std::string, Link*> mTopicLinks;
|
std::map<std::string, Link*> mTopicLinks;
|
||||||
|
|
|
@ -99,7 +99,9 @@ namespace MWGui
|
||||||
setCoord(0, 0, 300, 300);
|
setCoord(0, 0, 300, 300);
|
||||||
mDynamicToolTipBox->setVisible(true);
|
mDynamicToolTipBox->setVisible(true);
|
||||||
ToolTipInfo info;
|
ToolTipInfo info;
|
||||||
info.caption=mFocusObject.getCellRef().getRefId();
|
info.caption = mFocusObject.getClass().getName(mFocusObject);
|
||||||
|
if (info.caption.empty())
|
||||||
|
info.caption=mFocusObject.getCellRef().getRefId();
|
||||||
info.icon="";
|
info.icon="";
|
||||||
tooltipSize = createToolTip(info);
|
tooltipSize = createToolTip(info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else //is creature
|
else //is creature
|
||||||
{
|
{
|
||||||
weaptype = WeapType_HandToHand; //doesn't matter, should only reflect if it is melee or distant weapon
|
weaptype = actorClass.getCreatureStats(actor).getDrawState() == DrawState_Spell ? WeapType_Spell : WeapType_HandToHand;
|
||||||
weapRange = 150.0f; //TODO: use true attack range (the same problem in Creature::hit)
|
weapRange = 150.0f; //TODO: use true attack range (the same problem in Creature::hit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aitravel.hpp"
|
#include "aitravel.hpp"
|
||||||
|
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -70,6 +72,12 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Maximum travel distance for vanilla compatibility.
|
||||||
|
// Was likely meant to prevent NPCs walking into non-loaded exterior cells, but for some reason is used in interior cells as well.
|
||||||
|
// We can make this configurable at some point, but the default *must* be the below value. Anything else will break shoddily-written content (*cough* MW *cough*) in bizarre ways.
|
||||||
|
if (Ogre::Vector3(mX, mY, mZ).squaredDistance(Ogre::Vector3(pos.pos)) > 7168*7168)
|
||||||
|
return false;
|
||||||
|
|
||||||
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY;
|
||||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||||
{
|
{
|
||||||
|
|
|
@ -745,29 +745,55 @@ bool CharacterController::updateCreatureState()
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||||
|
|
||||||
// These are unique animations and not linked to movement type. Just pick one randomly.
|
std::string startKey = "start";
|
||||||
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 3; // [0, 2]
|
std::string stopKey = "stop";
|
||||||
if (roll == 0)
|
|
||||||
mCurrentWeapon = "attack1";
|
|
||||||
else if (roll == 1)
|
|
||||||
mCurrentWeapon = "attack2";
|
|
||||||
else
|
|
||||||
mCurrentWeapon = "attack3";
|
|
||||||
|
|
||||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
|
||||||
MWRender::Animation::Group_All, true,
|
|
||||||
1, "start", "stop",
|
|
||||||
0.0f, 0);
|
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
|
||||||
|
|
||||||
if (weapType == WeapType_Spell)
|
if (weapType == WeapType_Spell)
|
||||||
{
|
{
|
||||||
const std::string spellid = stats.getSpells().getSelectedSpell();
|
const std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
||||||
{
|
{
|
||||||
castSpell(spellid);
|
castSpell(spellid);
|
||||||
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
|
||||||
|
if (!mAnimation->hasAnimation("spellcast"))
|
||||||
|
MWBase::Environment::get().getWorld()->castSpell(mPtr); // No "release" text key to use, so cast immediately
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellid);
|
||||||
|
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
|
||||||
|
|
||||||
|
switch(effectentry.mRange)
|
||||||
|
{
|
||||||
|
case 0: mAttackType = "self"; break;
|
||||||
|
case 1: mAttackType = "touch"; break;
|
||||||
|
case 2: mAttackType = "target"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
startKey = mAttackType + " " + startKey;
|
||||||
|
stopKey = mAttackType + " " + stopKey;
|
||||||
|
mCurrentWeapon = "spellcast";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
mCurrentWeapon = "";
|
||||||
|
}
|
||||||
|
if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
|
||||||
|
{
|
||||||
|
int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 3; // [0, 2]
|
||||||
|
if (roll == 0)
|
||||||
|
mCurrentWeapon = "attack1";
|
||||||
|
else if (roll == 1)
|
||||||
|
mCurrentWeapon = "attack2";
|
||||||
|
else
|
||||||
|
mCurrentWeapon = "attack3";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mCurrentWeapon.empty())
|
||||||
|
{
|
||||||
|
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
||||||
|
MWRender::Animation::Group_All, true,
|
||||||
|
1, startKey, stopKey,
|
||||||
|
0.0f, 0);
|
||||||
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -378,6 +378,11 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreatureStats::setNeedRecalcDynamicStats(bool val)
|
||||||
|
{
|
||||||
|
mRecalcDynamicStats = val;
|
||||||
|
}
|
||||||
|
|
||||||
void CreatureStats::setKnockedDown(bool value)
|
void CreatureStats::setKnockedDown(bool value)
|
||||||
{
|
{
|
||||||
mKnockdown = value;
|
mKnockdown = value;
|
||||||
|
|
|
@ -92,6 +92,7 @@ namespace MWMechanics
|
||||||
void setAttackStrength(float value);
|
void setAttackStrength(float value);
|
||||||
|
|
||||||
bool needToRecalcDynamicStats();
|
bool needToRecalcDynamicStats();
|
||||||
|
void setNeedRecalcDynamicStats(bool val);
|
||||||
|
|
||||||
void addToFallHeight(float height);
|
void addToFallHeight(float height);
|
||||||
|
|
||||||
|
|
|
@ -1120,7 +1120,10 @@ namespace MWMechanics
|
||||||
ptr.getClass().getCreatureStats(ptr).friendlyHit();
|
ptr.getClass().getCreatureStats(ptr).friendlyHit();
|
||||||
|
|
||||||
if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4)
|
if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attacking peaceful NPCs is a crime
|
// Attacking peaceful NPCs is a crime
|
||||||
|
|
|
@ -805,7 +805,25 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
|
||||||
attachArrow();
|
attachArrow();
|
||||||
|
|
||||||
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
||||||
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
{
|
||||||
|
// Make sure this key is actually for the RangeType we are casting. The flame atronach has
|
||||||
|
// the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type.
|
||||||
|
// FIXME: This logic should really be in the CharacterController
|
||||||
|
const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell();
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellid);
|
||||||
|
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
|
||||||
|
int range = 0;
|
||||||
|
if (evt.compare(off, len, "self release") == 0)
|
||||||
|
range = 0;
|
||||||
|
else if (evt.compare(off, len, "touch release") == 0)
|
||||||
|
range = 1;
|
||||||
|
else if (evt.compare(off, len, "target release") == 0)
|
||||||
|
range = 2;
|
||||||
|
if (effectentry.mRange == range)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0)
|
else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0)
|
||||||
mPtr.getClass().block(mPtr);
|
mPtr.getClass().block(mPtr);
|
||||||
|
|
Loading…
Reference in a new issue