@ -19,6 +19,46 @@ namespace MWLua
{
using EquipmentItem = std : : variant < std : : string , ObjectId > ;
using Equipment = std : : map < int , EquipmentItem > ;
static constexpr int sAnySlot = - 1 ;
static std : : pair < MWWorld : : ContainerStoreIterator , bool > findInInventory (
MWWorld : : InventoryStore & store , const EquipmentItem & item , int slot = sAnySlot )
{
auto old_it = slot ! = sAnySlot ? store . getSlot ( slot ) : store . end ( ) ;
MWWorld : : Ptr itemPtr ;
if ( std : : holds_alternative < ObjectId > ( item ) )
{
itemPtr = MWBase : : Environment : : get ( ) . getWorldModel ( ) - > getPtr ( std : : get < ObjectId > ( item ) ) ;
if ( old_it ! = store . end ( ) & & * old_it = = itemPtr )
return { old_it , true } ; // already equipped
if ( itemPtr . isEmpty ( ) | | itemPtr . getRefData ( ) . getCount ( ) = = 0
| | itemPtr . getContainerStore ( ) ! = static_cast < const MWWorld : : ContainerStore * > ( & store ) )
{
Log ( Debug : : Warning ) < < " Object " < < std : : get < ObjectId > ( item ) . toString ( ) < < " is not in inventory " ;
return { store . end ( ) , false } ;
}
}
else
{
ESM : : RefId recordId = ESM : : RefId : : deserializeText ( std : : get < std : : string > ( item ) ) ;
if ( old_it ! = store . end ( ) & & old_it - > getCellRef ( ) . getRefId ( ) = = recordId )
return { old_it , true } ; // already equipped
itemPtr = store . search ( recordId ) ;
if ( itemPtr . isEmpty ( ) | | itemPtr . getRefData ( ) . getCount ( ) = = 0 )
{
Log ( Debug : : Warning ) < < " There is no object with recordId=' " < < recordId < < " ' in inventory " ;
return { store . end ( ) , false } ;
}
}
// TODO: Refactor InventoryStore to accept Ptr and get rid of this linear search.
MWWorld : : ContainerStoreIterator it = std : : find ( store . begin ( ) , store . end ( ) , itemPtr ) ;
if ( it = = store . end ( ) ) // should never happen
throw std : : logic_error ( " Item not found in container " ) ;
return { it , false } ;
}
static void setEquipment ( const MWWorld : : Ptr & actor , const Equipment & equipment )
{
@ -26,34 +66,13 @@ namespace MWLua
std : : array < bool , MWWorld : : InventoryStore : : Slots > usedSlots ;
std : : fill ( usedSlots . begin ( ) , usedSlots . end ( ) , false ) ;
static constexpr int anySlot = - 1 ;
auto tryEquipToSlot = [ & store , & usedSlots ] ( int slot , const EquipmentItem & item ) - > bool {
auto old_it = slot ! = anySlot ? store . getSlot ( slot ) : store . end ( ) ;
MWWorld : : Ptr itemPtr ;
if ( std : : holds_alternative < ObjectId > ( item ) )
{
itemPtr = MWBase : : Environment : : get ( ) . getWorldModel ( ) - > getPtr ( std : : get < ObjectId > ( item ) ) ;
if ( old_it ! = store . end ( ) & & * old_it = = itemPtr )
return true ; // already equipped
if ( itemPtr . isEmpty ( ) | | itemPtr . getRefData ( ) . getCount ( ) = = 0
| | itemPtr . getContainerStore ( ) ! = static_cast < const MWWorld : : ContainerStore * > ( & store ) )
{
Log ( Debug : : Warning ) < < " Object " < < std : : get < ObjectId > ( item ) . toString ( ) < < " is not in inventory " ;
return false ;
}
}
else
{
const ESM : : RefId & recordId = ESM : : RefId : : stringRefId ( std : : get < std : : string > ( item ) ) ;
if ( old_it ! = store . end ( ) & & old_it - > getCellRef ( ) . getRefId ( ) = = recordId )
return true ; // already equipped
itemPtr = store . search ( recordId ) ;
if ( itemPtr . isEmpty ( ) | | itemPtr . getRefData ( ) . getCount ( ) = = 0 )
{
Log ( Debug : : Warning ) < < " There is no object with recordId=' " < < recordId < < " ' in inventory " ;
return false ;
}
}
auto [ it , alreadyEquipped ] = findInInventory ( store , item , slot ) ;
if ( alreadyEquipped )
return true ;
if ( it = = store . end ( ) )
return false ;
MWWorld : : Ptr itemPtr = * it ;
auto [ allowedSlots , _ ] = itemPtr . getClass ( ) . getEquipmentSlots ( itemPtr ) ;
bool requestedSlotIsAllowed
@ -70,11 +89,6 @@ namespace MWLua
slot = * firstAllowed ;
}
// TODO: Refactor InventoryStore to accept Ptr and get rid of this linear search.
MWWorld : : ContainerStoreIterator it = std : : find ( store . begin ( ) , store . end ( ) , itemPtr ) ;
if ( it = = store . end ( ) ) // should never happen
throw std : : logic_error ( " Item not found in container " ) ;
store . equip ( slot , it ) ;
return requestedSlotIsAllowed ; // return true if equipped to requested slot and false if slot was changed
} ;
@ -94,7 +108,42 @@ namespace MWLua
}
for ( const auto & [ slot , item ] : equipment )
if ( slot > = MWWorld : : InventoryStore : : Slots )
tryEquipToSlot ( anySlot , item ) ;
tryEquipToSlot ( sAnySlot , item ) ;
}
static void setSelectedEnchantedItem ( const MWWorld : : Ptr & actor , const EquipmentItem & item )
{
MWWorld : : InventoryStore & store = actor . getClass ( ) . getInventoryStore ( actor ) ;
// We're not passing in a specific slot, so ignore the already equipped return value
auto [ it , _ ] = findInInventory ( store , item , sAnySlot ) ;
if ( it = = store . end ( ) )
return ;
MWWorld : : Ptr itemPtr = * it ;
// Equip the item if applicable
auto slots = itemPtr . getClass ( ) . getEquipmentSlots ( itemPtr ) ;
if ( ! slots . first . empty ( ) )
{
bool alreadyEquipped = false ;
for ( auto slot : slots . first )
{
if ( store . getSlot ( slot ) = = it )
alreadyEquipped = true ;
}
if ( ! alreadyEquipped )
{
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > useItem ( itemPtr ) ;
// make sure that item was successfully equipped
if ( ! store . isEquipped ( itemPtr ) )
return ;
}
}
store . setSelectedEnchantItem ( it ) ;
// to reset WindowManager::mSelectedSpell immediately
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > setSelectedEnchantItem ( * it ) ;
}
void addActorBindings ( sol : : table actor , const Context & context )
@ -173,8 +222,37 @@ namespace MWLua
stats . setDrawState ( newDrawState ) ;
} ;
// TODO
// getSelectedEnchantedItem, setSelectedEnchantedItem
actor [ " getSelectedEnchantedItem " ] = [ ] ( sol : : this_state lua , const Object & o ) - > sol : : object {
const MWWorld : : Ptr & ptr = o . ptr ( ) ;
if ( ! ptr . getClass ( ) . hasInventoryStore ( ptr ) )
return sol : : nil ;
MWWorld : : InventoryStore & store = ptr . getClass ( ) . getInventoryStore ( ptr ) ;
auto it = store . getSelectedEnchantItem ( ) ;
if ( it = = store . end ( ) )
return sol : : nil ;
MWBase : : Environment : : get ( ) . getWorldModel ( ) - > registerPtr ( * it ) ;
if ( dynamic_cast < const GObject * > ( & o ) )
return sol : : make_object ( lua , GObject ( * it ) ) ;
else
return sol : : make_object ( lua , LObject ( * it ) ) ;
} ;
actor [ " setSelectedEnchantedItem " ] = [ context ] ( const SelfObject & obj , const sol : : object & item ) {
const MWWorld : : Ptr & ptr = obj . ptr ( ) ;
if ( ! ptr . getClass ( ) . hasInventoryStore ( ptr ) )
return ;
EquipmentItem ei ;
if ( item . is < Object > ( ) )
{
ei = LuaUtil : : cast < Object > ( item ) . id ( ) ;
}
else
{
ei = LuaUtil : : cast < std : : string > ( item ) ;
}
context . mLuaManager - > addAction ( [ obj = Object ( ptr ) , ei = ei ] { setSelectedEnchantedItem ( obj . ptr ( ) , ei ) ; } ,
" setSelectedEnchantedItemAction " ) ;
} ;
actor [ " canMove " ] = [ ] ( const Object & o ) {
const MWWorld : : Class & cls = o . ptr ( ) . getClass ( ) ;