123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- #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.lock();
- other->cs.lock();
- return;
- }
- else if( current->location.x == other->location.x )
- {
- if( current->location.y < other->location.y )
- {
- current->cs.lock();
- other->cs.lock();
- return;
- }
- else if( current->location.y == other->location.y )
- {
- if( current->location.z < other->location.z )
- {
- current->cs.lock();
- other->cs.lock();
- return;
- }
- }
- }
- other->cs.lock();
- current->cs.lock();
- }
- void InventoryInteraction::unlock()
- {
- if( !current || !other ) return;
- if( current->location.x < other->location.x )
- {
- current->cs.unlock();
- other->cs.unlock();
- return;
- }
- else if( current->location.x == other->location.x )
- {
- if( current->location.y < other->location.y )
- {
- current->cs.unlock();
- other->cs.unlock();
- return;
- }
- else if( current->location.y == other->location.y )
- {
- if( current->location.z < other->location.z )
- {
- current->cs.unlock();
- other->cs.unlock();
- return;
- }
- }
- }
- other->cs.unlock();
- current->cs.unlock();
- }
- void InventoryInteraction::transaction( Inventory* zSource, Inventory* zTarget, ItemFilter* zFilter, Direction sourceView, Direction targetView, int count )
- {
- // TODO: rewrite this such that for each source slot all target slots are looped trough
- auto sourceSlot = zSource->pullSlotsOrder->begin();
- for( auto targetSlot = zTarget->pushSlotsOrder->begin(); 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->begin(); 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->updateCache( sourceSlot, 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 )
- break;
- }
- }
- }
- for( auto indexToDelete = toDelete.begin(); 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 );
- if( number > 0 )
- {
- ItemStack* stack = sourceSlot->takeItemsOut( number, dir );
- if( stack )
- {
- targetSlot->addItems( stack, dir );
- zSource->updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
- zTarget->updateCache( targetSlot, -1 );
- 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, getOppositeDirection( dir ), dir, count );
- }
- void InventoryInteraction::pushItems( int count, ItemFilter* zFilter )
- {
- if( !current || !other ) return;
- transaction( current, other, zFilter, dir, getOppositeDirection( dir ), count );
- }
- Inventory::Inventory( const Framework::Vec3<float> location, bool hasInventory )
- : ReferenceCounter(),
- location( location )
- {
- if( hasInventory )
- {
- pullSlotsOrder = new Framework::RCArray<ItemSlot>();
- pushSlotsOrder = new Framework::RCArray<ItemSlot>();
- itemCache = new Framework::HashMap<int, Framework::Array<ItemSlot*>*>( ITEM_CACHE_SIZE, std::_Identity<int>() );
- }
- else
- {
- pullSlotsOrder = 0;
- pushSlotsOrder = 0;
- itemCache = 0;
- }
- }
- Inventory::~Inventory()
- {
- if( pullSlotsOrder )
- pullSlotsOrder->release();
- if( pushSlotsOrder )
- pushSlotsOrder->release();
- if( itemCache )
- itemCache->release();
- }
- void Inventory::updateCache( ItemSlot* zSlot, int beforeKey )
- {
- if( !itemCache )
- return;
- int key = zSlot->zStack() ? zSlot->zStack()->zItem()->zItemType()->getId() : -1;
- 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.lock();
- int pullPrio = slot->getPullPriority();
- int pushPrio = slot->getPushPriority();
- int index = 0;
- for( auto stack : *pullSlotsOrder )
- {
- if( stack->getPullPriority() > pullPrio )
- break;
- index++;
- }
- pullSlotsOrder->add( dynamic_cast<ItemSlot*>(slot->getThis()), index );
- index = 0;
- for( auto stack : *pushSlotsOrder )
- {
- if( stack->getPushPriority() > pushPrio )
- break;
- index++;
- }
- pushSlotsOrder->add( slot, index );
- updateCache( slot, -1 );
- cs.unlock();
- }
- bool Inventory::allowPullStack( ItemSlot* zSlot, Direction dir ) const
- {
- return pullSlotsOrder;
- }
- bool Inventory::allowPushStack( ItemSlot* zSlot, Direction dir, const Item* zItem, int& count ) const
- {
- return pushSlotsOrder;
- }
- 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::loadInventory( Framework::StreamReader* zReader )
- {
- if( itemCache )
- {
- for( auto stack : *pushSlotsOrder )
- {
- int size = 0;
- zReader->lese( (char*)&size, 4 );
- if( size != 0 )
- {
- int id = 0;
- zReader->lese( (char*)&id, 4 );
- Item* item = StaticRegistry<ItemType>::INSTANCE.zElement( id )->loadItem( zReader );
- stack->addItems( new ItemStack( item, size ), NO_DIRECTION );
- }
- }
- }
- }
- void Inventory::saveInventory( Framework::StreamWriter* zWriter )
- {
- if( itemCache )
- {
- for( auto slot : *pushSlotsOrder )
- {
- const ItemStack* stack = slot->zStack();
- int value = 0;
- if( !stack || !stack->zItem() )
- {
- zWriter->schreibe( (char*)&value, 4 );
- }
- else
- {
- value = stack->getSize();
- zWriter->schreibe( (char*)&value, 4 );
- value = stack->zItem()->zItemType()->getId();
- zWriter->schreibe( (char*)&value, 4 );
- stack->zItem()->zItemType()->saveItem( stack->zItem(), zWriter );
- }
- }
- }
- }
- void Inventory::localTransaction( Array< ItemSlot* >* zSourceSlots, Array< ItemSlot* >* zTargetSlots, ItemFilter* zFilter, int count )
- {
- if( itemCache )
- {
- cs.lock();
- auto sourceSlot = zSourceSlots->begin();
- for( auto targetSlot = zTargetSlots->begin(); 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->begin(); 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 );
- updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
- if( stack->getSize() )
- {
- cs.unlock();
- throw stack;
- }
- stack->release();
- count -= number;
- if( count == 0 )
- break;
- }
- }
- }
- for( auto indexToDelete = toDelete.begin(); indexToDelete; indexToDelete++ )
- zSurceListe->remove( indexToDelete );
- if( count == 0 )
- {
- cs.unlock();
- return;
- }
- }
- }
- else
- {
- while( sourceSlot && (!sourceSlot->zStack() || (zFilter && !zFilter->matchItem( sourceSlot->zStack()->zItem() ))) )
- sourceSlot++;
- if( !sourceSlot )
- {
- cs.unlock();
- return;
- }
- int number = MIN( targetSlot->numberOfAddableItems( sourceSlot->zStack(), NO_DIRECTION ), count );
- if( number > 0 )
- {
- ItemStack* stack = sourceSlot->takeItemsOut( number, NO_DIRECTION );
- if( stack )
- {
- targetSlot->addItems( stack, NO_DIRECTION );
- updateCache( sourceSlot, targetSlot->zStack()->zItem()->zItemType()->getId() );
- updateCache( targetSlot, -1 );
- if( stack->getSize() )
- {
- cs.unlock();
- throw stack;
- }
- stack->release();
- count -= number;
- if( count == 0 )
- {
- cs.unlock();
- return;
- }
- }
- }
- }
- }
- if( amount == count || targetSlot->isFull() )
- targetSlot++;
- }
- cs.unlock();
- }
- }
- void Inventory::addItems( ItemStack* items, Direction dir )
- {
- if( itemCache && items && items->getSize() > 0 )
- {
- cs.lock();
- for( auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++ )
- {
- if( !targetSlot->isFull() )
- {
- if( targetSlot->zStack() )
- {
- int number = MIN( targetSlot->numberOfAddableItems( items, dir ), items->getSize() );
- int tmp = number;
- if( number > 0 && allowPushStack( targetSlot, dir, items->zItem(), tmp ) )
- {
- number = MIN( number, tmp );
- ItemStack* stack = items->split( number );
- if( stack )
- {
- targetSlot->addItems( stack, dir );
- afterPushStack( targetSlot, dir, targetSlot->zStack()->zItem(), number );
- if( stack->getSize() )
- throw stack;
- stack->release();
- if( !items->getSize() )
- break;
- }
- }
- }
- else
- {
- int number = MIN( targetSlot->numberOfAddableItems( items, dir ), items->getSize() );
- int tmp = number;
- if( number > 0 && allowPushStack( targetSlot, dir, items->zItem(), tmp ) )
- {
- number = MIN( number, tmp );
- ItemStack* stack = items->split( number );
- if( stack )
- {
- targetSlot->addItems( stack, dir );
- updateCache( targetSlot, -1 );
- afterPushStack( targetSlot, dir, targetSlot->zStack()->zItem(), number );
- if( stack->getSize() )
- throw stack;
- stack->release();
- if( !items->getSize() )
- break;
- }
- }
- }
- }
- }
- cs.unlock();
- }
- }
- ItemStack* Inventory::takeItemsOut( ItemSlot* zSlot, int count, Direction dir )
- {
- if( allowPullStack( zSlot, dir ) )
- {
- ItemStack* stack = zSlot->takeItemsOut( count, dir );
- if( stack )
- updateCache( zSlot, stack->zItem()->zItemType()->getId() );
- return stack;
- }
- return 0;
- }
- InventoryInteraction Inventory::interactWith( Inventory* zInventory, Direction dir )
- {
- return InventoryInteraction( this, zInventory, dir );
- }
- void Inventory::unsaveAddItem( ItemStack* zStack, Direction dir )
- {
- addItems( zStack, dir );
- }
- int Inventory::numberOfAddableItems( const ItemStack* zStack, Direction dir ) const
- {
- int count = 0;
- for( auto targetSlot = pushSlotsOrder->begin(); targetSlot; targetSlot++ )
- {
- int maxCount = targetSlot->numberOfAddableItems( zStack, dir );
- int allowed = maxCount;
- if( allowPushStack( targetSlot, dir, zStack->zItem(), allowed ) )
- count += MIN( maxCount, allowed );
- }
- return count;
- }
|