mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-29 03:26:38 +00:00 
			
		
		
		
	Move levelled list code out of ContainerStore
This commit is contained in:
		
							parent
							
								
									6aa56354c0
								
							
						
					
					
						commit
						90b92a8f41
					
				
					 4 changed files with 98 additions and 63 deletions
				
			
		|  | @ -74,7 +74,7 @@ add_openmw_dir (mwmechanics | ||||||
|     mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects |     mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects | ||||||
|     drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow |     drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow | ||||||
|     aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting |     aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting | ||||||
|     disease pickpocket |     disease pickpocket levelledlist | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| add_openmw_dir (mwbase | add_openmw_dir (mwbase | ||||||
|  |  | ||||||
							
								
								
									
										78
									
								
								apps/openmw/mwmechanics/levelledlist.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								apps/openmw/mwmechanics/levelledlist.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | ||||||
|  | #ifndef OPENMW_MECHANICS_LEVELLEDLIST_H | ||||||
|  | #define OPENMW_MECHANICS_LEVELLEDLIST_H | ||||||
|  | 
 | ||||||
|  | #include "../mwworld/ptr.hpp" | ||||||
|  | #include "../mwworld/manualref.hpp" | ||||||
|  | #include "../mwworld/class.hpp" | ||||||
|  | #include "../mwbase/world.hpp" | ||||||
|  | #include "../mwbase/environment.hpp" | ||||||
|  | 
 | ||||||
|  | namespace MWMechanics | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  |     /// @return ID of resulting item, or empty if none
 | ||||||
|  |     std::string getLevelledItem (const ESM::LeveledListBase* levItem, unsigned char failChance=0) | ||||||
|  |     { | ||||||
|  |         const std::vector<ESM::LeveledListBase::LevelItem>& items = levItem->mList; | ||||||
|  | 
 | ||||||
|  |         const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||||
|  |         int playerLevel = player.getClass().getCreatureStats(player).getLevel(); | ||||||
|  | 
 | ||||||
|  |         failChance += levItem->mChanceNone; | ||||||
|  | 
 | ||||||
|  |         float random = static_cast<float> (std::rand()) / RAND_MAX; | ||||||
|  |         if (random < failChance/100.f) | ||||||
|  |             return std::string(); | ||||||
|  | 
 | ||||||
|  |         std::vector<std::string> candidates; | ||||||
|  |         int highestLevel = 0; | ||||||
|  |         for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it) | ||||||
|  |         { | ||||||
|  |             if (it->mLevel > highestLevel) | ||||||
|  |                 highestLevel = it->mLevel; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         std::pair<int, std::string> highest = std::make_pair(-1, ""); | ||||||
|  |         for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it) | ||||||
|  |         { | ||||||
|  |             if (playerLevel >= it->mLevel | ||||||
|  |                     && (levItem->mFlags & ESM::LeveledListBase::AllLevels || it->mLevel == highestLevel)) | ||||||
|  |             { | ||||||
|  |                 candidates.push_back(it->mId); | ||||||
|  |                 if (it->mLevel >= highest.first) | ||||||
|  |                     highest = std::make_pair(it->mLevel, it->mId); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|  |         if (candidates.empty()) | ||||||
|  |             return std::string(); | ||||||
|  |         std::string item = candidates[std::rand()%candidates.size()]; | ||||||
|  | 
 | ||||||
|  |         // Is this another levelled item or a real item?
 | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, 1); | ||||||
|  |             if (ref.getPtr().getTypeName() != typeid(ESM::ItemLevList).name() | ||||||
|  |                     && ref.getPtr().getTypeName() != typeid(ESM::CreatureLevList).name()) | ||||||
|  |             { | ||||||
|  |                 return item; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 if (ref.getPtr().getTypeName() == typeid(ESM::ItemLevList).name()) | ||||||
|  |                     return getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase, failChance); | ||||||
|  |                 else | ||||||
|  |                     return getLevelledItem(ref.getPtr().get<ESM::CreatureLevList>()->mBase, failChance); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         catch (std::logic_error& e) | ||||||
|  |         { | ||||||
|  |             // Vanilla doesn't fail on nonexistent items in levelled lists
 | ||||||
|  |             std::cerr << "Warning: ignoring nonexistent item '" << item << "'" << std::endl; | ||||||
|  |             return std::string(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -5,17 +5,11 @@ | ||||||
| #include <typeinfo> | #include <typeinfo> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| 
 | 
 | ||||||
| #include <boost/algorithm/string.hpp> |  | ||||||
| 
 |  | ||||||
| #include <components/esm/loadcont.hpp> |  | ||||||
| #include <components/compiler/locals.hpp> |  | ||||||
| #include <components/misc/stringops.hpp> |  | ||||||
| 
 |  | ||||||
| #include "../mwbase/environment.hpp" | #include "../mwbase/environment.hpp" | ||||||
| #include "../mwbase/world.hpp" | #include "../mwbase/world.hpp" | ||||||
| #include "../mwbase/scriptmanager.hpp" |  | ||||||
| 
 | 
 | ||||||
| #include "../mwmechanics/creaturestats.hpp" | #include "../mwmechanics/creaturestats.hpp" | ||||||
|  | #include "../mwmechanics/levelledlist.hpp" | ||||||
| 
 | 
 | ||||||
| #include "manualref.hpp" | #include "manualref.hpp" | ||||||
| #include "refdata.hpp" | #include "refdata.hpp" | ||||||
|  | @ -309,72 +303,35 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std:: | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, | void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, | ||||||
|                                               int count, unsigned char failChance, bool topLevel) |                                               int count, bool topLevel) | ||||||
| { | { | ||||||
|     count = std::abs(count); /// \todo implement item restocking (indicated by negative count)
 |     count = std::abs(count); /// \todo implement item restocking (indicated by negative count)
 | ||||||
| 
 | 
 | ||||||
|     try |     ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); | ||||||
|  | 
 | ||||||
|  |     if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) | ||||||
|     { |     { | ||||||
|         ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); |         const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase; | ||||||
| 
 | 
 | ||||||
|         if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) |         if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) | ||||||
|         { |         { | ||||||
|             const ESM::ItemLevList* levItem = ref.getPtr().get<ESM::ItemLevList>()->mBase; |             for (int i=0; i<count; ++i) | ||||||
|             const std::vector<ESM::LeveledListBase::LevelItem>& items = levItem->mList; |                 addInitialItem(id, owner, faction, 1); | ||||||
| 
 |             return; | ||||||
|             MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); |  | ||||||
|             int playerLevel = player.getClass().getCreatureStats(player).getLevel(); |  | ||||||
| 
 |  | ||||||
|             failChance += levItem->mChanceNone; |  | ||||||
| 
 |  | ||||||
|             if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) |  | ||||||
|             { |  | ||||||
|                 for (int i=0; i<count; ++i) |  | ||||||
|                     addInitialItem(id, owner, faction, 1, failChance, false); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             float random = static_cast<float> (std::rand()) / RAND_MAX; |  | ||||||
|             if (random >= failChance/100.f) |  | ||||||
|             { |  | ||||||
|                 std::vector<std::string> candidates; |  | ||||||
|                 int highestLevel = 0; |  | ||||||
|                 for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it) |  | ||||||
|                 { |  | ||||||
|                     if (it->mLevel > highestLevel) |  | ||||||
|                         highestLevel = it->mLevel; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 std::pair<int, std::string> highest = std::make_pair(-1, ""); |  | ||||||
|                 for (std::vector<ESM::LeveledListBase::LevelItem>::const_iterator it = items.begin(); it != items.end(); ++it) |  | ||||||
|                 { |  | ||||||
|                     if (playerLevel >= it->mLevel |  | ||||||
|                             && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) |  | ||||||
|                     { |  | ||||||
|                         candidates.push_back(it->mId); |  | ||||||
|                         if (it->mLevel >= highest.first) |  | ||||||
|                             highest = std::make_pair(it->mLevel, it->mId); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                 } |  | ||||||
|                 if (candidates.empty()) |  | ||||||
|                     return; |  | ||||||
|                 std::string item = candidates[std::rand()%candidates.size()]; |  | ||||||
|                 addInitialItem(item, owner, faction, count, failChance, false); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             ref.getPtr().getCellRef().mOwner = owner; |             std::string id = MWMechanics::getLevelledItem(ref.getPtr().get<ESM::ItemLevList>()->mBase); | ||||||
|             ref.getPtr().getCellRef().mFaction = faction; |             if (id.empty()) | ||||||
|             addImp (ref.getPtr(), count); |                 return; | ||||||
|  |             addInitialItem(id, owner, faction, count, false); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     catch (std::logic_error& e) |     else | ||||||
|     { |     { | ||||||
|         // Vanilla doesn't fail on nonexistent items in levelled lists
 |         ref.getPtr().getCellRef().mOwner = owner; | ||||||
|         std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; |         ref.getPtr().getCellRef().mFaction = faction; | ||||||
|         return; |         addImp (ref.getPtr(), count); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -54,7 +54,7 @@ namespace MWWorld | ||||||
|             mutable float mCachedWeight; |             mutable float mCachedWeight; | ||||||
|             mutable bool mWeightUpToDate; |             mutable bool mWeightUpToDate; | ||||||
|             ContainerStoreIterator addImp (const Ptr& ptr, int count); |             ContainerStoreIterator addImp (const Ptr& ptr, int count); | ||||||
|             void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, unsigned char failChance=0, bool topLevel=true); |             void addInitialItem (const std::string& id, const std::string& owner, const std::string& faction, int count, bool topLevel=true); | ||||||
| 
 | 
 | ||||||
|         public: |         public: | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue