|
@@ -0,0 +1,371 @@
|
|
|
|
+#include "Inventory.h"
|
|
|
|
+#include "ItemFilter.h"
|
|
|
|
+#include "Constants.h"
|
|
|
|
+#include "Area.h"
|
|
|
|
+
|
|
|
|
+using namespace Framework;
|
|
|
|
+
|
|
|
|
+InventoryInteraction::InventoryInteraction( Inventory *current, Inventory *other, Direction dir )
|
|
|
|
+ : current( current ),
|
|
|
|
+ other( other ),
|
|
|
|
+ dir( dir )
|
|
|
|
+{
|
|
|
|
+ lock();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+InventoryInteraction::InventoryInteraction( const InventoryInteraction &interaction )
|
|
|
|
+ : InventoryInteraction( interaction.current, interaction.other, interaction.dir )
|
|
|
|
+{}
|
|
|
|
+
|
|
|
|
+InventoryInteraction::~InventoryInteraction()
|
|
|
|
+{
|
|
|
|
+ unlock();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InventoryInteraction::lock()
|
|
|
|
+{
|
|
|
|
+ if( !current || !other ) return;
|
|
|
|
+ if( current->location.x < other->location.x )
|
|
|
|
+ {
|
|
|
|
+ current->cs.Enter();
|
|
|
|
+ other->cs.Enter();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ else if( current->location.x == other->location.x )
|
|
|
|
+ {
|
|
|
|
+ if( current->location.y < other->location.y )
|
|
|
|
+ {
|
|
|
|
+ current->cs.Enter();
|
|
|
|
+ other->cs.Enter();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ else if( current->location.y == other->location.y )
|
|
|
|
+ {
|
|
|
|
+ if( current->location.z < other->location.z )
|
|
|
|
+ {
|
|
|
|
+ current->cs.Enter();
|
|
|
|
+ other->cs.Enter();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ other->cs.Enter();
|
|
|
|
+ current->cs.Enter();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InventoryInteraction::unlock()
|
|
|
|
+{
|
|
|
|
+ if( !current || !other ) return;
|
|
|
|
+ if( current->location.x < other->location.x )
|
|
|
|
+ {
|
|
|
|
+ current->cs.Leave();
|
|
|
|
+ other->cs.Leave();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ else if( current->location.x == other->location.x )
|
|
|
|
+ {
|
|
|
|
+ if( current->location.y < other->location.y )
|
|
|
|
+ {
|
|
|
|
+ current->cs.Leave();
|
|
|
|
+ other->cs.Leave();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ else if( current->location.y == other->location.y )
|
|
|
|
+ {
|
|
|
|
+ if( current->location.z < other->location.z )
|
|
|
|
+ {
|
|
|
|
+ current->cs.Leave();
|
|
|
|
+ other->cs.Leave();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ other->cs.Leave();
|
|
|
|
+ current->cs.Leave();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InventoryInteraction::transaction( Inventory *zSource, Inventory *zTarget, ItemFilter *zFilter, Direction sourceView, Direction targetView, int count )
|
|
|
|
+{
|
|
|
|
+ auto sourceSlot = zSource->pullSlotsOrder->getIterator();
|
|
|
|
+ for( auto targetSlot = zTarget->pushSlotsOrder->getIterator(); targetSlot; )
|
|
|
|
+ {
|
|
|
|
+ int amount = count;
|
|
|
|
+ if( !targetSlot->isFull() )
|
|
|
|
+ {
|
|
|
|
+ if( targetSlot->zStack() )
|
|
|
|
+ {
|
|
|
|
+ Array<ItemSlot *> *zSurceListe = zSource->itemCache->safeGet( targetSlot->zStack()->zItem()->zItemType()->getId(), 0 );
|
|
|
|
+ if( zSurceListe )
|
|
|
|
+ {
|
|
|
|
+ Array<int> toDelete;
|
|
|
|
+ int index = 0;
|
|
|
|
+ for( auto sourceSlot = zSurceListe->getIterator(); sourceSlot; sourceSlot++, index++ )
|
|
|
|
+ {
|
|
|
|
+ if( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) )
|
|
|
|
+ continue;
|
|
|
|
+ int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), sourceView ), count );
|
|
|
|
+ int tmp = number;
|
|
|
|
+ if( number > 0 && zSource->allowPullStack( sourceSlot, sourceView ) && zTarget->allowPushStack( targetSlot, targetView, sourceSlot->zStack()->zItem(), tmp ) )
|
|
|
|
+ {
|
|
|
|
+ number = MIN( number, tmp );
|
|
|
|
+ ItemStack *stack = sourceSlot->takeItemsOut( number, dir );
|
|
|
|
+ if( stack )
|
|
|
|
+ {
|
|
|
|
+ if( !sourceSlot->zStack() )
|
|
|
|
+ toDelete.add( index, 0 );
|
|
|
|
+ targetSlot->addItems( stack, dir );
|
|
|
|
+ zSource->afterPullStack( sourceSlot, sourceView, targetSlot->zStack()->zItem(), number );
|
|
|
|
+ zTarget->afterPushStack( targetSlot, targetView, targetSlot->zStack()->zItem(), number );
|
|
|
|
+ if( stack->getSize() )
|
|
|
|
+ throw stack;
|
|
|
|
+ stack->release();
|
|
|
|
+ count -= number;
|
|
|
|
+ if( count == 0 )
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for( auto indexToDelete = toDelete.getIterator(); indexToDelete; indexToDelete++ )
|
|
|
|
+ zSurceListe->remove( indexToDelete );
|
|
|
|
+ if( count == 0 )
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ while( sourceSlot && ( !sourceSlot->zStack() || ( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) ) ) )
|
|
|
|
+ sourceSlot++;
|
|
|
|
+ if( !sourceSlot )
|
|
|
|
+ return;
|
|
|
|
+ int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), sourceView ), count );
|
|
|
|
+ int tmp = number;
|
|
|
|
+ if( number > 0 && zSource->allowPullStack( sourceSlot, sourceView ) && zTarget->allowPushStack( targetSlot, targetView, sourceSlot->zStack()->zItem(), tmp ) )
|
|
|
|
+ {
|
|
|
|
+ number = MIN( number, tmp );
|
|
|
|
+ ItemStack *stack = sourceSlot->takeItemsOut( number, dir );
|
|
|
|
+ if( stack )
|
|
|
|
+ {
|
|
|
|
+ zSource->updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
|
|
|
|
+ targetSlot->addItems( stack, dir );
|
|
|
|
+ zTarget->updateCache( targetSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
|
|
|
|
+ zSource->afterPullStack( sourceSlot, sourceView, targetSlot->zStack()->zItem(), number );
|
|
|
|
+ zTarget->afterPushStack( targetSlot, targetView, targetSlot->zStack()->zItem(), number );
|
|
|
|
+ if( stack->getSize() )
|
|
|
|
+ throw stack;
|
|
|
|
+ stack->release();
|
|
|
|
+ count -= number;
|
|
|
|
+ if( count == 0 )
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( amount == count || targetSlot->isFull() )
|
|
|
|
+ targetSlot++;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+InventoryInteraction &InventoryInteraction::operator=( const InventoryInteraction &data )
|
|
|
|
+{
|
|
|
|
+ if( &data == this ) return *this;
|
|
|
|
+ unlock();
|
|
|
|
+ current = data.current;
|
|
|
|
+ other = data.other;
|
|
|
|
+ dir = data.dir;
|
|
|
|
+ lock();
|
|
|
|
+ return *this;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InventoryInteraction::endInteraction()
|
|
|
|
+{
|
|
|
|
+ unlock();
|
|
|
|
+ current = 0;
|
|
|
|
+ other = 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InventoryInteraction::pullItems( int count, ItemFilter *zFilter )
|
|
|
|
+{
|
|
|
|
+ if( !current || !other ) return;
|
|
|
|
+ transaction( other, current, zFilter, opposite( dir ), dir, count );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void InventoryInteraction::pushItems( int count, ItemFilter *zFilter )
|
|
|
|
+{
|
|
|
|
+ if( !current || !other ) return;
|
|
|
|
+ transaction( current, other, zFilter, dir, opposite( dir ), count );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+Inventory::Inventory( const Framework::Vec3<float> location )
|
|
|
|
+{
|
|
|
|
+ pullSlotsOrder = new Framework::RCArray<ItemSlot>();
|
|
|
|
+ pushSlotsOrder = new Framework::RCArray<ItemSlot>();
|
|
|
|
+ itemCache = new Framework::HashMap<int, Framework::Array<ItemSlot *> *>( ITEM_CACHE_SIZE, std::_Identity<int>() );
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Inventory::~Inventory()
|
|
|
|
+{
|
|
|
|
+ pullSlotsOrder->release();
|
|
|
|
+ pushSlotsOrder->release();
|
|
|
|
+ itemCache->release();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Inventory::updateCache( ItemSlot *zSlot, int beforeKey )
|
|
|
|
+{
|
|
|
|
+ int key = zSlot->zStack()->zItem()->zItemType()->getId();
|
|
|
|
+ if( key == beforeKey )
|
|
|
|
+ return;
|
|
|
|
+ if( beforeKey >= 0 )
|
|
|
|
+ {
|
|
|
|
+ auto tmp = itemCache->safeGet( key, 0 );
|
|
|
|
+ if( tmp )
|
|
|
|
+ tmp->removeValue( zSlot );
|
|
|
|
+ }
|
|
|
|
+ if( zSlot->zStack() )
|
|
|
|
+ {
|
|
|
|
+ auto tmp = itemCache->safeGet( key, 0 );
|
|
|
|
+ if( !tmp )
|
|
|
|
+ {
|
|
|
|
+ tmp = new Array<ItemSlot *>();
|
|
|
|
+ itemCache->put( key, tmp );
|
|
|
|
+ }
|
|
|
|
+ tmp->add( zSlot, 0 );
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Inventory::addSlot( ItemSlot *slot )
|
|
|
|
+{
|
|
|
|
+ cs.Enter();
|
|
|
|
+ int pullPrio = slot->getPullPriority();
|
|
|
|
+ int pushPrio = slot->getPushPriority();
|
|
|
|
+ int index = 0;
|
|
|
|
+ for( auto iterator = pullSlotsOrder->getIterator(); iterator; iterator++, index++ )
|
|
|
|
+ {
|
|
|
|
+ if( iterator->getPullPriority() > pullPrio )
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ pullSlotsOrder->add( dynamic_cast<ItemSlot *>( slot->getThis() ), index );
|
|
|
|
+ index = 0;
|
|
|
|
+ for( auto iterator = pushSlotsOrder->getIterator(); iterator; iterator++, index++ )
|
|
|
|
+ {
|
|
|
|
+ if( iterator->getPushPriority() > pushPrio )
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ pullSlotsOrder->add( slot, index );
|
|
|
|
+ updateCache( slot, -1 );
|
|
|
|
+ cs.Leave();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool Inventory::allowPullStack( ItemSlot *zSlot, Direction dir )
|
|
|
|
+{
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool Inventory::allowPushStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int &count )
|
|
|
|
+{
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void Inventory::afterPullStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int count )
|
|
|
|
+{}
|
|
|
|
+
|
|
|
|
+void Inventory::afterPushStack( ItemSlot *zSlot, Direction dir, const Item *zItem, int count )
|
|
|
|
+{}
|
|
|
|
+
|
|
|
|
+void Inventory::localTransaction( Array< ItemSlot * > *zSourceSlots, Array< ItemSlot * > *zTargetSlots, ItemFilter *zFilter, int count )
|
|
|
|
+{
|
|
|
|
+ cs.Enter();
|
|
|
|
+ auto sourceSlot = zSourceSlots->getIterator();
|
|
|
|
+ for( auto targetSlot = zTargetSlots->getIterator(); targetSlot; )
|
|
|
|
+ {
|
|
|
|
+ int amount = count;
|
|
|
|
+ if( !targetSlot->isFull() )
|
|
|
|
+ {
|
|
|
|
+ if( targetSlot->zStack() )
|
|
|
|
+ {
|
|
|
|
+ Array<ItemSlot *> *zSurceListe = itemCache->safeGet( targetSlot->zStack()->zItem()->zItemType()->getId(), 0 );
|
|
|
|
+ if( zSurceListe )
|
|
|
|
+ {
|
|
|
|
+ Array<int> toDelete;
|
|
|
|
+ int index = 0;
|
|
|
|
+ for( auto sourceSlot = zSurceListe->getIterator(); sourceSlot; sourceSlot++, index++ )
|
|
|
|
+ {
|
|
|
|
+ if( zSourceSlots->getWertIndex( sourceSlot ) < 0 )
|
|
|
|
+ continue;
|
|
|
|
+ if( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) )
|
|
|
|
+ continue;
|
|
|
|
+ int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
|
|
|
|
+ if( number > 0 )
|
|
|
|
+ {
|
|
|
|
+ ItemStack *stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
|
|
|
|
+ if( stack )
|
|
|
|
+ {
|
|
|
|
+ if( !sourceSlot->zStack() )
|
|
|
|
+ toDelete.add( index, 0 );
|
|
|
|
+ targetSlot->addItems( stack, NO_DIRECTION );
|
|
|
|
+ if( stack->getSize() )
|
|
|
|
+ {
|
|
|
|
+ cs.Leave();
|
|
|
|
+ throw stack;
|
|
|
|
+ }
|
|
|
|
+ stack->release();
|
|
|
|
+ count -= number;
|
|
|
|
+ if( count == 0 )
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for( auto indexToDelete = toDelete.getIterator(); indexToDelete; indexToDelete++ )
|
|
|
|
+ zSurceListe->remove( indexToDelete );
|
|
|
|
+ if( count == 0 )
|
|
|
|
+ {
|
|
|
|
+ cs.Leave();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ while( sourceSlot && ( !sourceSlot->zStack() || ( zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ) ) ) )
|
|
|
|
+ sourceSlot++;
|
|
|
|
+ if( !sourceSlot )
|
|
|
|
+ {
|
|
|
|
+ cs.Leave();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
|
|
|
|
+ if( number > 0 )
|
|
|
|
+ {
|
|
|
|
+ ItemStack *stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
|
|
|
|
+ if( stack )
|
|
|
|
+ {
|
|
|
|
+ updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
|
|
|
|
+ targetSlot->addItems( stack, NO_DIRECTION );
|
|
|
|
+ updateCache( targetSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
|
|
|
|
+ if( stack->getSize() )
|
|
|
|
+ {
|
|
|
|
+ cs.Leave();
|
|
|
|
+ throw stack;
|
|
|
|
+ }
|
|
|
|
+ stack->release();
|
|
|
|
+ count -= number;
|
|
|
|
+ if( count == 0 )
|
|
|
|
+ {
|
|
|
|
+ cs.Leave();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if( amount == count || targetSlot->isFull() )
|
|
|
|
+ targetSlot++;
|
|
|
|
+ }
|
|
|
|
+ cs.Leave();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+InventoryInteraction Inventory::interactWith( Inventory *zInventory, Direction dir )
|
|
|
|
+{
|
|
|
|
+ return InventoryInteraction( this, zInventory, dir );
|
|
|
|
+}
|