1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-04-01 10:36:42 +00:00

Merge remote-tracking branch 'scrawl/master'

This commit is contained in:
Marc Zinnschlag 2014-09-18 09:22:33 +02:00
commit 144f6ca79a
15 changed files with 96 additions and 26 deletions

View file

@ -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();
} }

View file

@ -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());

View file

@ -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

View file

@ -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());

View file

@ -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);
} }
} }

View file

@ -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();
} }

View file

@ -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;

View file

@ -99,6 +99,8 @@ 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.getClass().getName(mFocusObject);
if (info.caption.empty())
info.caption=mFocusObject.getCellRef().getRefId(); info.caption=mFocusObject.getCellRef().getRefId();
info.icon=""; info.icon="";
tooltipSize = createToolTip(info); tooltipSize = createToolTip(info);

View file

@ -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)
} }

View file

@ -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)
{ {

View file

@ -745,7 +745,39 @@ 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";
std::string stopKey = "stop";
if (weapType == WeapType_Spell)
{
const std::string spellid = stats.getSpells().getSelectedSpell();
if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
{
castSpell(spellid);
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] int roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 3; // [0, 2]
if (roll == 0) if (roll == 0)
mCurrentWeapon = "attack1"; mCurrentWeapon = "attack1";
@ -753,21 +785,15 @@ bool CharacterController::updateCreatureState()
mCurrentWeapon = "attack2"; mCurrentWeapon = "attack2";
else else
mCurrentWeapon = "attack3"; mCurrentWeapon = "attack3";
}
if (!mCurrentWeapon.empty())
{
mAnimation->play(mCurrentWeapon, Priority_Weapon, mAnimation->play(mCurrentWeapon, Priority_Weapon,
MWRender::Animation::Group_All, true, MWRender::Animation::Group_All, true,
1, "start", "stop", 1, startKey, stopKey,
0.0f, 0); 0.0f, 0);
mUpperBodyState = UpperCharState_StartToMinAttack; mUpperBodyState = UpperCharState_StartToMinAttack;
if (weapType == WeapType_Spell)
{
const std::string spellid = stats.getSpells().getSelectedSpell();
if (!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
{
castSpell(spellid);
MWBase::Environment::get().getWorld()->castSpell(mPtr);
}
} }
} }

View file

@ -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;

View file

@ -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);

View file

@ -1120,8 +1120,11 @@ 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
if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)

View file

@ -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")
{
// 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); 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);