mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-31 13:56:45 +00:00 
			
		
		
		
	Make Drop and soulgem instruction behavior closer to vanilla (bug #4999)
This commit is contained in:
		
							parent
							
								
									c3cebbfaf6
								
							
						
					
					
						commit
						b42f981200
					
				
					 2 changed files with 54 additions and 30 deletions
				
			
		|  | @ -82,6 +82,7 @@ | |||
|     Bug #4984: "Friendly hits" feature should be used only for player's followers | ||||
|     Bug #4989: Object dimension-dependent VFX scaling behavior is inconsistent | ||||
|     Bug #4990: Dead bodies prevent you from hitting | ||||
|     Bug #4999: Drop instruction behaves differently from vanilla | ||||
|     Bug #5004: Werewolves shield their eyes during storm | ||||
|     Feature #1774: Handle AvoidNode | ||||
|     Feature #2229: Improve pathfinding AI | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/windowmanager.hpp" | ||||
| #include "../mwbase/scriptmanager.hpp" | ||||
| #include "../mwbase/soundmanager.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
|  | @ -23,6 +24,7 @@ | |||
| #include "../mwworld/inventorystore.hpp" | ||||
| #include "../mwworld/esmstore.hpp" | ||||
| #include "../mwworld/cellstore.hpp" | ||||
| #include "../mwworld/manualref.hpp" | ||||
| 
 | ||||
| #include "../mwmechanics/aicast.hpp" | ||||
| #include "../mwmechanics/npcstats.hpp" | ||||
|  | @ -469,6 +471,9 @@ namespace MWScript | |||
|                     std::string gem = runtime.getStringLiteral (runtime[0].mInteger); | ||||
|                     runtime.pop(); | ||||
| 
 | ||||
|                     if (!ptr.getClass().hasInventoryStore(ptr)) | ||||
|                         return; | ||||
| 
 | ||||
|                     const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); | ||||
|                     store.get<ESM::Creature>().find(creature); // This line throws an exception if it can't find the creature
 | ||||
| 
 | ||||
|  | @ -499,7 +504,10 @@ namespace MWScript | |||
|                     for (unsigned int i=0; i<arg0; ++i) | ||||
|                         runtime.pop(); | ||||
| 
 | ||||
|                     MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); | ||||
|                     if (!ptr.getClass().hasInventoryStore(ptr)) | ||||
|                         return; | ||||
| 
 | ||||
|                     MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr); | ||||
|                     for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) | ||||
|                     { | ||||
|                         if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), soul)) | ||||
|  | @ -534,16 +542,18 @@ namespace MWScript | |||
|                     if (amount == 0) | ||||
|                         return; | ||||
| 
 | ||||
|                     // Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping them.
 | ||||
|                     MWWorld::InventoryStore *invStorePtr = 0; | ||||
|                     if (ptr.getClass().hasInventoryStore(ptr)) { | ||||
|                         invStorePtr = &ptr.getClass().getInventoryStore(ptr); | ||||
|                     if (!ptr.getClass().isActor()) | ||||
|                         return; | ||||
| 
 | ||||
|                         int numNotEquipped = invStorePtr->count(item); | ||||
|                     if (ptr.getClass().hasInventoryStore(ptr)) | ||||
|                     { | ||||
|                         // Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping them.
 | ||||
|                         MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr); | ||||
|                         int numNotEquipped = store.count(item); | ||||
|                         for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) | ||||
|                         { | ||||
|                             MWWorld::ConstContainerStoreIterator it = invStorePtr->getSlot (slot); | ||||
|                             if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) | ||||
|                             MWWorld::ConstContainerStoreIterator it = store.getSlot (slot); | ||||
|                             if (it != store.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) | ||||
|                             { | ||||
|                                 numNotEquipped -= it->getRefData().getCount(); | ||||
|                             } | ||||
|  | @ -551,37 +561,48 @@ namespace MWScript | |||
| 
 | ||||
|                         for (int slot = 0; slot < MWWorld::InventoryStore::Slots && amount > numNotEquipped; ++slot) | ||||
|                         { | ||||
|                             MWWorld::ContainerStoreIterator it = invStorePtr->getSlot (slot); | ||||
|                             if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) | ||||
|                             MWWorld::ContainerStoreIterator it = store.getSlot (slot); | ||||
|                             if (it != store.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) | ||||
|                             { | ||||
|                                 int numToRemove = it->getRefData().getCount(); | ||||
|                                 if (numToRemove > amount - numNotEquipped) | ||||
|                                 { | ||||
|                                     numToRemove = amount - numNotEquipped; | ||||
|                                 } | ||||
|                                 invStorePtr->unequipItemQuantity(*it, ptr, numToRemove); | ||||
|                                 int numToRemove = std::min(amount - numNotEquipped, it->getRefData().getCount()); | ||||
|                                 store.unequipItemQuantity(*it, ptr, numToRemove); | ||||
|                                 numNotEquipped += numToRemove; | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) | ||||
|                         { | ||||
|                             if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item) && !store.isEquipped(*iter)) | ||||
|                             { | ||||
|                                 int removed = store.remove(*iter, amount, ptr); | ||||
|                                 MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); | ||||
|                                 dropped.getCellRef().setOwner(""); | ||||
| 
 | ||||
|                                 amount -= removed; | ||||
| 
 | ||||
|                                 if (amount <= 0) | ||||
|                                     break; | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     int toRemove = amount; | ||||
|                     MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); | ||||
|                     for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) | ||||
|                     MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), item, 1); | ||||
|                     MWWorld::Ptr itemPtr(ref.getPtr()); | ||||
|                     if (amount > 0) | ||||
|                     { | ||||
|                         if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item) | ||||
|                                 && (!invStorePtr || !invStorePtr->isEquipped(*iter))) | ||||
|                         if (itemPtr.getClass().getScript(itemPtr).empty()) | ||||
|                         { | ||||
|                             int removed = store.remove(*iter, toRemove, ptr); | ||||
|                             MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); | ||||
|                             dropped.getCellRef().setOwner(""); | ||||
| 
 | ||||
|                             toRemove -= removed; | ||||
| 
 | ||||
|                             if (toRemove <= 0) | ||||
|                                 break; | ||||
|                             MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, itemPtr, amount); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             // Dropping one item per time to prevent making stacks of scripted items
 | ||||
|                             for (int i = 0; i < amount; i++) | ||||
|                                 MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, itemPtr, 1); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     MWBase::Environment::get().getSoundManager()->playSound3D(ptr, itemPtr.getClass().getDownSoundId(itemPtr), 1.f, 1.f); | ||||
|                 } | ||||
|         }; | ||||
| 
 | ||||
|  | @ -598,8 +619,10 @@ namespace MWScript | |||
|                     std::string soul = runtime.getStringLiteral (runtime[0].mInteger); | ||||
|                     runtime.pop(); | ||||
| 
 | ||||
|                     MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr); | ||||
|                     if (!ptr.getClass().hasInventoryStore(ptr)) | ||||
|                         return; | ||||
| 
 | ||||
|                     MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr); | ||||
| 
 | ||||
|                     for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) | ||||
|                     { | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue