boost::shared_ptr<MWWorld::Action> Container::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { if (!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) return boost::shared_ptr<MWWorld::Action> (new MWWorld::NullAction ()); if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfContainer"); boost::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); if(sound) action->setSound(sound->mId); return action; } const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::InventoryStore& invStore = player.getClass().getInventoryStore(player); bool needKey = ptr.getCellRef().getLockLevel() > 0; bool hasKey = false; std::string keyName; // make key id lowercase std::string keyId = ptr.getCellRef().getKey(); Misc::StringUtils::toLower(keyId); for (MWWorld::ContainerStoreIterator it = invStore.begin(); it != invStore.end(); ++it) { std::string refId = it->getCellRef().getRefId(); Misc::StringUtils::toLower(refId); if (refId == keyId) { hasKey = true; keyName = it->getClass().getName(*it); } } if (needKey && hasKey) { MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); unlock(ptr); // using a key disarms the trap ptr.getCellRef().setTrap(""); } if (!needKey || hasKey) { if(ptr.getCellRef().getTrap().empty()) { boost::shared_ptr<MWWorld::Action> action (new MWWorld::ActionOpen(ptr)); return action; } else { // Activate trap boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTrap(actor, ptr.getCellRef().getTrap(), ptr)); action->setSound(trapActivationSound); return action; } } else { boost::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction); action->setSound(lockedSound); return action; } }
boost::shared_ptr<Action> prepareNextAction(const MWWorld::Ptr &actor, const MWWorld::Ptr &target) { Spells& spells = actor.getClass().getCreatureStats(actor).getSpells(); float bestActionRating = 0.f; // Default to hand-to-hand combat boost::shared_ptr<Action> bestAction (new ActionWeapon(MWWorld::Ptr())); if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) { bestAction->prepare(actor); return bestAction; } if (actor.getClass().hasInventoryStore(actor)) { MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor); for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { float rating = ratePotion(*it, actor); if (rating > bestActionRating) { bestActionRating = rating; bestAction.reset(new ActionPotion(*it)); } } for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { float rating = rateMagicItem(*it, actor, target); if (rating > bestActionRating) { bestActionRating = rating; bestAction.reset(new ActionEnchantedItem(it)); } } float bestArrowRating = 0; MWWorld::Ptr bestArrow; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { float rating = rateWeapon(*it, actor, target, ESM::Weapon::Arrow); if (rating > bestArrowRating) { bestArrowRating = rating; bestArrow = *it; } } float bestBoltRating = 0; MWWorld::Ptr bestBolt; for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { float rating = rateWeapon(*it, actor, target, ESM::Weapon::Bolt); if (rating > bestBoltRating) { bestBoltRating = rating; bestBolt = *it; } } for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) { std::vector<int> equipmentSlots = it->getClass().getEquipmentSlots(*it).first; if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight) == equipmentSlots.end()) continue; float rating = rateWeapon(*it, actor, target, -1, bestArrowRating, bestBoltRating); if (rating > bestActionRating) { const ESM::Weapon* weapon = it->get<ESM::Weapon>()->mBase; MWWorld::Ptr ammo; if (weapon->mData.mType == ESM::Weapon::MarksmanBow) ammo = bestArrow; else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow) ammo = bestBolt; bestActionRating = rating; bestAction.reset(new ActionWeapon(*it, ammo)); } } } for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it) { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first); float rating = rateSpell(spell, actor, target); if (rating > bestActionRating) { bestActionRating = rating; bestAction.reset(new ActionSpell(spell->mId)); } } if (bestAction.get()) bestAction->prepare(actor); return bestAction; }
virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); runtime.push (ptr.getClass().getNpcStats (ptr).getReputation ()); }
bool ProjectileManager::readRecord(ESM::ESMReader &reader, uint32_t type) { if (type == ESM::REC_PROJ) { ESM::ProjectileState esm; esm.load(reader); ProjectileState state; state.mActorId = esm.mActorId; state.mBowId = esm.mBowId; state.mVelocity = esm.mVelocity; state.mId = esm.mId; state.mAttackStrength = esm.mAttackStrength; std::string model; try { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); MWWorld::Ptr ptr = ref.getPtr(); model = ptr.getClass().getModel(ptr); } catch(...) { return true; } createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), false); mProjectiles.push_back(state); return true; } else if (type == ESM::REC_MPRJ) { ESM::MagicBoltState esm; esm.load(reader); MagicBoltState state; state.mSourceName = esm.mSourceName; state.mId = esm.mId; state.mSpellId = esm.mSpellId; state.mActorId = esm.mActorId; state.mSpeed = esm.mSpeed; state.mStack = esm.mStack; state.mEffects = esm.mEffects; std::string model; try { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId); MWWorld::Ptr ptr = ref.getPtr(); model = ptr.getClass().getModel(ptr); } catch(...) { return true; } createModel(state, model, osg::Vec3f(esm.mPosition), osg::Quat(esm.mOrientation), true); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); state.mSound = sndMgr->playSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); state.mSoundId = esm.mSound; mMagicBolts.push_back(state); return true; } return false; }
void ActionEnchantedItem::prepare(const MWWorld::Ptr &actor) { actor.getClass().getCreatureStats(actor).getSpells().setSelectedSpell(std::string()); actor.getClass().getInventoryStore(actor).setSelectedEnchantItem(mItem); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Spell); }
int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) const { MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { case SelectWrapper::Function_Journal: return MWBase::Environment::get().getJournal()->getJournalIndex (select.getName()); case SelectWrapper::Function_Item: { MWWorld::ContainerStore& store = player.getClass().getContainerStore (player); return store.count(select.getName()); } case SelectWrapper::Function_Dead: return MWBase::Environment::get().getMechanicsManager()->countDeaths (select.getName()); case SelectWrapper::Function_Choice: return mChoice; case SelectWrapper::Function_AiSetting: return mActor.getClass().getCreatureStats (mActor).getAiSetting ( (MWMechanics::CreatureStats::AiSetting)select.getArgument()).getModified(); case SelectWrapper::Function_PcAttribute: return player.getClass().getCreatureStats (player). getAttribute (select.getArgument()).getModified(); case SelectWrapper::Function_PcSkill: return static_cast<int> (player.getClass(). getNpcStats (player).getSkill (select.getArgument()).getModified()); case SelectWrapper::Function_FriendlyHit: { int hits = mActor.getClass().getCreatureStats (mActor).getFriendlyHits(); return hits>4 ? 4 : hits; } case SelectWrapper::Function_PcLevel: return player.getClass().getCreatureStats (player).getLevel(); case SelectWrapper::Function_PcGender: return player.get<ESM::NPC>()->mBase->isMale() ? 0 : 1; case SelectWrapper::Function_PcClothingModifier: { MWWorld::InventoryStore& store = player.getClass().getInventoryStore (player); int value = 0; for (int i=0; i<=15; ++i) // everything except things held in hands and ammunition { MWWorld::ContainerStoreIterator slot = store.getSlot (i); if (slot!=store.end()) value += slot->getClass().getValue (*slot); } return value; } case SelectWrapper::Function_PcCrimeLevel: return player.getClass().getNpcStats (player).getBounty(); case SelectWrapper::Function_RankRequirement: { std::string faction = mActor.getClass().getPrimaryFaction(mActor); if (faction.empty()) return 0; int rank = getFactionRank (player, faction); if (rank>=9) return 0; // max rank int result = 0; if (hasFactionRankSkillRequirements (player, faction, rank+1)) result += 1; if (hasFactionRankReputationRequirements (player, faction, rank+1)) result += 2; return result; } case SelectWrapper::Function_Level: return mActor.getClass().getCreatureStats (mActor).getLevel(); case SelectWrapper::Function_PCReputation: return player.getClass().getNpcStats (player).getReputation(); case SelectWrapper::Function_Weather: return MWBase::Environment::get().getWorld()->getCurrentWeather(); case SelectWrapper::Function_Reputation: return mActor.getClass().getNpcStats (mActor).getReputation(); case SelectWrapper::Function_FactionRankDiff: { std::string faction = mActor.getClass().getPrimaryFaction(mActor); if (faction.empty()) return 0; int rank = getFactionRank (player, faction); int npcRank = mActor.getClass().getPrimaryFactionRank(mActor); return rank-npcRank; } case SelectWrapper::Function_WerewolfKills: return player.getClass().getNpcStats (player).getWerewolfKills(); case SelectWrapper::Function_RankLow: case SelectWrapper::Function_RankHigh: { bool low = select.getFunction()==SelectWrapper::Function_RankLow; std::string factionId = mActor.getClass().getPrimaryFaction(mActor); if (factionId.empty()) return 0; int value = 0; MWMechanics::NpcStats& playerStats = player.getClass().getNpcStats (player); std::map<std::string, int>::const_iterator playerFactionIt = playerStats.getFactionRanks().begin(); for (; playerFactionIt != playerStats.getFactionRanks().end(); ++playerFactionIt) { int reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(factionId, playerFactionIt->first); if (low ? reaction < value : reaction > value) value = reaction; } return value; } case SelectWrapper::Function_CreatureTargetted: { MWWorld::Ptr target; mActor.getClass().getCreatureStats(mActor).getAiSequence().getCombatTarget(target); if (target) { if (target.getClass().isNpc() && target.getClass().getNpcStats(target).isWerewolf()) return 2; if (target.getTypeName() == typeid(ESM::Creature).name()) return 1; } } return 0; default: throw std::runtime_error ("unknown integer select function"); } }
bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { float frametime = std::min(evt.timeSinceLastFrame, 0.2f); mEnvironment.setFrameDuration (frametime); // update input MWBase::Environment::get().getInputManager()->update(frametime, false); // sound if (mUseSound) MWBase::Environment::get().getSoundManager()->update(frametime); // GUI active? Most game processing will be paused, but scripts still run. bool guiActive = MWBase::Environment::get().getWindowManager()->isGuiMode(); // Main menu opened? Then scripts are also paused. bool paused = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state MWBase::Environment::get().getStateManager()->update (frametime); if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) { if (!paused) { // global scripts MWBase::Environment::get().getScriptManager()->getGlobalScripts().run(); // local scripts executeLocalScripts(); MWBase::Environment::get().getWorld()->markCellAsUnchanged(); } if (!guiActive) MWBase::Environment::get().getWorld()->advanceTime( frametime*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/3600); } // update actors if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { MWBase::Environment::get().getMechanicsManager()->update(frametime, guiActive); } if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_Running) { MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if(!guiActive && player.getClass().getCreatureStats(player).isDead()) MWBase::Environment::get().getStateManager()->endGame(); } // update world if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { MWBase::Environment::get().getWorld()->update(frametime, guiActive); } // update GUI MWBase::Environment::get().getWindowManager()->onFrame(frametime); if (MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { Ogre::RenderWindow* window = mOgre->getWindow(); unsigned int tri, batch; MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch); MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->update(); } } catch (const std::exception& e) { std::cerr << "Error in framelistener: " << e.what() << std::endl; } return true; }
void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) { TradeItemModel* playerItemModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getTradeModel(); const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>(); // were there any items traded at all? std::vector<ItemStack> playerBought = playerItemModel->getItemsBorrowedToUs(); std::vector<ItemStack> merchantBought = mTradeModel->getItemsBorrowedToUs(); if (playerBought.empty() && merchantBought.empty()) { // user notification MWBase::Environment::get().getWindowManager()-> messageBox("#{sBarterDialog11}"); return; } MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); // check if the player can afford this if (mCurrentBalance < 0 && playerGold < std::abs(mCurrentBalance)) { // user notification MWBase::Environment::get().getWindowManager()-> messageBox("#{sBarterDialog1}"); return; } // check if the merchant can afford this if (mCurrentBalance > 0 && getMerchantGold() < mCurrentBalance) { // user notification MWBase::Environment::get().getWindowManager()-> messageBox("#{sBarterDialog2}"); return; } // check if the player is attempting to sell back an item stolen from this actor for (std::vector<ItemStack>::iterator it = merchantBought.begin(); it != merchantBought.end(); ++it) { if (Misc::StringUtils::ciEqual(it->mBase.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) { std::string msg = gmst.find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase)); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief"); MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, it->mBase.getClass().getValue(it->mBase) * it->mCount); onCancelButtonClicked(mCancelButton); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); return; } } if(mCurrentBalance > mCurrentMerchantOffer) { //if npc is a creature: reject (no haggle) if (mPtr.getTypeName() != typeid(ESM::NPC).name()) { MWBase::Environment::get().getWindowManager()-> messageBox("#{sNotifyMessage9}"); return; } int a = abs(mCurrentMerchantOffer); int b = abs(mCurrentBalance); int d = 0; if (mCurrentBalance<0) d = int(100 * (a - b) / a); else d = int(100 * (b - a) / a); float clampedDisposition = std::max<int>(0,std::min<int>(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); const MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr); const MWMechanics::CreatureStats &playerStats = player.getClass().getCreatureStats(player); float a1 = std::min(player.getClass().getSkill(player, ESM::Skill::Mercantile), 100); float b1 = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c1 = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float d1 = std::min(mPtr.getClass().getSkill(mPtr, ESM::Skill::Mercantile), 100); float e1 = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f1 = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); float pcTerm = (clampedDisposition - 50 + a1 + b1 + c1) * playerStats.getFatigueTerm(); float npcTerm = (d1 + e1 + f1) * sellerStats.getFatigueTerm(); float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat(); if (mCurrentBalance<0) x += abs(int(pcTerm - npcTerm)); else x += abs(int(npcTerm - pcTerm)); int roll = std::rand()%100 + 1; if(roll > x) //trade refused { MWBase::Environment::get().getWindowManager()-> messageBox("#{sNotifyMessage9}"); int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); if (mPtr.getClass().isNpc()) MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterFailDisposition); return; } //skill use! player.getClass().skillUsageSucceeded(player, ESM::Skill::Mercantile, 0); } int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); if (mPtr.getClass().isNpc()) MWBase::Environment::get().getDialogueManager()->applyDispositionChange(iBarterSuccessDisposition); // make the item transfer mTradeModel->transferItems(); playerItemModel->transferItems(); // transfer the gold if (mCurrentBalance != 0) { addOrRemoveGold(mCurrentBalance, player); mPtr.getClass().getCreatureStats(mPtr).setGoldPool( mPtr.getClass().getCreatureStats(mPtr).getGoldPool() - mCurrentBalance ); } MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sBarterDialog5")->getString()); std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); }
void TradeWindow::buyFromNpc(const MWWorld::Ptr& item, int count, bool soldItem) { int diff = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, item.getClass().getValue(item) * count, !soldItem); mCurrentBalance -= diff; mCurrentMerchantOffer -= diff; updateLabels(); }
bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); switch (select.getFunction()) { case SelectWrapper::Function_False: return false; case SelectWrapper::Function_NotId: return !Misc::StringUtils::ciEqual(MWWorld::Class::get (mActor).getId (mActor), select.getName()); case SelectWrapper::Function_NotFaction: return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mFaction, select.getName()); case SelectWrapper::Function_NotClass: return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mClass, select.getName()); case SelectWrapper::Function_NotRace: return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, select.getName()); case SelectWrapper::Function_NotCell: return !Misc::StringUtils::ciEqual(mActor.getCell()->getCell()->mName, select.getName()); case SelectWrapper::Function_NotLocal: { std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor); if (scriptName.empty()) // This actor has no attached script, so there is no local variable return true; const ESM::Script *script = MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptName); std::string name = select.getName(); int i = 0; for (; i < static_cast<int> (script->mVarNames.size()); ++i) if (Misc::StringUtils::ciEqual(script->mVarNames[i], name)) break; if (i >= static_cast<int> (script->mVarNames.size())) return true; // script does not have a variable of this name return false; } case SelectWrapper::Function_SameGender: return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)== (mActor.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female); case SelectWrapper::Function_SameRace: return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, player.get<ESM::NPC>()->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 (ESM::MagicEffect::Corprus).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; return player.getClass().getNpcStats(player).getExpelled(faction); } case SelectWrapper::Function_PcVampire: return MWWorld::Class::get (player).getCreatureStats(player).getMagicEffects(). get(ESM::MagicEffect::Vampirism).mMagnitude > 0; case SelectWrapper::Function_TalkedToPc: return mTalkedToPlayer; case SelectWrapper::Function_Alarmed: return MWWorld::Class::get (mActor).getCreatureStats (mActor).isAlarmed(); case SelectWrapper::Function_Detected: return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor); 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 mActor.getClass().getCreatureStats (mActor).getCreatureTargetted(); case SelectWrapper::Function_Werewolf: return MWWorld::Class::get (mActor).getNpcStats (mActor).isWerewolf(); default: throw std::runtime_error ("unknown boolean select function"); } }
void MWState::StateManager::saveGame (const std::string& description, const Slot *slot) { try { ESM::SavedGame profile; MWBase::World& world = *MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world.getPlayerPtr(); profile.mContentFiles = world.getContentFiles(); profile.mPlayerName = player.getClass().getName (player); profile.mPlayerLevel = player.getClass().getNpcStats (player).getLevel(); std::string classId = player.get<ESM::NPC>()->mBase->mClass; if (world.getStore().get<ESM::Class>().isDynamic(classId)) profile.mPlayerClassName = world.getStore().get<ESM::Class>().find(classId)->mName; else profile.mPlayerClassId = classId; profile.mPlayerCell = world.getCellName(); profile.mInGameTime.mGameHour = world.getTimeStamp().getHour(); profile.mInGameTime.mDay = world.getDay(); profile.mInGameTime.mMonth = world.getMonth(); profile.mInGameTime.mYear = world.getYear(); profile.mTimePlayed = mTimePlayed; profile.mDescription = description; int screenshotW = 259*2, screenshotH = 133*2; // *2 to get some nice antialiasing Ogre::Image screenshot; world.screenshot(screenshot, screenshotW, screenshotH); Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); profile.mScreenshot.resize(encoded->size()); encoded->read(&profile.mScreenshot[0], encoded->size()); if (!slot) slot = getCurrentCharacter()->createSlot (profile); else slot = getCurrentCharacter()->updateSlot (slot, profile); boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); ESM::ESMWriter writer; const std::vector<std::string>& current = MWBase::Environment::get().getWorld()->getContentFiles(); for (std::vector<std::string>::const_iterator iter (current.begin()); iter!=current.end(); ++iter) writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0 writer.setFormat (ESM::Header::CurrentFormat); int recordCount = 1 // saved game header +MWBase::Environment::get().getJournal()->countSavedGameRecords() +MWBase::Environment::get().getWorld()->countSavedGameRecords() +MWBase::Environment::get().getScriptManager()->getGlobalScripts().countSavedGameRecords() +MWBase::Environment::get().getDialogueManager()->countSavedGameRecords() +MWBase::Environment::get().getWindowManager()->countSavedGameRecords(); writer.setRecordCount (recordCount); writer.save (stream); Loading::Listener& listener = *MWBase::Environment::get().getWindowManager()->getLoadingScreen(); listener.setProgressRange(recordCount); listener.setLabel("#{sNotifyMessage4}"); Loading::ScopedLoad load(&listener); writer.startRecord (ESM::REC_SAVE); slot->mProfile.save (writer); writer.endRecord (ESM::REC_SAVE); listener.increaseProgress(); MWBase::Environment::get().getJournal()->write (writer, listener); MWBase::Environment::get().getDialogueManager()->write (writer, listener); MWBase::Environment::get().getWorld()->write (writer, listener); MWBase::Environment::get().getScriptManager()->getGlobalScripts().write (writer, listener); MWBase::Environment::get().getWindowManager()->write(writer, listener); // Ensure we have written the number of records that was estimated if (writer.getRecordCount() != recordCount+1) // 1 extra for TES3 record std::cerr << "Warning: number of written savegame records does not match. Estimated: " << recordCount+1 << ", written: " << writer.getRecordCount() << std::endl; writer.close(); if (stream.fail()) throw std::runtime_error("Write operation failed"); Settings::Manager::setString ("character", "Saves", slot->mPath.parent_path().filename().string()); } catch (const std::exception& e) { std::stringstream error; error << "Failed to save game: " << e.what(); std::cerr << error.str() << std::endl; std::vector<std::string> buttons; buttons.push_back("#{sOk}"); MWBase::Environment::get().getWindowManager()->messageBox(error.str(), buttons); // If no file was written, clean up the slot if (slot && !boost::filesystem::exists(slot->mPath)) getCurrentCharacter()->deleteSlot(slot); } }
void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) { if (mEffects.size() <= 0) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu11}"); return; } if (mName->getCaption ().empty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mEnchanting.soulEmpty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage52}"); return; } if (mEnchanting.itemEmpty()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage11}"); return; } if (mEnchanting.getEnchantPoints() > mEnchanting.getMaxEnchantValue()) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}"); return; } mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); if (mEnchanting.getEnchantPrice() > playerGold) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } // check if the player is attempting to use a soulstone or item that was stolen from this actor if (mPtr != player) { for (int i=0; i<2; ++i) { MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem(); if (Misc::StringUtils::ciEqual(item.getCellRef().getOwner(), mPtr.getCellRef().getRefId())) { std::string msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage49")->getString(); if (msg.find("%s") != std::string::npos) msg.replace(msg.find("%s"), 2, item.getClass().getName(item)); MWBase::Environment::get().getWindowManager()->messageBox(msg); MWBase::Environment::get().getDialogueManager()->say(mPtr, "Thief"); MWBase::Environment::get().getMechanicsManager()->reportCrime(player, mPtr, MWBase::MechanicsManager::OT_Theft, item.getClass().getValue(item)); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); return; } } } int result = mEnchanting.create(); if(result==1) { MWBase::Environment::get().getSoundManager()->playSound("enchant success", 1.f, 1.f); MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu12}"); } else { MWBase::Environment::get().getSoundManager()->playSound("enchant fail", 1.f, 1.f); MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage34}"); } MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); }
bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration) { //Update various Timers mTimer += duration; //Update timer mStuckTimer += duration; //Update stuck timer ESM::Position pos = actor.getRefData().getPosition(); //position of the actor /// Stops the actor when it gets too close to a unloaded cell { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const ESM::Cell *cell = actor.getCell()->getCell(); Movement &movement = actor.getClass().getMovementSettings(actor); //Ensure pursuer doesn't leave loaded cells if(cell->mData.mX != player.getCell()->getCell()->mData.mX) { int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX); //check if actor is near the border of an inactive cell. If so, stop walking. if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) { movement.mPosition[1] = 0; return false; } } if(cell->mData.mY != player.getCell()->getCell()->mData.mY) { int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY); //check if actor is near the border of an inactive cell. If so, stop walking. if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) { movement.mPosition[1] = 0; return false; } } } //Start position ESM::Pathgrid::Point start = pos.pos; //*********************** /// Checks if you can't get to the end position at all, adds end position to end of path /// Rebuilds path every quarter of a second, in case the target has moved //*********************** if(mTimer > 0.25) { if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved mPrevDest = dest; } if(!mPathFinder.getPath().empty()) //Path has points in it { ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path if(distance(dest, lastPos) > 100) //End of the path is far from the destination mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go } mTimer = 0; } //************************ /// Checks if you aren't moving; attempts to unstick you //************************ if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished? return true; else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something { /// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason //if(mObstacleCheck.check(actor, duration)) { if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care // first check if we're walking into a door MWWorld::Ptr door = getNearbyDoor(actor); if(door != MWWorld::Ptr()) // NOTE: checks interior cells only { if(door.getCellRef().getTrap().empty() && mLastDoorChecked != door) { //Open the door if untrapped door.getClass().activate(door, actor).get()->execute(actor); mLastDoorChecked = door; } } else // probably walking into another NPC { // TODO: diagonal should have same animation as walk forward // but doesn't seem to do that? actor.getClass().getMovementSettings(actor).mPosition[0] = 1; actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } } else { //Not stuck, so reset things mStuckTimer = 0; mStuckPos = pos; mLastDoorChecked = MWWorld::Ptr(); //Resets it, in case he gets stuck behind the door again actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward } } else { actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time } zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); return false; }
void MerchantRepair::startRepair(const MWWorld::Ptr &actor) { mActor = actor; while (mList->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); int currentY = 0; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId); MWWorld::ContainerStore& store = player.getClass().getContainerStore(player); int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); iter!=store.end(); ++iter) { if (iter->getClass().hasItemHealth(*iter)) { int maxDurability = iter->getClass().getItemMaxHealth(*iter); int durability = iter->getClass().getItemHealth(*iter); if (maxDurability == durability) continue; int basePrice = iter->getClass().getValue(*iter); float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() .find("fRepairMult")->getFloat(); float p = std::max(1, basePrice); float r = std::max(1, static_cast<int>(maxDurability / p)); int x = ((maxDurability - durability) / r); x = (fRepairMult * x); int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); std::string name = iter->getClass().getName(*iter) + " - " + boost::lexical_cast<std::string>(price) + MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() .find("sgp")->getString(); MyGUI::Button* button = mList->createWidget<MyGUI::Button>("SandTextButton", 0, currentY, 0, 18, MyGUI::Align::Default ); currentY += 18; button->setEnabled(price<=playerGold); button->setUserString("Price", boost::lexical_cast<std::string>(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); button->setSize(button->getTextSize().width,18); button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); button->setUserString("ToolTipType", "ItemPtr"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); } } // Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden mList->setVisibleVScroll(false); mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); mList->setVisibleVScroll(true); mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast<std::string>(playerGold)); }
void ActionEquip::executeImp (const Ptr& actor) { MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = actor.getClass().getInventoryStore(actor); if (object.getClass().hasItemHealth(object) && object.getCellRef().getCharge() == 0) { if (actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox("#{sInventoryMessage1}"); return; } if (!mForce) { std::pair <int, std::string> result = object.getClass().canBeEquipped (object, actor); // display error message if the player tried to equip something if (!result.second.empty() && actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(result.second); switch(result.first) { case 0: return; default: break; } } // slots that this item can be equipped in std::pair<std::vector<int>, bool> slots_ = getTarget().getClass().getEquipmentSlots(getTarget()); if (slots_.first.empty()) return; // retrieve ContainerStoreIterator to the item MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { if (*it == object) { break; } } if (it == invStore.end()) { std::stringstream error; error << "ActionEquip can't find item " << object.getCellRef().getRefId(); throw std::runtime_error(error.str()); } // equip the item in the first free slot std::vector<int>::const_iterator slot=slots_.first.begin(); for (;slot!=slots_.first.end(); ++slot) { // if the item is equipped already, nothing to do if (invStore.getSlot(*slot) == it) return; if (invStore.getSlot(*slot) == invStore.end()) { // slot is not occupied invStore.equip(*slot, it, actor); break; } } // all slots are occupied -> cycle // move all slots one towards begin(), then equip the item in the slot that is now free if (slot == slots_.first.end()) { for (slot=slots_.first.begin();slot!=slots_.first.end(); ++slot) { invStore.unequipSlot(*slot, actor); if (slot+1 != slots_.first.end()) invStore.equip(*slot, invStore.getSlot(*(slot+1)), actor); else invStore.equip(*slot, it, actor); } } }
void CharacterCreation::spawnDialog(const char id) { switch (id) { case GM_Name: MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; mNameDialog = new TextInputDialog(); mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); mNameDialog->setTextInput(mPlayerName); mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); mNameDialog->setVisible(true); break; case GM_Race: MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; mRaceDialog = new RaceDialog(); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); mRaceDialog->setVisible(true); if (mCreationStage < CSE_NameChosen) mCreationStage = CSE_NameChosen; break; case GM_Class: MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; mClassChoiceDialog = new ClassChoiceDialog(); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_ClassPick: MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; mPickClassDialog = new PickClassDialog(); mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mPickClassDialog->setClassId(mPlayerClass.mName); mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); mPickClassDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_Birth: MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; mBirthSignDialog = new BirthDialog(); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); mBirthSignDialog->setVisible(true); if (mCreationStage < CSE_ClassChosen) mCreationStage = CSE_ClassChosen; break; case GM_ClassCreate: if (!mCreateClassDialog) { mCreateClassDialog = new CreateClassDialog(); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); } mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_ClassGenerate: mGenerateClassStep = 0; mGenerateClass = ""; mGenerateClassSpecializations[0] = 0; mGenerateClassSpecializations[1] = 0; mGenerateClassSpecializations[2] = 0; showClassQuestionDialog(); if (mCreationStage < CSE_RaceChosen) mCreationStage = CSE_RaceChosen; break; case GM_Review: MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; mReviewDialog = new ReviewDialog(); mReviewDialog->setPlayerName(mPlayerName); mReviewDialog->setRace(mPlayerRaceId); mReviewDialog->setClass(mPlayerClass); mReviewDialog->setBirthSign(mPlayerBirthSignId); { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); mReviewDialog->setHealth ( stats.getHealth() ); mReviewDialog->setMagicka( stats.getMagicka() ); mReviewDialog->setFatigue( stats.getFatigue() ); } { std::map<int, MWMechanics::AttributeValue > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); for (std::map<int, MWMechanics::AttributeValue >::iterator it = attributes.begin(); it != attributes.end(); ++it) { mReviewDialog->setAttribute(static_cast<ESM::Attribute::AttributeID> (it->first), it->second); } } { std::map<int, MWMechanics::SkillValue > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); for (std::map<int, MWMechanics::SkillValue >::iterator it = skills.begin(); it != skills.end(); ++it) { mReviewDialog->setSkillValue(static_cast<ESM::Skill::SkillEnum> (it->first), it->second); } mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); mReviewDialog->setVisible(true); if (mCreationStage < CSE_BirthSignChosen) mCreationStage = CSE_BirthSignChosen; break; } }
bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) const { switch (select.getFunction()) { case SelectWrapper::Function_Global: // internally all globals are float :( return select.selectCompare ( MWBase::Environment::get().getWorld()->getGlobalFloat (select.getName())); case SelectWrapper::Function_Local: { std::string scriptName = mActor.getClass().getScript (mActor); if (scriptName.empty()) return false; // no script std::string name = Misc::StringUtils::lowerCase (select.getName()); const Compiler::Locals& localDefs = MWBase::Environment::get().getScriptManager()->getLocals (scriptName); char type = localDefs.getType (name); if (type==' ') return false; // script does not have a variable of this name. int index = localDefs.getIndex (name); if (index < 0) return false; // shouldn't happen, we checked that variable has a type above, so must exist const MWScript::Locals& locals = mActor.getRefData().getLocals(); switch (type) { case 's': return select.selectCompare (static_cast<int> (locals.mShorts[index])); case 'l': return select.selectCompare (locals.mLongs[index]); case 'f': return select.selectCompare (locals.mFloats[index]); } throw std::logic_error ("unknown local variable type in dialogue filter"); } case SelectWrapper::Function_PcHealthPercent: { MWWorld::Ptr player = MWMechanics::getPlayer(); float ratio = player.getClass().getCreatureStats (player).getHealth().getCurrent() / player.getClass().getCreatureStats (player).getHealth().getModified(); return select.selectCompare (static_cast<int>(ratio*100)); } case SelectWrapper::Function_PcDynamicStat: { MWWorld::Ptr player = MWMechanics::getPlayer(); float value = player.getClass().getCreatureStats (player). getDynamic (select.getArgument()).getCurrent(); return select.selectCompare (value); } case SelectWrapper::Function_HealthPercent: { float ratio = mActor.getClass().getCreatureStats (mActor).getHealth().getCurrent() / mActor.getClass().getCreatureStats (mActor).getHealth().getModified(); return select.selectCompare (static_cast<int>(ratio*100)); } default: throw std::runtime_error ("unknown numeric select function"); } }
void RenderingManager::addObject (const MWWorld::Ptr& ptr){ const MWWorld::Class& class_ = ptr.getClass(); class_.insertObjectRendering(ptr, *this); }
bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) const { MWWorld::Ptr player = MWMechanics::getPlayer(); switch (select.getFunction()) { case SelectWrapper::Function_False: return false; case SelectWrapper::Function_NotId: return !Misc::StringUtils::ciEqual(mActor.getCellRef().getRefId(), select.getName()); case SelectWrapper::Function_NotFaction: return !Misc::StringUtils::ciEqual(mActor.getClass().getPrimaryFaction(mActor), select.getName()); case SelectWrapper::Function_NotClass: return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mClass, select.getName()); case SelectWrapper::Function_NotRace: return !Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, select.getName()); case SelectWrapper::Function_NotCell: return !Misc::StringUtils::ciEqual(MWBase::Environment::get().getWorld()->getCellName(mActor.getCell()) , select.getName()); case SelectWrapper::Function_NotLocal: { std::string scriptName = mActor.getClass().getScript (mActor); if (scriptName.empty()) // This actor has no attached script, so there is no local variable return true; const Compiler::Locals& localDefs = MWBase::Environment::get().getScriptManager()->getLocals (scriptName); return localDefs.getIndex (Misc::StringUtils::lowerCase (select.getName()))==-1; } case SelectWrapper::Function_SameGender: return (player.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female)== (mActor.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Female); case SelectWrapper::Function_SameRace: return Misc::StringUtils::ciEqual(mActor.get<ESM::NPC>()->mBase->mRace, player.get<ESM::NPC>()->mBase->mRace); case SelectWrapper::Function_SameFaction: return player.getClass().getNpcStats (player).isInFaction(mActor.getClass().getPrimaryFaction(mActor)); case SelectWrapper::Function_PcCommonDisease: return player.getClass().getCreatureStats (player).hasCommonDisease(); case SelectWrapper::Function_PcBlightDisease: return player.getClass().getCreatureStats (player).hasBlightDisease(); case SelectWrapper::Function_PcCorprus: return player.getClass().getCreatureStats (player). getMagicEffects().get (ESM::MagicEffect::Corprus).getMagnitude()!=0; case SelectWrapper::Function_PcExpelled: { std::string faction = mActor.getClass().getPrimaryFaction(mActor); if (faction.empty()) return false; return player.getClass().getNpcStats(player).getExpelled(faction); } case SelectWrapper::Function_PcVampire: return player.getClass().getCreatureStats(player).getMagicEffects(). get(ESM::MagicEffect::Vampirism).getMagnitude() > 0; case SelectWrapper::Function_TalkedToPc: return mTalkedToPlayer; case SelectWrapper::Function_Alarmed: return mActor.getClass().getCreatureStats (mActor).isAlarmed(); case SelectWrapper::Function_Detected: return MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, mActor); case SelectWrapper::Function_Attacked: return mActor.getClass().getCreatureStats (mActor).getAttacked(); case SelectWrapper::Function_ShouldAttack: return MWBase::Environment::get().getMechanicsManager()->isAggressive(mActor, MWMechanics::getPlayer()); case SelectWrapper::Function_Werewolf: return mActor.getClass().getNpcStats (mActor).isWerewolf(); default: throw std::runtime_error ("unknown boolean select function"); } }
void RenderingManager::update (float duration, bool paused) { if (MWBase::Environment::get().getStateManager()->getState()== MWBase::StateManager::State_NoGame) return; MWBase::World *world = MWBase::Environment::get().getWorld(); MWWorld::Ptr player = world->getPlayerPtr(); int blind = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude(); MWBase::Environment::get().getWindowManager()->setScreenFactor(std::max(0.f, 1.f-(blind / 100.f))); setAmbientMode(); // player position MWWorld::RefData &data = player.getRefData(); Ogre::Vector3 playerPos(data.getPosition().pos); mCamera->setCameraDistance(); if(!mCamera->isFirstPerson()) { Ogre::Vector3 orig, dest; mCamera->getPosition(orig, dest); btVector3 btOrig(orig.x, orig.y, orig.z); btVector3 btDest(dest.x, dest.y, dest.z); std::pair<bool,float> test = mPhysicsEngine->sphereCast(mRendering.getCamera()->getNearClipDistance()*2.5, btOrig, btDest); if(test.first) mCamera->setCameraDistance(test.second * orig.distance(dest), false, false); } // Sink the camera while sneaking bool isSneaking = player.getClass().getCreatureStats(player).getStance(MWMechanics::CreatureStats::Stance_Sneak); 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(!paused && isSneaking && !(isSwimming || isInAir)) mCamera->setSneakOffset(i1stPersonSneakDelta); mOcclusionQuery->update(duration); mRendering.update(duration); Ogre::ControllerManager::getSingleton().setTimeFactor(paused ? 0.f : 1.f); Ogre::Vector3 cam = mRendering.getCamera()->getRealPosition(); applyFog(world->isUnderwater(player.getCell(), cam)); mCamera->update(duration, paused); Ogre::SceneNode *node = data.getBaseNode(); Ogre::Quaternion orient = node->_getDerivedOrientation(); mLocalMap->updatePlayer(playerPos, orient); if(paused) return; mEffectManager->update(duration, mRendering.getCamera()); mActors->update (mRendering.getCamera()); mPlayerAnimation->preRender(mRendering.getCamera()); mObjects->update (duration, mRendering.getCamera()); mSkyManager->update(duration); mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); mWater->updateUnderwater(world->isUnderwater(player.getCell(), cam)); mWater->update(duration, playerPos); }
bool MWMechanics::AiPackage::isTargetMagicallyHidden(const MWWorld::Ptr& target) { const MagicEffects& magicEffects(target.getClass().getCreatureStats(target).getMagicEffects()); return (magicEffects.get(ESM::MagicEffect::Invisibility).getMagnitude() > 0) || (magicEffects.get(ESM::MagicEffect::Chameleon).getMagnitude() > 75); }
bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { MWWorld::Ptr target = getTarget(); if (target.isEmpty() || !target.getRefData().getCount() || !target.getRefData().isEnabled() // Really we should be checking whether the target is currently registered // with the MechanicsManager ) return false; // Target is not here right now, wait for it to return actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); AiFollowStorage& storage = state.get<AiFollowStorage>(); // AiFollow requires the target to be in range and within sight for the initial activation if (!mActive) { storage.mTimer -= duration; if (storage.mTimer < 0) { if ((actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length2() < 500*500 && MWBase::Environment::get().getWorld()->getLOS(actor, target)) mActive = true; storage.mTimer = 0.5f; } } if (!mActive) return false; ESM::Position pos = actor.getRefData().getPosition(); //position of the actor // The distances below are approximations based on observations of the original engine. // If only one actor is following the target, it uses 186. // If there are multiple actors following the same target, they form a group with each group member at 313 + (130 * i) distance to the target. short followDistance = 186; std::list<int> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowingIndices(target); if (followers.size() >= 2) { followDistance = 313; short i = 0; followers.sort(); for (std::list<int>::iterator it = followers.begin(); it != followers.end(); ++it) { if (*it == mFollowIndex) followDistance += 130 * i; ++i; } } if (!mAlwaysFollow) //Update if you only follow for a bit { //Check if we've run out of time if (mDuration > 0) { mRemainingDuration -= ((duration*MWBase::Environment::get().getWorld()->getTimeScaleFactor()) / 3600); if (mRemainingDuration <= 0) { mRemainingDuration = mDuration; return true; } } if ((pos.pos[0]-mX)*(pos.pos[0]-mX) + (pos.pos[1]-mY)*(pos.pos[1]-mY) + (pos.pos[2]-mZ)*(pos.pos[2]-mZ) < followDistance*followDistance) //Close-ish to final position { if (actor.getCell()->isExterior()) //Outside? { if (mCellId == "") //No cell to travel to return true; } else { if (mCellId == actor.getCell()->getCell()->mName) //Cell to travel to return true; } } } //Set the target destination from the actor ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; if (!storage.mMoving) { const short threshold = 10; // to avoid constant switching between moving/stopping followDistance += threshold; } storage.mMoving = !pathTo(actor, dest, duration, followDistance); // Go to the destination if (storage.mMoving) { //Check if you're far away float dist = distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]); if (dist > 450) actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run else if (dist < 325) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshold actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk } return false; }
float rateEffect(const ESM::ENAMstruct &effect, const MWWorld::Ptr &actor, const MWWorld::Ptr &target) { // NOTE: target may be empty float rating = 1; switch (effect.mEffectID) { case ESM::MagicEffect::Soultrap: case ESM::MagicEffect::AlmsiviIntervention: case ESM::MagicEffect::DivineIntervention: case ESM::MagicEffect::CalmHumanoid: case ESM::MagicEffect::CalmCreature: case ESM::MagicEffect::FrenzyHumanoid: case ESM::MagicEffect::FrenzyCreature: case ESM::MagicEffect::DemoralizeHumanoid: case ESM::MagicEffect::DemoralizeCreature: case ESM::MagicEffect::RallyHumanoid: case ESM::MagicEffect::RallyCreature: case ESM::MagicEffect::Charm: case ESM::MagicEffect::DetectAnimal: case ESM::MagicEffect::DetectEnchantment: case ESM::MagicEffect::DetectKey: case ESM::MagicEffect::Telekinesis: case ESM::MagicEffect::Mark: case ESM::MagicEffect::Recall: case ESM::MagicEffect::Jump: case ESM::MagicEffect::WaterBreathing: case ESM::MagicEffect::SwiftSwim: case ESM::MagicEffect::WaterWalking: case ESM::MagicEffect::SlowFall: case ESM::MagicEffect::Light: case ESM::MagicEffect::Lock: case ESM::MagicEffect::Open: case ESM::MagicEffect::TurnUndead: case ESM::MagicEffect::WeaknessToCommonDisease: case ESM::MagicEffect::WeaknessToBlightDisease: case ESM::MagicEffect::WeaknessToCorprusDisease: case ESM::MagicEffect::CureCommonDisease: case ESM::MagicEffect::CureBlightDisease: case ESM::MagicEffect::CureCorprusDisease: case ESM::MagicEffect::Invisibility: return 0.f; case ESM::MagicEffect::Feather: if (actor.getClass().getEncumbrance(actor) - actor.getClass().getCapacity(actor) >= 0) return 100.f; else return 0.f; case ESM::MagicEffect::Levitate: return 0.f; // AI isn't designed to take advantage of this, and could be perceived as unfair anyway case ESM::MagicEffect::BoundBoots: case ESM::MagicEffect::BoundHelm: if (actor.getClass().isNpc()) { // Beast races can't wear helmets or boots std::string raceid = actor.get<ESM::NPC>()->mBase->mRace; const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(raceid); if (race->mData.mFlags & ESM::Race::Beast) return 0.f; } // Intended fall-through // Creatures can not wear armor case ESM::MagicEffect::BoundCuirass: case ESM::MagicEffect::BoundGloves: if (!actor.getClass().isNpc()) return 0.f; break; case ESM::MagicEffect::RestoreHealth: case ESM::MagicEffect::RestoreMagicka: case ESM::MagicEffect::RestoreFatigue: if (effect.mRange == ESM::RT_Self) { int priority = 1; if (effect.mEffectID == ESM::MagicEffect::RestoreHealth) priority = 10; const DynamicStat<float>& current = actor.getClass().getCreatureStats(actor). getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); float toHeal = (effect.mMagnMin + effect.mMagnMax)/2.f * effect.mDuration; // Effect doesn't heal more than we need, *or* we are below 1/2 health if (current.getModified() - current.getCurrent() > toHeal || current.getCurrent() < current.getModified()*0.5) return 10000.f * priority; else return -10000.f * priority; // Save for later } break; // Prefer Cure effects over Dispel, because Dispel also removes positive effects case ESM::MagicEffect::Dispel: return 1000.f * numEffectsToCure(actor); case ESM::MagicEffect::CureParalyzation: return 1001.f * numEffectsToCure(actor, ESM::MagicEffect::Paralyze); case ESM::MagicEffect::CurePoison: return 1001.f * numEffectsToCure(actor, ESM::MagicEffect::Poison); case ESM::MagicEffect::DisintegrateArmor: // TODO: check if actor is wearing armor case ESM::MagicEffect::DisintegrateWeapon: // TODO: check if actor is wearing weapon break; case ESM::MagicEffect::DamageAttribute: case ESM::MagicEffect::DrainAttribute: if (!target.isEmpty() && target.getClass().getCreatureStats(target).getAttribute(effect.mAttribute).getModified() <= 0) return 0.f; { if (effect.mAttribute >= 0 && effect.mAttribute < ESM::Attribute::Length) { const float attributePriorities[ESM::Attribute::Length] = { 1.f, // Strength 0.5, // Intelligence 0.6, // Willpower 0.7, // Agility 0.5, // Speed 0.8, // Endurance 0.7, // Personality 0.3 // Luck }; rating *= attributePriorities[effect.mAttribute]; } } break; case ESM::MagicEffect::DamageSkill: case ESM::MagicEffect::DrainSkill: if (target.isEmpty() || !target.getClass().isNpc()) return 0.f; if (target.getClass().getNpcStats(target).getSkill(effect.mSkill).getModified() <= 0) return 0.f; break; default: break; } // TODO: for non-cumulative effects (e.g. paralyze), check if the target is already suffering from them // TODO: could take into account target's resistance/weakness against the effect const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effect.mEffectID); rating *= magicEffect->mData.mBaseCost; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) rating *= (effect.mMagnMin + effect.mMagnMax)/2.f; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) rating *= effect.mDuration; if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) rating *= -1.f; // Currently treating all "on target" or "on touch" effects to target the enemy actor. // Combat AI is egoistic, so doesn't consider applying positive effects to friendly actors. if (effect.mRange != ESM::RT_Self) rating *= -1.f; return rating; }
virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); ptr.getClass().getCreatureStats(ptr).setMovementFlag (mFlag, false); }
void ActionPotion::prepare(const MWWorld::Ptr &actor) { actor.getClass().apply(actor, mPotion.getCellRef().getRefId(), actor); actor.getClass().getContainerStore(actor).remove(mPotion, 1, actor); }
std::shared_ptr<MWWorld::Action> Door::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { MWWorld::LiveCellRef<ESM::Door> *ref = ptr.get<ESM::Door>(); const std::string &openSound = ref->mBase->mOpenSound; const std::string &closeSound = ref->mBase->mCloseSound; const std::string lockedSound = "LockedDoor"; const std::string trapActivationSound = "Disarm Trap Fail"; MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor); bool isLocked = ptr.getCellRef().getLockLevel() > 0; bool isTrapped = !ptr.getCellRef().getTrap().empty(); bool hasKey = false; std::string keyName; // FIXME: If NPC activate teleporting door, it can lead to crash due to iterator invalidation in the Actors update. // Make such activation a no-op for now, like how it is in the vanilla game. if (actor != MWMechanics::getPlayer() && ptr.getCellRef().getTeleport()) { std::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction(std::string(), ptr)); action->setSound(lockedSound); return action; } // make door glow if player activates it with telekinesis if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis"); const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(index); animation->addSpellCastGlow(effect, 1); // 1 second glow to match the time taken for a door opening or closing } const std::string keyId = ptr.getCellRef().getKey(); if (!keyId.empty()) { MWWorld::Ptr keyPtr = invStore.search(keyId); if (!keyPtr.isEmpty()) { hasKey = true; keyName = keyPtr.getClass().getName(keyPtr); } } if ((isLocked || isTrapped) && hasKey) { if(actor == MWMechanics::getPlayer()) MWBase::Environment::get().getWindowManager()->messageBox(keyName + " #{sKeyUsed}"); if(isLocked) unlock(ptr); //Call the function here. because that makes sense. // using a key disarms the trap if(isTrapped) { ptr.getCellRef().setTrap(""); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Disarm Trap", 1.0f, 1.0f); isTrapped = false; } } if (!isLocked || hasKey) { if(isTrapped) { // Trap activation std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTrap(ptr.getCellRef().getTrap(), ptr)); action->setSound(trapActivationSound); return action; } if (ptr.getCellRef().getTeleport()) { if (actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getDistanceToFacedObject() > MWBase::Environment::get().getWorld()->getMaxActivationDistance()) { // player activated teleport door with telekinesis std::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction); return action; } else { std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionTeleport (ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true)); action->setSound(openSound); return action; } } else { // animated door std::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr)); int doorstate = getDoorState(ptr); bool opening = true; float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2]; if (doorstate == 1) opening = false; if (doorstate == 0 && doorRot != 0) opening = false; if (opening) { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, closeSound, 0.5f); // Doors rotate at 90 degrees per second, so start the sound at // where it would be at the current rotation. float offset = doorRot/(osg::PI * 0.5f); action->setSoundOffset(offset); action->setSound(openSound); } else { MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f); float offset = 1.0f - doorRot/(osg::PI * 0.5f); action->setSoundOffset(std::max(offset, 0.0f)); action->setSound(closeSound); } return action; } } else { // locked, and we can't open. std::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction(std::string(), ptr)); action->setSound(lockedSound); return action; } }
float rateWeapon (const MWWorld::Ptr &item, const MWWorld::Ptr& actor, const MWWorld::Ptr& target, int type, float arrowRating, float boltRating) { if (item.getTypeName() != typeid(ESM::Weapon).name()) return 0.f; const ESM::Weapon* weapon = item.get<ESM::Weapon>()->mBase; if (type != -1 && weapon->mData.mType != type) return 0.f; float rating=0.f; if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) { rating = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f; } else { for (int i=0; i<2; ++i) { rating += weapon->mData.mSlash[i]; rating += weapon->mData.mThrust[i]; rating += weapon->mData.mChop[i]; } rating /= 6.f; } if (item.getClass().hasItemHealth(item)) { if (item.getClass().getItemHealth(item) == 0) return 0.f; rating *= item.getClass().getItemHealth(item) / float(item.getClass().getItemMaxHealth(item)); } if (weapon->mData.mType == ESM::Weapon::MarksmanBow) { if (arrowRating <= 0.f) rating = 0.f; else rating += arrowRating; } else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow) { if (boltRating <= 0.f) rating = 0.f; else rating += boltRating; } if (!weapon->mEnchant.empty()) { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(weapon->mEnchant); if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes && (item.getCellRef().getEnchantmentCharge() == -1 || item.getCellRef().getEnchantmentCharge() >= enchantment->mData.mCost)) rating += rateEffects(enchantment->mEffects, actor, target); } int skill = item.getClass().getEquipmentSkill(item); if (skill != -1) rating *= actor.getClass().getSkill(actor, skill) / 100.f; return rating; }
void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { TSlots slots_; initSlots (slots_); // Disable model update during auto-equip mUpdatesEnabled = false; for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { Ptr test = *iter; // Don't autoEquip lights. Handled in Actors::updateEquippedLight based on environment light. if (test.getTypeName() == typeid(ESM::Light).name()) { continue; } // Only autoEquip if we are the original owner of the item. // This stops merchants from auto equipping anything you sell to them. // ...unless this is a companion, he should always equip items given to him. if (!Misc::StringUtils::ciEqual(test.getCellRef().getOwner(), actor.getCellRef().getRefId()) && (actor.getClass().getScript(actor).empty() || !actor.getRefData().getLocals().getIntVar(actor.getClass().getScript(actor), "companion")) && !actor.getClass().getCreatureStats(actor).isDead() // Corpses can be dressed up by the player as desired ) { continue; } int testSkill = test.getClass().getEquipmentSkill (test); std::pair<std::vector<int>, bool> itemsSlots = iter->getClass().getEquipmentSlots (*iter); for (std::vector<int>::const_iterator iter2 (itemsSlots.first.begin()); iter2!=itemsSlots.first.end(); ++iter2) { if (*iter2 == Slot_CarriedRight) // Items in right hand are situational use, so don't equip them. // Equipping weapons is handled by AiCombat. Anything else (lockpicks, probes) can't be used by NPCs anyway (yet) continue; if (iter.getType() == MWWorld::ContainerStore::Type_Weapon) continue; if (slots_.at (*iter2)!=end()) { Ptr old = *slots_.at (*iter2); // check skill int oldSkill = old.getClass().getEquipmentSkill (old); bool use = false; if (testSkill!=-1 && oldSkill==-1) use = true; else if (testSkill!=-1 && oldSkill!=-1 && testSkill!=oldSkill) { if (actor.getClass().getSkill(actor, oldSkill) > actor.getClass().getSkill (actor, testSkill)) continue; // rejected, because old item better matched the NPC's skills. if (actor.getClass().getSkill(actor, oldSkill) < actor.getClass().getSkill (actor, testSkill)) use = true; } if (!use) { // check value if (old.getClass().getValue (old)>= test.getClass().getValue (test)) { continue; } } } switch(test.getClass().canBeEquipped (test, actor).first) { case 0: continue; default: break; } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { // unstack item pointed to by iterator if required if (iter->getRefData().getCount() > 1) { unstack(*iter, actor); } } slots_[*iter2] = iter; break; } } bool changed = false; for (std::size_t i=0; i<slots_.size(); ++i) { if (slots_[i] != mSlots[i]) { changed = true; break; } } mUpdatesEnabled = true; if (changed) { mSlots.swap (slots_); fireEquipmentChangedEvent(actor); updateMagicEffects(actor); flagAsModified(); } }
bool OMW::Engine::frame(float frametime) { try { mStartTick = mViewer->getStartTick(); mEnvironment.setFrameDuration(frametime); // update input mEnvironment.getInputManager()->update(frametime, false); // When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) if (!mEnvironment.getInputManager()->isWindowVisible()) return false; // sound if (mUseSound) mEnvironment.getSoundManager()->update(frametime); // Main menu opened? Then scripts are also paused. bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu); // update game state mEnvironment.getStateManager()->update (frametime); bool guiActive = mEnvironment.getWindowManager()->isGuiMode(); osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick(); if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { if (!paused) { if (mEnvironment.getWorld()->getScriptsEnabled()) { // local scripts executeLocalScripts(); // global scripts mEnvironment.getScriptManager()->getGlobalScripts().run(); } mEnvironment.getWorld()->markCellAsUnchanged(); } if (!guiActive) { double hours = (frametime * mEnvironment.getWorld()->getTimeScaleFactor()) / 3600.0; mEnvironment.getWorld()->advanceTime(hours, true); } } osg::Timer_t afterScriptTick = osg::Timer::instance()->tick(); // update actors osg::Timer_t beforeMechanicsTick = osg::Timer::instance()->tick(); if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { mEnvironment.getMechanicsManager()->update(frametime, guiActive); } osg::Timer_t afterMechanicsTick = osg::Timer::instance()->tick(); if (mEnvironment.getStateManager()->getState()== MWBase::StateManager::State_Running) { MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr(); if(!guiActive && player.getClass().getCreatureStats(player).isDead()) mEnvironment.getStateManager()->endGame(); } // update world osg::Timer_t beforePhysicsTick = osg::Timer::instance()->tick();; if (mEnvironment.getStateManager()->getState()!= MWBase::StateManager::State_NoGame) { mEnvironment.getWorld()->update(frametime, guiActive); } osg::Timer_t afterPhysicsTick = osg::Timer::instance()->tick(); // update GUI mEnvironment.getWindowManager()->onFrame(frametime); unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); osg::Stats* stats = mViewer->getViewerStats(); stats->setAttribute(frameNumber, "script_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeScriptTick)); stats->setAttribute(frameNumber, "script_time_taken", osg::Timer::instance()->delta_s(beforeScriptTick, afterScriptTick)); stats->setAttribute(frameNumber, "script_time_end", osg::Timer::instance()->delta_s(mStartTick, afterScriptTick)); stats->setAttribute(frameNumber, "mechanics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforeMechanicsTick)); stats->setAttribute(frameNumber, "mechanics_time_taken", osg::Timer::instance()->delta_s(beforeMechanicsTick, afterMechanicsTick)); stats->setAttribute(frameNumber, "mechanics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterMechanicsTick)); stats->setAttribute(frameNumber, "physics_time_begin", osg::Timer::instance()->delta_s(mStartTick, beforePhysicsTick)); stats->setAttribute(frameNumber, "physics_time_taken", osg::Timer::instance()->delta_s(beforePhysicsTick, afterPhysicsTick)); stats->setAttribute(frameNumber, "physics_time_end", osg::Timer::instance()->delta_s(mStartTick, afterPhysicsTick)); if (stats->collectStats("resource")) { mResourceSystem->reportStats(frameNumber, stats); stats->setAttribute(frameNumber, "WorkQueue", mWorkQueue->getNumItems()); stats->setAttribute(frameNumber, "WorkThread", mWorkQueue->getNumActiveThreads()); } } catch (const std::exception& e) { Log(Debug::Error) << "Error in frame: " << e.what(); } return true; }
bool AiWander::execute (const MWWorld::Ptr& actor,float duration) { if (actor.getClass().isNpc()) actor.getClass().getNpcStats(actor).setDrawState(DrawState_Nothing); MWBase::World *world = MWBase::Environment::get().getWorld(); if(mDuration) { // End package if duration is complete or mid-night hits: MWWorld::TimeStamp currentTime = world->getTimeStamp(); if(currentTime.getHour() >= mStartTime.getHour() + mDuration) { if(!mRepeat) { stopWalking(actor); return true; } else mStartTime = currentTime; } else if(int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay()) { if(!mRepeat) { stopWalking(actor); return true; } else mStartTime = currentTime; } } ESM::Position pos = actor.getRefData().getPosition(); if(!mStoredAvailableNodes) { mStoredAvailableNodes = true; mPathgrid = world->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell); mCellX = actor.getCell()->mCell->mData.mX; mCellY = actor.getCell()->mCell->mData.mY; if(!mPathgrid) mDistance = 0; else if(mPathgrid->mPoints.empty()) mDistance = 0; if(mDistance) { mXCell = 0; mYCell = 0; if(actor.getCell()->mCell->isExterior()) { mXCell = mCellX * ESM::Land::REAL_SIZE; mYCell = mCellY * ESM::Land::REAL_SIZE; } Ogre::Vector3 npcPos(actor.getRefData().getPosition().pos); npcPos[0] = npcPos[0] - mXCell; npcPos[1] = npcPos[1] - mYCell; for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++) { Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, mPathgrid->mPoints[counter].mZ); if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance) mAllowedNodes.push_back(mPathgrid->mPoints[counter]); } if(!mAllowedNodes.empty()) { Ogre::Vector3 firstNodePos(mAllowedNodes[0].mX, mAllowedNodes[0].mY, mAllowedNodes[0].mZ); float closestNode = npcPos.squaredDistance(firstNodePos); unsigned int index = 0; for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++) { Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, mAllowedNodes[counterThree].mZ); float tempDist = npcPos.squaredDistance(nodePos); if(tempDist < closestNode) index = counterThree; } mCurrentNode = mAllowedNodes[index]; mAllowedNodes.erase(mAllowedNodes.begin() + index); } } } if(mAllowedNodes.empty()) mDistance = 0; // Don't try to move if you are in a new cell (ie: positioncell command called) but still play idles. if(mDistance && (mCellX != actor.getCell()->mCell->mData.mX || mCellY != actor.getCell()->mCell->mData.mY)) mDistance = 0; if(mChooseAction) { mPlayedIdle = 0; unsigned short idleRoll = 0; for(unsigned int counter = 0; counter < mIdle.size(); counter++) { unsigned short idleChance = mIdleChanceMultiplier * mIdle[counter]; unsigned short randSelect = (int)(rand() / ((double)RAND_MAX + 1) * int(100 / mIdleChanceMultiplier)); if(randSelect < idleChance && randSelect > idleRoll) { mPlayedIdle = counter+2; idleRoll = randSelect; } } if(!mPlayedIdle && mDistance) { mChooseAction = false; mMoveNow = true; } else { // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: MWWorld::TimeStamp currentTime = world->getTimeStamp(); mStartTime = currentTime; playIdle(actor, mPlayedIdle); mChooseAction = false; mIdleNow = true; } } if(mIdleNow) { if(!checkIdle(actor, mPlayedIdle)) { mPlayedIdle = 0; mIdleNow = false; mChooseAction = true; } } if(mMoveNow && mDistance) { if(!mPathFinder.isPathConstructed()) { assert(mAllowedNodes.size()); unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); ESM::Pathgrid::Point dest; dest.mX = destNodePos[0] + mXCell; dest.mY = destNodePos[1] + mYCell; dest.mZ = destNodePos[2]; ESM::Pathgrid::Point start; start.mX = pos.pos[0]; start.mY = pos.pos[1]; start.mZ = pos.pos[2]; mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false); if(mPathFinder.isPathConstructed()) { // Remove this node as an option and add back the previously used node (stops NPC from picking the same node): ESM::Pathgrid::Point temp = mAllowedNodes[randNode]; mAllowedNodes.erase(mAllowedNodes.begin() + randNode); mAllowedNodes.push_back(mCurrentNode); mCurrentNode = temp; mMoveNow = false; mWalking = true; } // Choose a different node and delete this one from possible nodes because it is uncreachable: else mAllowedNodes.erase(mAllowedNodes.begin() + randNode); } } if(mWalking) { float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); // TODO: use movement settings instead of rotating directly world->rotateObject(actor, 0, 0, zAngle, false); MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) { stopWalking(actor); mMoveNow = false; mWalking = false; mChooseAction = true; } } return false; }