mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +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)
|
||||
{
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
||||
// local scripts
|
||||
executeLocalScripts();
|
||||
|
||||
// global scripts
|
||||
MWBase::Environment::get().getScriptManager()->getGlobalScripts().run();
|
||||
|
||||
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,8 @@ namespace MWClass
|
|||
|
||||
data->mCreatureStats.setGoldPool(ref->mBase->mData.mGold);
|
||||
|
||||
data->mCreatureStats.setNeedRecalcDynamicStats(false);
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData(data.release());
|
||||
|
||||
|
|
|
@ -83,6 +83,8 @@ namespace MWClass
|
|||
customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId();
|
||||
customData.mSpawn = false;
|
||||
}
|
||||
else
|
||||
customData.mSpawn = false;
|
||||
}
|
||||
|
||||
void CreatureLevList::ensureCustomData(const MWWorld::Ptr &ptr) const
|
||||
|
|
|
@ -388,6 +388,8 @@ namespace MWClass
|
|||
|
||||
data->mNpcStats.setGoldPool(gold);
|
||||
|
||||
data->mNpcStats.setNeedRecalcDynamicStats(false);
|
||||
|
||||
// store
|
||||
ptr.getRefData().setCustomData (data.release());
|
||||
|
||||
|
|
|
@ -151,7 +151,8 @@ void CompanionWindow::onMessageBoxButtonClicked(int button)
|
|||
"minimumprofit", mPtr.getClass().getNpcStats(mPtr).getProfit());
|
||||
|
||||
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 linkNormal (150/255.f, 50/255.f, 30/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);
|
||||
mLinks.push_back(link);
|
||||
|
@ -600,7 +600,7 @@ namespace MWGui
|
|||
|
||||
void DialogueWindow::addChoice(const std::string& choice, int id)
|
||||
{
|
||||
mChoices[choice] = id;
|
||||
mChoices.push_back(std::make_pair(choice, id));
|
||||
updateHistory();
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ namespace MWGui
|
|||
bool mGoodbye;
|
||||
|
||||
std::vector<DialogueText*> mHistoryContents;
|
||||
std::map<std::string, int> mChoices;
|
||||
std::vector<std::pair<std::string, int> > mChoices;
|
||||
|
||||
std::vector<Link*> mLinks;
|
||||
std::map<std::string, Link*> mTopicLinks;
|
||||
|
|
|
@ -99,7 +99,9 @@ namespace MWGui
|
|||
setCoord(0, 0, 300, 300);
|
||||
mDynamicToolTipBox->setVisible(true);
|
||||
ToolTipInfo info;
|
||||
info.caption=mFocusObject.getCellRef().getRefId();
|
||||
info.caption = mFocusObject.getClass().getName(mFocusObject);
|
||||
if (info.caption.empty())
|
||||
info.caption=mFocusObject.getCellRef().getRefId();
|
||||
info.icon="";
|
||||
tooltipSize = createToolTip(info);
|
||||
}
|
||||
|
|
|
@ -320,7 +320,7 @@ namespace MWMechanics
|
|||
}
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "aitravel.hpp"
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
#include <components/esm/aisequence.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;
|
||||
if(!mPathFinder.isPathConstructed() || cellChange)
|
||||
{
|
||||
|
|
|
@ -745,29 +745,55 @@ bool CharacterController::updateCreatureState()
|
|||
{
|
||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||
|
||||
// These are unique animations and not linked to movement type. Just pick one randomly.
|
||||
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";
|
||||
|
||||
mAnimation->play(mCurrentWeapon, Priority_Weapon,
|
||||
MWRender::Animation::Group_All, true,
|
||||
1, "start", "stop",
|
||||
0.0f, 0);
|
||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
void CreatureStats::setNeedRecalcDynamicStats(bool val)
|
||||
{
|
||||
mRecalcDynamicStats = val;
|
||||
}
|
||||
|
||||
void CreatureStats::setKnockedDown(bool value)
|
||||
{
|
||||
mKnockdown = value;
|
||||
|
|
|
@ -92,6 +92,7 @@ namespace MWMechanics
|
|||
void setAttackStrength(float value);
|
||||
|
||||
bool needToRecalcDynamicStats();
|
||||
void setNeedRecalcDynamicStats(bool val);
|
||||
|
||||
void addToFallHeight(float height);
|
||||
|
||||
|
|
|
@ -1120,7 +1120,10 @@ namespace MWMechanics
|
|||
ptr.getClass().getCreatureStats(ptr).friendlyHit();
|
||||
|
||||
if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4)
|
||||
{
|
||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Attacking peaceful NPCs is a crime
|
||||
|
|
|
@ -805,7 +805,25 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
|
|||
attachArrow();
|
||||
|
||||
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)
|
||||
mPtr.getClass().block(mPtr);
|
||||
|
|
Loading…
Reference in a new issue