diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 57a417722e..4ca6e95812 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -63,7 +63,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence alchemy + activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate ) add_openmw_dir (mwbase diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index d646d5acad..2299053cdc 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -356,7 +356,7 @@ void OMW::Engine::go() // Create dialog system mEnvironment.setJournal (new MWDialogue::Journal); - mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions)); + mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts)); // Sets up the input system mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 881a02d003..31cef7f70e 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -75,11 +75,11 @@ namespace namespace MWDialogue { - DialogueManager::DialogueManager (const Compiler::Extensions& extensions) : + DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose) : mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) , mTemporaryDispositionChange(0.f) - , mPermanentDispositionChange(0.f) + , mPermanentDispositionChange(0.f), mScriptVerbose (scriptVerbose) { mChoice = -1; mIsInChoice = false; @@ -129,7 +129,7 @@ namespace MWDialogue mIsInChoice = false; mActor = actor; - + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); mTalkedTo = creatureStats.hasTalkedToPlayer(); creatureStats.talkedToPlayer(); @@ -174,6 +174,8 @@ namespace MWDialogue bool DialogueManager::compile (const std::string& cmd,std::vector& code) { + bool success = true; + try { mErrorHandler.reset(); @@ -195,23 +197,33 @@ namespace MWDialogue Compiler::ScriptParser parser(mErrorHandler,mCompilerContext, locals, false); scanner.scan (parser); - if(mErrorHandler.isGood()) - { - parser.getCode(code); - return true; - } - return false; + + if (!mErrorHandler.isGood()) + success = false; + + if (success) + parser.getCode (code); } catch (const Compiler::SourceException& /* error */) { // error has already been reported via error handler + success = false; } catch (const std::exception& error) { - printError (std::string ("An exception has been thrown: ") + error.what()); + std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl; + success = false; } - return false; + if (!success && mScriptVerbose) + { + std::cerr + << "compiling failed (dialogue script)" << std::endl + << cmd + << std::endl << std::endl; + } + + return success; } void DialogueManager::executeScript (const std::string& script) @@ -228,7 +240,7 @@ namespace MWDialogue } catch (const std::exception& error) { - printError (std::string ("An exception has been thrown: ") + error.what()); + std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what(); } } } @@ -252,7 +264,7 @@ namespace MWDialogue if (filter.search (*iter)) { mActorKnownTopics.push_back (toLower (iter->mId)); - + //does the player know the topic? if (mKnownTopics.find (toLower (iter->mId)) != mKnownTopics.end()) { @@ -328,8 +340,8 @@ namespace MWDialogue if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) { Filter filter (mActor, mChoice, mTalkedTo); - - if (const ESM::DialInfo *info = filter.search (mDialogueMap[keyword])) + + if (const ESM::DialInfo *info = filter.search (mDialogueMap[keyword])) { std::string text = info->mResponse; std::string script = info->mResultScript; @@ -377,7 +389,7 @@ namespace MWDialogue if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic) { Filter filter (mActor, mChoice, mTalkedTo); - + if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic])) { mChoiceMap.clear(); @@ -392,7 +404,7 @@ namespace MWDialogue } } } - + updateTopics(); } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 8e862f9328..9e1971b0fc 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -35,6 +35,7 @@ namespace MWDialogue float mTemporaryDispositionChange; float mPermanentDispositionChange; + bool mScriptVerbose; void parseText (const std::string& text); @@ -47,7 +48,7 @@ namespace MWDialogue public: - DialogueManager (const Compiler::Extensions& extensions); + DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose); virtual void startDialogue (const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 21904b4bc2..0deef7fd03 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -74,7 +74,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter==stats.getFactionRanks().end()) return false; - + // check rank if (iter->second < info.mData.mRank) return false; @@ -87,14 +87,14 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (info.mData.mGender==(npc->mBase->mFlags & npc->mBase->Female ? 0 : 1)) return false; } - + return true; } bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const { const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - + // check player faction if (!info.mPcFaction.empty()) { @@ -123,7 +123,7 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const iter != info.mSelects.end(); ++iter) if (!testSelectStruct (*iter)) return false; - + return true; } @@ -131,7 +131,7 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) return select.isInverted(); - + switch (select.getType()) { case SelectWrapper::Type_None: return true; @@ -139,7 +139,7 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select); case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select)); } - + return true; } @@ -148,11 +148,11 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c switch (select.getFunction()) { case SelectWrapper::Function_Global: - + // internally all globals are float :( return select.selectCompare ( MWBase::Environment::get().getWorld()->getGlobalVariable (select.getName()).mFloat); - + case SelectWrapper::Function_Local: { std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor); @@ -178,7 +178,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c if (imData.mNumShorts) return select.selectCompare (static_cast (locals.mShorts[i])); - + i -= script->mData.mNumShorts; if (imData.mNumLongs) @@ -186,39 +186,39 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c i -= script->mData.mNumShorts; - return select.selectCompare (locals.mFloats.at (i)); + return select.selectCompare (locals.mFloats.at (i)); } - + case SelectWrapper::Function_PcHealthPercent: { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - - float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() / + + float ratio = MWWorld::Class::get (player).getCreatureStats (player).getHealth().getCurrent() / MWWorld::Class::get (player).getCreatureStats (player).getHealth().getModified(); - + return select.selectCompare (ratio); } - + case SelectWrapper::Function_PcDynamicStat: { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - + float value = MWWorld::Class::get (player).getCreatureStats (player). - getDynamic (select.getArgument()).getCurrent(); - + getDynamic (select.getArgument()).getCurrent(); + return select.selectCompare (value); } - + case SelectWrapper::Function_HealthPercent: { - float ratio = MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getCurrent() / + float ratio = MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getCurrent() / MWWorld::Class::get (mActor).getCreatureStats (mActor).getHealth().getModified(); - + return select.selectCompare (ratio); } default: - + throw std::runtime_error ("unknown numeric select function"); } } @@ -230,11 +230,11 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con switch (select.getFunction()) { case SelectWrapper::Function_Journal: - + return MWBase::Environment::get().getJournal()->getJournalIndex (select.getName()); - - case SelectWrapper::Function_Item: - { + + case SelectWrapper::Function_Item: + { MWWorld::ContainerStore& store = MWWorld::Class::get (player).getContainerStore (player); int sum = 0; @@ -244,39 +244,39 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) if (toLower(iter->getCellRef().mRefID) == name) sum += iter->getRefData().getCount(); - + return sum; } case SelectWrapper::Function_Dead: return MWBase::Environment::get().getMechanicsManager()->countDeaths (select.getName()); - + case SelectWrapper::Function_Choice: - + return mChoice; - + case SelectWrapper::Function_AiSetting: - + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAiSetting (select.getArgument()); - + case SelectWrapper::Function_PcAttribute: - + return MWWorld::Class::get (player).getCreatureStats (player). getAttribute (select.getArgument()).getModified(); case SelectWrapper::Function_PcSkill: - + return static_cast (MWWorld::Class::get (player). getNpcStats (player).getSkill (select.getArgument()).getModified()); - + case SelectWrapper::Function_FriendlyHit: { int hits = MWWorld::Class::get (mActor).getCreatureStats (mActor).getFriendlyHits(); - return hits>4 ? 4 : hits; + return hits>4 ? 4 : hits; } - + case SelectWrapper::Function_PcLevel: return MWWorld::Class::get (player).getCreatureStats (player).getLevel(); @@ -284,26 +284,26 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con case SelectWrapper::Function_PcGender: return player.get()->mBase->mFlags & ESM::NPC::Female ? 0 : 1; - + case SelectWrapper::Function_PcClothingModifier: { MWWorld::InventoryStore& store = MWWorld::Class::get (player).getInventoryStore (player); int value = 0; - + for (int i=0; i<=15; ++i) // everything except thigns held in hands and amunition { MWWorld::ContainerStoreIterator slot = store.getSlot (i); - + if (slot!=store.end()) value += MWWorld::Class::get (*slot).getValue (*slot); } - + return value; } - + case SelectWrapper::Function_PcCrimeLevel: - + return MWWorld::Class::get (player).getNpcStats (player).getBounty(); case SelectWrapper::Function_RankRequirement: @@ -313,12 +313,12 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con std::string faction = MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; - + int rank = getFactionRank (player, faction); - + if (rank>=9) return 0; // max rank - + int result = 0; if (hasFactionRankSkillRequirements (player, faction, rank+1)) @@ -328,16 +328,68 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con result += 2; return result; - } - + } + case SelectWrapper::Function_Level: - + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getLevel(); - + case SelectWrapper::Function_PCReputation: - - return MWWorld::Class::get (player).getNpcStats (player).getReputation(); - + + return MWWorld::Class::get (player).getNpcStats (player).getReputation(); + + case SelectWrapper::Function_Weather: + + return MWBase::Environment::get().getWorld()->getCurrentWeather(); + + case SelectWrapper::Function_Reputation: + + return MWWorld::Class::get (mActor).getNpcStats (mActor).getReputation(); + + case SelectWrapper::Function_FactionRankDiff: + { + if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) + return 0; + + std::pair faction = + *MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin(); + + int rank = getFactionRank (player, faction.first); + + return rank-faction.second; + } + + case SelectWrapper::Function_WerewolfKills: + + return MWWorld::Class::get (player).getNpcStats (player).getWerewolfKills(); + + case SelectWrapper::Function_RankLow: + case SelectWrapper::Function_RankHigh: + { + bool low = select.getFunction()==SelectWrapper::Function_RankLow; + + if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) + return 0; + + std::string factionId = + MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; + + int value = 0; + + const ESM::Faction& faction = + *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); + + MWMechanics::NpcStats& playerStats = MWWorld::Class::get (player).getNpcStats (player); + + for (std::vector::const_iterator iter (faction.mReactions.begin()); + iter!=faction.mReactions.end(); ++iter) + if (playerStats.getFactionRanks().find (iter->mFaction)!=playerStats.getFactionRanks().end()) + if (low ? iter->mReactionmReaction>value) + value = iter->mReaction; + + return value; + } + default: throw std::runtime_error ("unknown integer select function"); @@ -351,13 +403,13 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co switch (select.getFunction()) { case SelectWrapper::Function_False: - + return false; - + case SelectWrapper::Function_Id: - + return select.getName()==toLower (MWWorld::Class::get (mActor).getId (mActor)); - + case SelectWrapper::Function_Faction: return toLower (mActor.get()->mBase->mFaction)==select.getName(); @@ -371,9 +423,9 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return toLower (mActor.get()->mBase->mRace)==select.getName(); case SelectWrapper::Function_Cell: - + return toLower (mActor.getCell()->mCell->mName)==select.getName(); - + case SelectWrapper::Function_SameGender: return (player.get()->mBase->mFlags & ESM::NPC::Female)== @@ -383,46 +435,70 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return toLower (mActor.get()->mBase->mRace)!= toLower (player.get()->mBase->mRace); - + case SelectWrapper::Function_SameFaction: return MWWorld::Class::get (mActor).getNpcStats (mActor).isSameFaction ( MWWorld::Class::get (player).getNpcStats (player)); - + case SelectWrapper::Function_PcCommonDisease: return MWWorld::Class::get (player).getCreatureStats (player).hasCommonDisease(); - + case SelectWrapper::Function_PcBlightDisease: return MWWorld::Class::get (player).getCreatureStats (player).hasBlightDisease(); - + case SelectWrapper::Function_PcCorprus: - + return MWWorld::Class::get (player).getCreatureStats (player). getMagicEffects().get (132).mMagnitude!=0; - + case SelectWrapper::Function_PcExpelled: { if (MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().empty()) return false; - + std::string faction = MWWorld::Class::get (mActor).getNpcStats (mActor).getFactionRanks().begin()->first; - + std::set& expelled = MWWorld::Class::get (player).getNpcStats (player).getExpelled(); - + return expelled.find (faction)!=expelled.end(); } - + case SelectWrapper::Function_PcVampire: - + return MWWorld::Class::get (player).getNpcStats (player).isVampire(); - + case SelectWrapper::Function_TalkedToPc: - + return mTalkedToPlayer; + case SelectWrapper::Function_Alarmed: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).isAlarmed(); + + case SelectWrapper::Function_Detected: + + return MWWorld::Class::get (mActor).hasDetected (mActor, player); + + case SelectWrapper::Function_Attacked: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getAttacked(); + + case SelectWrapper::Function_ShouldAttack: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).isHostile(); + + case SelectWrapper::Function_CreatureTargetted: + + return MWWorld::Class::get (mActor).getCreatureStats (mActor).getCreatureTargetted(); + + case SelectWrapper::Function_PCWerewolf: + + return MWWorld::Class::get (player).getNpcStats (player).isWerewolf(); + default: throw std::runtime_error ("unknown boolean select function"); @@ -432,12 +508,12 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co int MWDialogue::Filter::getFactionRank (const MWWorld::Ptr& actor, const std::string& factionId) const { MWMechanics::NpcStats& stats = MWWorld::Class::get (actor).getNpcStats (actor); - + std::map::const_iterator iter = stats.getFactionRanks().find (factionId); - + if (iter==stats.getFactionRanks().end()) return -1; - + return iter->second; } diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index ae5b8c582f..bba17bfd10 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -34,7 +34,7 @@ namespace throw std::runtime_error ("unknown compare type in dialogue info select"); } - + template bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1) { @@ -49,21 +49,22 @@ namespace } else throw std::runtime_error ( - "unsupported variable type in dialogue info select"); + "unsupported variable type in dialogue info select"); } } MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() const { int index = 0; - + std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index; switch (index) { - // 0, 1 + case 0: return Function_RankLow; + case 1: return Function_RankHigh; case 2: return Function_RankRequirement; - // 3 + case 3: return Function_Reputation; case 4: return Function_HealthPercent; case 5: return Function_PCReputation; case 6: return Function_PcLevel; @@ -82,22 +83,26 @@ MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::decodeFunction() case 44: return Function_SameGender; case 45: return Function_SameRace; case 46: return Function_SameFaction; - // 47-49 + case 47: return Function_FactionRankDiff; + case 48: return Function_Detected; + case 49: return Function_Alarmed; case 50: return Function_Choice; case 51: case 52: case 53: case 54: case 55: case 56: case 57: return Function_PcAttribute; case 58: return Function_PcCorprus; - // 59 + case 59: return Function_Weather; case 60: return Function_PcVampire; case 61: return Function_Level; - // 62 + case 62: return Function_Attacked; case 63: return Function_TalkedToPc; case 64: return Function_PcDynamicStat; - // 65 + case 65: return Function_CreatureTargetted; case 66: return Function_FriendlyHit; case 67: case 68: case 69: case 70: return Function_AiSetting; - // 71 + case 71: return Function_ShouldAttack; + case 72: return Function_PCWerewolf; + case 73: return Function_WerewolfKills; } - + return Function_False; } @@ -130,11 +135,11 @@ int MWDialogue::SelectWrapper::getArgument() const { if (mSelect.mSelectRule[1]!='1') return 0; - + int index = 0; - + std::istringstream (mSelect.mSelectRule.substr(2,2)) >> index; - + switch (index) { // AI settings @@ -142,7 +147,7 @@ int MWDialogue::SelectWrapper::getArgument() const case 68: return 0; case 69: return 3; case 70: return 2; - + // attributes case 10: return 0; case 51: return 1; @@ -152,7 +157,7 @@ int MWDialogue::SelectWrapper::getArgument() const case 55: return 5; case 56: return 6; case 57: return 7; - + // skills case 11: return 0; case 12: return 1; @@ -181,13 +186,13 @@ int MWDialogue::SelectWrapper::getArgument() const case 35: return 24; case 36: return 25; case 37: return 26; - + // dynamic stats case 8: return 1; case 9: return 2; case 64: return 0; } - + return 0; } @@ -204,17 +209,21 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_PcCrimeLevel, Function_RankRequirement, Function_Level, Function_PCReputation, + Function_Weather, + Function_Reputation, Function_FactionRankDiff, + Function_WerewolfKills, + Function_RankLow, Function_RankHigh, Function_None // end marker }; - + static const Function numericFunctions[] = { Function_Global, Function_Local, Function_PcDynamicStat, Function_PcHealthPercent, Function_HealthPercent, Function_None // end marker - }; - + }; + static const Function booleanFunctions[] = { Function_False, @@ -223,15 +232,19 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, Function_PcExpelled, Function_PcVampire, Function_TalkedToPc, + Function_Alarmed, Function_Detected, + Function_Attacked, Function_ShouldAttack, + Function_CreatureTargetted, + Function_PCWerewolf, Function_None // end marker - }; - + }; + Function function = getFunction(); for (int i=0; integerFunctions[i]!=Function_None; ++i) if (integerFunctions[i]==function) return Type_Integer; - + for (int i=0; numericFunctions[i]!=Function_None; ++i) if (numericFunctions[i]==function) return Type_Numeric; @@ -239,7 +252,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const for (int i=0; booleanFunctions[i]!=Function_None; ++i) if (booleanFunctions[i]==function) return Type_Boolean; - + return Type_None; } @@ -261,15 +274,18 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const Function_PcVampire, Function_PcCrimeLevel, Function_RankRequirement, + Function_Reputation, Function_FactionRankDiff, + Function_PCWerewolf, Function_WerewolfKills, + Function_RankLow, Function_RankHigh, Function_None // end marker }; Function function = getFunction(); - + for (int i=0; functions[i]!=Function_None; ++i) if (functions[i]==function) return true; - + return false; } diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index 15cd5bfff9..b77ed7985a 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -8,9 +8,9 @@ namespace MWDialogue class SelectWrapper { const ESM::DialInfo::SelectStruct& mSelect; - + public: - + enum Function { Function_None, Function_False, @@ -36,7 +36,13 @@ namespace MWDialogue Function_PcLevel, Function_PcHealthPercent, Function_PcDynamicStat, Function_PcGender, Function_PcClothingModifier, Function_PcCrimeLevel, Function_RankRequirement, - Function_HealthPercent, Function_Level, Function_PCReputation + Function_HealthPercent, Function_Level, Function_PCReputation, + Function_Weather, + Function_Reputation, Function_Alarmed, Function_FactionRankDiff, Function_Detected, + Function_Attacked, Function_ShouldAttack, + Function_CreatureTargetted, + Function_PCWerewolf, Function_WerewolfKills, + Function_RankLow, Function_RankHigh }; enum Type @@ -46,32 +52,32 @@ namespace MWDialogue Type_Numeric, Type_Boolean }; - + private: - + Function decodeFunction() const; - + public: - + SelectWrapper (const ESM::DialInfo::SelectStruct& select); - + Function getFunction() const; - + int getArgument() const; - + Type getType() const; - + bool isInverted() const; - + bool isNpcOnly() const; ///< \attention Do not call any of the select functions for this select struct! - + bool selectCompare (int value) const; bool selectCompare (float value) const; - + bool selectCompare (bool value) const; - + std::string getName() const; ///< Return case-smashed name. }; diff --git a/apps/openmw/mwmechanics/aiactivate.cpp b/apps/openmw/mwmechanics/aiactivate.cpp new file mode 100644 index 0000000000..b94c8c2599 --- /dev/null +++ b/apps/openmw/mwmechanics/aiactivate.cpp @@ -0,0 +1,21 @@ +#include "aiactivate.hpp" +#include + +MWMechanics::AiActivate::AiActivate(const std::string &objectId) +: mObjectId(objectId) +{ +} +MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const +{ + return new AiActivate(*this); +} +bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiActivate completed.\n"; + return true; +} + +int MWMechanics::AiActivate::getTypeId() const +{ + return 4; +} diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp new file mode 100644 index 0000000000..7f3d4016dc --- /dev/null +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -0,0 +1,23 @@ +#ifndef GAME_MWMECHANICS_AIACTIVATE_H +#define GAME_MWMECHANICS_AIACTIVATE_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + + class AiActivate : public AiPackage + { + public: + AiActivate(const std::string &objectId); + virtual AiActivate *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + + private: + std::string mObjectId; + }; +} +#endif // GAME_MWMECHANICS_AIACTIVATE_H diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp new file mode 100644 index 0000000000..27cd9095dc --- /dev/null +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -0,0 +1,24 @@ +#include "aiescort.hpp" +#include + +MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z) +: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration) +{ +} + +MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const +{ + return new AiEscort(*this); +} + +bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiEscort completed. \n"; + return true; +} + +int MWMechanics::AiEscort::getTypeId() const +{ + return 2; +} + diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp new file mode 100644 index 0000000000..fef70f508e --- /dev/null +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MWMECHANICS_AIESCORT_H +#define GAME_MWMECHANICS_AIESCORT_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + class AiEscort : public AiPackage + { + public: + AiEscort(const std::string &actorId,int duration, float x, float y, float z); + virtual AiEscort *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + std::string mActorId; + float mX; + float mY; + float mZ; + int mDuration; + + }; +} +#endif diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp new file mode 100644 index 0000000000..3fee6d98c3 --- /dev/null +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -0,0 +1,22 @@ +#include "aifollow.hpp" +#include + +MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) +: mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId) +{ +} +MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const +{ + return new AiFollow(*this); +} + + bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiFollow completed.\n"; + return true; +} + + int MWMechanics::AiFollow::getTypeId() const +{ + return 3; +} diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp new file mode 100644 index 0000000000..ded13d7800 --- /dev/null +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -0,0 +1,27 @@ +#ifndef GAME_MWMECHANICS_AIFALLOW_H +#define GAME_MWMECHANICS_AIFALLOW_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + + class AiFollow : public AiPackage + { + public: + AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z); + virtual AiFollow *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + + private: + float mDuration; + float mX; + float mY; + float mZ; + std::string mActorId; + }; +} +#endif diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp new file mode 100644 index 0000000000..897dd17480 --- /dev/null +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -0,0 +1,25 @@ +#include "aitravel.hpp" +#include + +MWMechanics::AiTravel::AiTravel(float x, float y, float z) +: mX(x),mY(y),mZ(z) +{ +} + +MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const +{ + return new AiTravel(*this); +} + +bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiTravel completed.\n"; + return true; +} + +int MWMechanics::AiTravel::getTypeId() const +{ + return 1; +} + + diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp new file mode 100644 index 0000000000..1c6abbf279 --- /dev/null +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -0,0 +1,27 @@ +#ifndef GAME_MWMECHANICS_AITRAVEL_H +#define GAME_MWMECHANICS_AITRAVEL_H + +#include "aipackage.hpp" + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp new file mode 100644 index 0000000000..e9db6d212a --- /dev/null +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -0,0 +1,23 @@ +#include "aiwander.hpp" +#include + +MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle): + mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle) +{ +} + +MWMechanics::AiPackage * MWMechanics::AiWander::clone() const +{ + return new AiWander(*this); +} + +bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) +{ + std::cout << "AiWadner completed.\n"; + return true; +} + +int MWMechanics::AiWander::getTypeId() const +{ + return 0; +} diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp new file mode 100644 index 0000000000..a71858febc --- /dev/null +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -0,0 +1,29 @@ +#ifndef GAME_MWMECHANICS_AIWANDER_H +#define GAME_MWMECHANICS_AIWANDER_H + +#include "aipackage.hpp" +#include + +namespace MWMechanics +{ + + class AiWander : public AiPackage + { + public: + + AiWander(int distance, int duration, int timeOfDay, const std::vector& idle); + virtual AiPackage *clone() const; + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + virtual int getTypeId() const; + ///< 0: Wander + + private: + int mDistance; + int mDuration; + int mTimeOfDay; + std::vector mIdle; + }; + } + +#endif diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 9ee7ca7c27..4be5d55b22 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -8,9 +8,10 @@ #include "../mwbase/world.hpp" namespace MWMechanics -{ +{ CreatureStats::CreatureStats() - : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mFriendlyHits (0), mTalkedTo (false) + : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), + mAttacked (false), mHostile (false) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; @@ -30,26 +31,26 @@ namespace MWMechanics { return mAiSequence; } - + AiSequence& CreatureStats::getAiSequence() { - return mAiSequence; + return mAiSequence; } - - float CreatureStats::getFatigueTerm() const + + float CreatureStats::getFatigueTerm() const { int max = getFatigue().getModified(); int current = getFatigue().getCurrent(); - + float normalised = max==0 ? 1 : std::max (0.0f, static_cast (current)/max); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - + return gmst.find ("fFatigueBase")->getFloat() - gmst.find ("fFatigueMult")->getFloat() * (1-normalised); } - + const Stat &CreatureStats::getAttribute(int index) const { if (index < 0 || index > 7) { @@ -92,13 +93,13 @@ namespace MWMechanics { return mLevel; } - + int CreatureStats::getAiSetting (int index) const { assert (index>=0 && index<4); return mAiSettings[index]; } - + Stat &CreatureStats::getAttribute(int index) { if (index < 0 || index > 7) { @@ -168,7 +169,7 @@ namespace MWMechanics if (index==0 && mDynamic[index].getCurrent()<1) mDead = true; } - + void CreatureStats::setLevel(int level) { mLevel = level; @@ -189,24 +190,24 @@ namespace MWMechanics assert (index>=0 && index<4); mAiSettings[index] = value; } - + bool CreatureStats::isDead() const { return mDead; } - + void CreatureStats::resurrect() { if (mDead) { if (mDynamic[0].getCurrent()<1) mDynamic[0].setCurrent (1); - + if (mDynamic[0].getCurrent()>=1) mDead = false; } } - + bool CreatureStats::hasCommonDisease() const { return mSpells.hasCommonDisease(); @@ -216,24 +217,59 @@ namespace MWMechanics { return mSpells.hasBlightDisease(); } - + int CreatureStats::getFriendlyHits() const { return mFriendlyHits; } - + void CreatureStats::friendlyHit() { ++mFriendlyHits; } - + bool CreatureStats::hasTalkedToPlayer() const { return mTalkedTo; } - + void CreatureStats::talkedToPlayer() { mTalkedTo = true; } + + bool CreatureStats::isAlarmed() const + { + return mAlarmed; + } + + void CreatureStats::setAlarmed (bool alarmed) + { + mAlarmed = alarmed; + } + + bool CreatureStats::getAttacked() const + { + return mAttacked; + } + + void CreatureStats::setAttacked (bool attacked) + { + mAttacked = attacked; + } + + bool CreatureStats::isHostile() const + { + return mHostile; + } + + void CreatureStats::setHostile (bool hostile) + { + mHostile = hostile; + } + + bool CreatureStats::getCreatureTargetted() const + { + return false; + } } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 937cb61cc7..3375c1af83 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -30,6 +30,9 @@ namespace MWMechanics bool mDead; int mFriendlyHits; bool mTalkedTo; + bool mAlarmed; + bool mAttacked; + bool mHostile; public: CreatureStats(); @@ -83,11 +86,11 @@ namespace MWMechanics void setAiSetting (int index, int value); ///< 0: hello, 1 fight, 2 flee, 3 alarm - + const AiSequence& getAiSequence() const; - + AiSequence& getAiSequence(); - + float getFatigueTerm() const; ///< Return effective fatigue @@ -96,23 +99,37 @@ namespace MWMechanics float getLevelHealthBonus() const; bool isDead() const; - + void resurrect(); - + bool hasCommonDisease() const; bool hasBlightDisease() const; - + int getFriendlyHits() const; ///< Number of friendly hits received. - + void friendlyHit(); ///< Increase number of friendly hits by one. - + bool hasTalkedToPlayer() const; ///< Has this creature talked with the player before? - + void talkedToPlayer(); + + bool isAlarmed() const; + + void setAlarmed (bool alarmed); + + bool getAttacked() const; + + void setAttacked (bool attacked); + + bool isHostile() const; + + void setHostile (bool hostile); + + bool getCreatureTargetted() const; }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 26415b6311..20a0360e77 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -22,7 +22,7 @@ MWMechanics::NpcStats::NpcStats() : mMovementFlags (0), mDrawState (DrawState_Nothing), mBounty (0) -, mLevelProgress(0), mDisposition(0), mVampire (0), mReputation(0) +, mLevelProgress(0), mDisposition(0), mVampire (0), mReputation(0), mWerewolf (false), mWerewolfKills (0) { mSkillIncreases.resize (ESM::Attribute::Length); for (int i=0; ifirst)!=npcStats.mFactionRank.end()) return true; - + return false; } @@ -280,10 +280,10 @@ void MWMechanics::NpcStats::setBounty (int bounty) int MWMechanics::NpcStats::getFactionReputation (const std::string& faction) const { std::map::const_iterator iter = mFactionReputation.find (faction); - + if (iter==mFactionReputation.end()) return 0; - + return iter->second; } @@ -321,19 +321,33 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); std::vector skills; - + for (int i=0; i<6; ++i) skills.push_back (static_cast (getSkill (faction.mData.mSkillID[i]).getModified())); - + std::sort (skills.begin(), skills.end()); - + std::vector::const_reverse_iterator iter = skills.rbegin(); - + const ESM::RankData& rankData = faction.mData.mRankData[rank]; - + if (*iter=rankData.mSkill2; } +bool MWMechanics::NpcStats::isWerewolf() const +{ + return mWerewolf; +} + +void MWMechanics::NpcStats::setWerewolf (bool set) +{ + mWerewolf = set; +} + +int MWMechanics::NpcStats::getWerewolfKills() const +{ + return mWerewolfKills; +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 46af216d9c..af32bd294a 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -51,6 +51,8 @@ namespace MWMechanics std::map mFactionReputation; bool mVampire; int mReputation; + bool mWerewolf; + int mWerewolfKills; int mLevelProgress; // 0-10 @@ -83,7 +85,7 @@ namespace MWMechanics Stat& getSkill (int index); std::map& getFactionRanks(); - + std::set& getExpelled(); bool isSameFaction (const NpcStats& npcStats) const; @@ -107,24 +109,30 @@ namespace MWMechanics int getLevelupAttributeMultiplier(int attribute) const; void levelUp(); - + void flagAsUsed (const std::string& id); - + bool hasBeenUsed (const std::string& id) const; - + int getBounty() const; - + void setBounty (int bounty); - + int getFactionReputation (const std::string& faction) const; - + void setFactionReputation (const std::string& faction, int value); - + bool isVampire() const; - + void setVampire (bool set); - + bool hasSkillsForRank (const std::string& factionId, int rank) const; + + bool isWerewolf() const; + + void setWerewolf (bool set); + + int getWerewolfKills() const; }; } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index cb984e257c..5a939b5db0 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -31,7 +31,13 @@ op 0x2000e: PCGetRank implicit op 0x2000f: PCGetRank explicit op 0x20010: AiWander op 0x20011: AiWander, explicit reference -op s 0x20012-0x3ffff unused +op 0x20012: GetPCFacRep +op 0x20013: GetPCFacRep, explicit reference +op 0x20014: SetPCFacRep +op 0x20015: SetPCFacRep, explicit reference +op 0x20016: ModPCFacRep +op 0x20017: ModPCFacRep, explicit reference +op s 0x20018-0x3ffff unused Segment 4: (not implemented yet) @@ -198,14 +204,22 @@ op 0x2000197: Position Explicit op 0x2000198: PositionCell op 0x2000199: PositionCell Explicit op 0x200019a: PlaceItemCell -op 0x200019b: PlaceItem +op 0x200019b: PlaceItem op 0x200019c: PlaceAtPc -op 0x200019d: PlaceAtMe +op 0x200019d: PlaceAtMe op 0x200019e: PlaceAtMe Explicit op 0x200019f: GetPcSleep op 0x20001a0: ShowMap op 0x20001a1: FillMap op 0x20001a2: WakeUpPc op 0x20001a3: GetDeadCount -opcodes 0x20001a4-0x3ffffff unused +op 0x20001a4: SetDisposition +op 0x20001a5: SetDisposition, Explicit +op 0x20001a6: GetDisposition +op 0x20001a7: GetDisposition, Explicit +op 0x20001a8: CommonDisease +op 0x20001a9: CommonDisease, explicit reference +op 0x20001aa: BlightDisease +op 0x20001ab: BlightDisease, explicit reference +opcodes 0x20001ac-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 4fbb81b37b..f6a31dd7f7 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -33,13 +33,13 @@ namespace std::string getDialogueActorFaction() { MWWorld::Ptr actor = MWBase::Environment::get().getDialogueManager()->getActor(); - + MWMechanics::NpcStats stats = MWWorld::Class::get (actor).getNpcStats (actor); - + if (stats.getFactionRanks().empty()) throw std::runtime_error ( "failed to determine dialogue actors faction (because actor is factionless)"); - + return stats.getFactionRanks().begin()->first; } } @@ -208,7 +208,7 @@ namespace MWScript .getDynamic (mIndex)); stat.setModified (value, 0); - + MWWorld::Class::get (ptr).getCreatureStats (ptr).setDynamic (mIndex, stat); } }; @@ -565,7 +565,7 @@ namespace MWScript { if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) { - //throw exception? + factionID = ""; } else { @@ -601,13 +601,43 @@ namespace MWScript { MWWorld::Ptr ptr = R()(runtime); -// Interpreter::Type_Integer value = runtime[0].mInteger; + Interpreter::Type_Integer value = runtime[0].mInteger; runtime.pop(); - /// \todo modify disposition towards the player + MWWorld::Class::get (ptr).getNpcStats (ptr).setBaseDisposition + (MWWorld::Class::get (ptr).getNpcStats (ptr).getBaseDisposition() + value); } }; - + + template + class OpSetDisposition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr).getNpcStats (ptr).setBaseDisposition (value); + } + }; + + template + class OpGetDisposition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get (ptr).getNpcStats (ptr).getBaseDisposition()); + } + }; + class OpGetDeadCount : public Interpreter::Opcode0 { public: @@ -617,7 +647,138 @@ namespace MWScript std::string id = runtime.getStringLiteral (runtime[0].mInteger); runtime[0].mInteger = MWBase::Environment::get().getMechanicsManager()->countDeaths (id); } - }; + }; + + template + class OpGetPCFacRep : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + std::string factionId; + + if (arg0==1) + { + factionId = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + MWWorld::Ptr ptr = R()(runtime); + + if (!MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().empty()) + factionId = MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().begin()->first; + } + + if (factionId.empty()) + throw std::runtime_error ("failed to determine faction"); + + boost::algorithm::to_lower (factionId); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + runtime.push ( + MWWorld::Class::get (player).getNpcStats (player).getFactionReputation (factionId)); + } + }; + + template + class OpSetPCFacRep : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + std::string factionId; + + if (arg0==1) + { + factionId = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + MWWorld::Ptr ptr = R()(runtime); + + if (!MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().empty()) + factionId = MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().begin()->first; + } + + if (factionId.empty()) + throw std::runtime_error ("failed to determine faction"); + + boost::algorithm::to_lower (factionId); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, value); + } + }; + + template + class OpModPCFacRep : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + std::string factionId; + + if (arg0==1) + { + factionId = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + MWWorld::Ptr ptr = R()(runtime); + + if (!MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().empty()) + factionId = MWWorld::Class::get (ptr).getNpcStats (ptr).getFactionRanks().begin()->first; + } + + if (factionId.empty()) + throw std::runtime_error ("failed to determine faction"); + + boost::algorithm::to_lower (factionId); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getNpcStats (player).setFactionReputation (factionId, + MWWorld::Class::get (player).getNpcStats (player).getFactionReputation (factionId)+ + value); + } + }; + + template + class OpGetCommonDisease : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get (ptr).getCreatureStats (ptr).hasCommonDisease()); + } + }; + + template + class OpGetBlightDisease : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get (ptr).getCreatureStats (ptr).hasBlightDisease()); + } + }; const int numberOfAttributes = 8; @@ -665,14 +826,30 @@ namespace MWScript const int opcodeGetPCRankExplicit = 0x2000f; const int opcodeModDisposition = 0x200014d; const int opcodeModDispositionExplicit = 0x200014e; + const int opcodeSetDisposition = 0x20001a4; + const int opcodeSetDispositionExplicit = 0x20001a5; + const int opcodeGetDisposition = 0x20001a6; + const int opcodeGetDispositionExplicit = 0x20001a7; const int opcodeGetLevel = 0x200018c; const int opcodeGetLevelExplicit = 0x200018d; const int opcodeSetLevel = 0x200018e; const int opcodeSetLevelExplicit = 0x200018f; - + const int opcodeGetDeadCount = 0x20001a3; + const int opcodeGetPCFacRep = 0x20012; + const int opcodeGetPCFacRepExplicit = 0x20013; + const int opcodeSetPCFacRep = 0x20014; + const int opcodeSetPCFacRepExplicit = 0x20015; + const int opcodeModPCFacRep = 0x20016; + const int opcodeModPCFacRepExplicit = 0x20017; + + const int opcodeGetCommonDisease = 0x20001a8; + const int opcodeGetCommonDiseaseExplicit = 0x20001a9; + const int opcodeGetBlightDisease = 0x20001aa; + const int opcodeGetBlightDiseaseExplicit = 0x20001ab; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -752,14 +929,27 @@ namespace MWScript extensions.registerInstruction("pcraiserank","/S",opcodePCRaiseRank); extensions.registerInstruction("pclowerrank","/S",opcodePCLowerRank); extensions.registerInstruction("pcjoinfaction","/S",opcodePCJoinFaction); - extensions.registerInstruction("moddisposition","l",opcodeModDisposition, + extensions.registerInstruction ("moddisposition","l",opcodeModDisposition, opcodeModDispositionExplicit); + extensions.registerInstruction ("setdisposition","l",opcodeSetDisposition, + opcodeSetDispositionExplicit); + extensions.registerFunction ("getdisposition",'l', "",opcodeGetDisposition, + opcodeGetDispositionExplicit); extensions.registerFunction("getpcrank",'l',"/S",opcodeGetPCRank,opcodeGetPCRankExplicit); extensions.registerInstruction("setlevel", "l", opcodeSetLevel, opcodeSetLevelExplicit); extensions.registerFunction("getlevel", 'l', "", opcodeGetLevel, opcodeGetLevelExplicit); - extensions.registerFunction("getdeadcount", 'l', "c", opcodeGetDeadCount); + extensions.registerFunction ("getdeadcount", 'l', "c", opcodeGetDeadCount); + + extensions.registerFunction ("getpcfacrep", 'l', "/c", opcodeGetPCFacRep, opcodeGetPCFacRepExplicit); + extensions.registerInstruction ("setpcfacrep", "l/c", opcodeSetPCFacRep, opcodeSetPCFacRepExplicit); + extensions.registerInstruction ("modpcfacrep", "l/c", opcodeModPCFacRep, opcodeModPCFacRepExplicit); + + extensions.registerFunction ("getcommondisease", 'l', "", opcodeGetCommonDisease, + opcodeGetCommonDiseaseExplicit); + extensions.registerFunction ("getblightdisease", 'l', "", opcodeGetBlightDisease, + opcodeGetBlightDiseaseExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -827,17 +1017,34 @@ namespace MWScript interpreter.installSegment3(opcodePCRaiseRank,new OpPCRaiseRank); interpreter.installSegment3(opcodePCLowerRank,new OpPCLowerRank); interpreter.installSegment3(opcodePCJoinFaction,new OpPCJoinFaction); - interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); - interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); interpreter.installSegment3(opcodeGetPCRank,new OpGetPCRank); interpreter.installSegment3(opcodeGetPCRankExplicit,new OpGetPCRank); + interpreter.installSegment5(opcodeModDisposition,new OpModDisposition); + interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); + interpreter.installSegment5(opcodeSetDisposition,new OpSetDisposition); + interpreter.installSegment5(opcodeSetDispositionExplicit,new OpSetDisposition); + interpreter.installSegment5(opcodeGetDisposition,new OpGetDisposition); + interpreter.installSegment5(opcodeGetDispositionExplicit,new OpGetDisposition); + interpreter.installSegment5 (opcodeGetLevel, new OpGetLevel); interpreter.installSegment5 (opcodeGetLevelExplicit, new OpGetLevel); interpreter.installSegment5 (opcodeSetLevel, new OpSetLevel); interpreter.installSegment5 (opcodeSetLevelExplicit, new OpSetLevel); interpreter.installSegment5 (opcodeGetDeadCount, new OpGetDeadCount); + + interpreter.installSegment3 (opcodeGetPCFacRep, new OpGetPCFacRep); + interpreter.installSegment3 (opcodeGetPCFacRepExplicit, new OpGetPCFacRep); + interpreter.installSegment3 (opcodeSetPCFacRep, new OpSetPCFacRep); + interpreter.installSegment3 (opcodeSetPCFacRepExplicit, new OpSetPCFacRep); + interpreter.installSegment3 (opcodeModPCFacRep, new OpModPCFacRep); + interpreter.installSegment3 (opcodeModPCFacRepExplicit, new OpModPCFacRep); + + interpreter.installSegment5 (opcodeGetCommonDisease, new OpGetCommonDisease); + interpreter.installSegment5 (opcodeGetCommonDiseaseExplicit, new OpGetCommonDisease); + interpreter.installSegment5 (opcodeGetBlightDisease, new OpGetBlightDisease); + interpreter.installSegment5 (opcodeGetBlightDiseaseExplicit, new OpGetBlightDisease); } } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 8c639a874c..c760191496 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -162,6 +162,11 @@ namespace MWWorld return false; } + bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const + { + return false; + } + const Class& Class::get (const std::string& key) { std::map >::const_iterator iter = sClasses.find (key); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4662cbab63..07dcb8fe03 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -191,6 +191,11 @@ namespace MWWorld /// /// (default implementation: return false) + virtual bool hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const; + ///< Has \æ ptr detected \a ptr2? + /// + /// (default implementation: return false) + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. diff --git a/credits.txt b/credits.txt index c9f98861c2..4633dbba1b 100644 --- a/credits.txt +++ b/credits.txt @@ -27,6 +27,7 @@ Jason Hooks (jhooks) Karl-Felix Glatzer (k1ll) Leon Saunders (emoose) Lukasz Gromanowski (lgro) +Marcin Hulist (Gohan) Michael Mc Donnell Michael Papageorgiou (werdanith) Nikolay Kasyanov (corristo)