Storage stacking fix

Submit code for osProse project.

Moderators: osRose dev team, ospRose dev team, osiRose dev team, Moderators

Storage stacking fix

Postby PurpleYouko on Mon May 19, 2008 6:04 pm

I don't know if any of you have noticed but storage items don't stack. They just go into the first available empty slot, regardless of whether there is already a stack of them or not.

here is how to fix it.

in PlayerFuncions.cpp
find
  1.  
  2. // Returns a free slot in the storage (0xffff if is full)
  3. UINT CPlayer::GetNewStorageItemSlot( CItem thisitem )
  4.  

Replace the entire function with
  1.  
  2. // Returns a free slot in the storage (0xffff if is full)
  3. UINT CPlayer::GetNewStorageItemSlot( CItem thisitem )
  4. {
  5.     //first check for a slot that already contains this item if it is stackable
  6.     if(thisitem.itemtype == 10 || thisitem.itemtype == 11 || thisitem.itemtype == 12)
  7.         {
  8.         for(UINT i=0;i<160;i++)
  9.         {
  10.             if(storageitems[i].itemtype == thisitem.itemtype && storageitems[i].itemnum == thisitem.itemnum)
  11.             {
  12.                 //now we make sure that the total of the new items plus the ones already there do not exceed 999
  13.                 int totalcount = storageitems[i].count + thisitem.count;
  14.                 if(totalcount < 999)
  15.                 {
  16.                     return i;
  17.                 }
  18.             }  
  19.         }
  20.     }
  21.     //so we couldn't find a matching entry to stack onto
  22.     //or the item is unstackable
  23.     //Let's look for an empty slot instead then
  24.     for(UINT i=0;i<160;i++)
  25.     {
  26.         if(storageitems[i].itemtype == 0)
  27.         {
  28.            
  29.             return i;
  30.         }
  31.     }
  32.     return 0xffff;
  33. }

This will now return EITHER a matching stack OR an empty space. matching stacks will always be returned first.
But this is only half of it. The code that actually puts teh items into storage is highly screwed up too

in WorldPackets.cpp
find
  1. // Change Storage (Deposit/Withdraw items)
  2. bool CWorldServer::pakChangeStorage( CPlayer* thisclient, CPacket* P)

as before, replace the entire function with this.
  1.  
  2. // Change Storage (Deposit/Withdraw items)
  3. bool CWorldServer::pakChangeStorage( CPlayer* thisclient, CPacket* P)
  4. {
  5.     BYTE action = GETBYTE((*P),0);
  6.     switch(action)
  7.     {
  8.         case 0x00: //Deposit
  9.         {
  10.             int itemslot = (int)GETBYTE((*P),1);
  11.             if(!CheckInventorySlot( thisclient, itemslot ))
  12.                 return false;
  13.             CItem newitem = thisclient->items[itemslot];
  14.             // find an empty or matching slot depending on new item type
  15.             int newslot = thisclient->GetNewStorageItemSlot ( newitem );
  16.             if(newslot==0xffff)
  17.                     return true;  
  18.             if(thisclient->storageitems[newslot].count != 0) // already something in this slot
  19.             {
  20.                 if(newitem.itemtype == 10 || newitem.itemtype == 11 || newitem.itemtype == 12) //is it a stackable type
  21.                 {
  22.                     //stackable item
  23.                     if(newitem.itemtype != thisclient->storageitems[newslot].itemtype || newitem.itemnum != thisclient->storageitems[newslot].itemnum)
  24.                         return true;  // better kick out so it doesn't overwrite something
  25.                     // by now we know that the items in this slot are the same as the ones we want to deposit so add them together
  26.                     int count = (int)GETWORD((*P),6);
  27.                     if(count > thisclient->items[itemslot].count)
  28.                         count = thisclient->items[itemslot].count; //stops players transferring more than they actually have
  29.                     thisclient->storageitems[newslot].count += count; //add the new items to the storage slot
  30.                     thisclient->items[itemslot].count -= count; //delete the items from inventory slot
  31.                     if(thisclient->items[itemslot].count <= 0)
  32.                         ClearItem(thisclient->items[itemslot]);
  33.                 }
  34.                 else // not stackable
  35.                     return true;  // better kick out so it doesn't overwrite something
  36.             }    
  37.             else // slot is empty
  38.             {
  39.                 if(newitem.itemtype == 10 || newitem.itemtype == 11 || newitem.itemtype == 12) //is it a stackable type
  40.                 {
  41.                     //stackable item to make a new stack
  42.                     int count = (int)GETWORD((*P),6);
  43.                     if(count > thisclient->items[itemslot].count)
  44.                         count = thisclient->items[itemslot].count; //stops players transferring more than they actually have
  45.                     thisclient->storageitems[newslot] = newitem; //add the new items to the storage slot
  46.                     thisclient->storageitems[newslot].count = count; //make sure the count is right
  47.                     thisclient->items[itemslot].count -= count; //delete the items from inventory slot
  48.                     if(thisclient->items[itemslot].count <= 0)
  49.                         ClearItem(thisclient->items[itemslot]);
  50.                 }
  51.                 else
  52.                 {
  53.                     // non-stackable
  54.                     ClearItem(thisclient->items[itemslot]);
  55.                     thisclient->storageitems[newslot] = newitem;  
  56.                 }            
  57.             }  
  58.             BEGINPACKET( pak, 0x7ae );
  59.             ADDWORD    ( pak, itemslot );
  60.             ADDWORD    ( pak, newslot );        
  61.             ADDDWORD   ( pak, BuildItemHead( thisclient->items[itemslot] ) );
  62.             ADDDWORD   ( pak, BuildItemData( thisclient->items[itemslot] ) );
  63.             ADDDWORD   ( pak, BuildItemHead( thisclient->storageitems[newslot] ) );
  64.             ADDDWORD   ( pak, BuildItemData( thisclient->storageitems[newslot] ) );
  65.             ADDQWORD   ( pak, thisclient->CharInfo->Zulies );
  66.             thisclient->client->SendPacket( &pak );
  67.             //thisclient->nstorageitems++;  //this is pointless and serves no purpose          
  68.         }
  69.         break;//thanks to anon for post that this break was missing
  70.         case 0x01: //Withdraw
  71.         {            
  72.             BYTE storageslot = GETBYTE((*P),1);            
  73.             if(storageslot>=160)
  74.             {
  75.                 Log( MSG_HACK, "Invalid storage slot %i from %s", storageslot, thisclient->Session->username );
  76.                 return false;
  77.             }
  78.             CItem newitem =  newitem = thisclient->storageitems[storageslot];                  
  79.             if(newitem.itemtype>9 && newitem.itemtype<14)
  80.             {
  81.                 WORD count = GETWORD((*P),6);                
  82.                 if( count>thisclient->storageitems[storageslot].count )
  83.                     count = thisclient->storageitems[storageslot].count;
  84.                 newitem.count = count;
  85.                 thisclient->storageitems[storageslot].count -= count;
  86.                 if(thisclient->storageitems[storageslot].count<=0)
  87.                     ClearItem(thisclient->storageitems[storageslot]);
  88.             }    
  89.             else
  90.             {
  91.                 ClearItem(thisclient->storageitems[storageslot]);                
  92.             }                            
  93.             int newslot= thisclient->GetNewItemSlot ( newitem );
  94.             if(newslot==0xffff)
  95.             {
  96.                 thisclient->storageitems[storageslot] = newitem;
  97.                 return true;
  98.             }
  99.                            
  100.             int amount = 0;
  101.             if(thisclient->items[newslot].count>0)                
  102.             {
  103.               int amount = thisclient->items[newslot].count;                    
  104.               newitem.count+=amount;
  105.             }
  106.             if( newitem.count > 999 )
  107.             {
  108.                 amount = 999 - newitem.count;
  109.                 newitem.count = 999;                        
  110.             }        
  111.             thisclient->items[newslot] = newitem;  
  112.             if( amount > 0 )
  113.             {
  114.                 newitem.count = amount;
  115.                 unsigned int newslot2 = thisclient->GetNewItemSlot( newitem );
  116.                 if( newslot2 == 0xffff )
  117.                 {
  118.                     thisclient->storageitems[storageslot] = thisclient->items[newslot];
  119.                     thisclient->items[newslot].count = amount;
  120.                     return true;
  121.                 }
  122.                 thisclient->items[newslot2] = newitem;
  123.                 thisclient->UpdateInventory( newslot2 );    
  124.             }                                                                                    
  125.             BEGINPACKET( pak, 0x7ae );
  126.             ADDWORD    ( pak, newslot );
  127.             ADDWORD    ( pak, storageslot );
  128.             ADDDWORD   ( pak, BuildItemHead( thisclient->items[newslot] ) );
  129.             ADDDWORD   ( pak, BuildItemData( thisclient->items[newslot] ) );
  130.             ADDDWORD   ( pak, BuildItemHead( thisclient->storageitems[storageslot] ) );
  131.             ADDDWORD   ( pak, BuildItemData( thisclient->storageitems[storageslot] ) );
  132.             ADDQWORD   ( pak, thisclient->CharInfo->Zulies );
  133.             ADDBYTE    ( pak, 0x00 );          
  134.             thisclient->client->SendPacket( &pak );            
  135.             //thisclient->nstorageitems--; //this is pointless and serves no purpose                          
  136.         }        
  137.         break;
  138.         default:
  139.             Log( MSG_INFO, "Storage unknow action: %i ", action);            
  140.     }
  141.     return true;
  142. }

Notice that i have removed the bit that adds or subtracts a value from thisclient->nstorageitems.
There is a very good reason for that.
It didn't work anyway.
It was incrementing or decrementing the value each time you added or removed a partial stack so it was getting pretty screwed up anyway.
However we can't lose the value completely as it is used in a packet 0x7ad in PakStorage.
So we have to add a new function to count it up for us :D

we will call it unsigned int CPlayer::Getnstorageitems( CPlayer* thisclient )
find
  1. // Returns a free slot in the storage (0xffff if is full)
  2. UINT CPlayer::GetNewStorageItemSlot( CItem thisitem )
again
BEFORE, add
  1.  
  2. //count storage items
  3. unsigned int CPlayer::Getnstorageitems( CPlayer* thisclient )
  4. {
  5.     UINT count = 0;
  6.     for(UINT i=0;i<160;i++)
  7.     {
  8.         if(thisclient->storageitems[i].count > 0)
  9.             count++;
  10.     }
  11.     return count;    
  12. }

And we had better also add this in Player.h
find
  1.  
  2. unsigned int AddItem( CItem item );
  3.  

after add
  1.  
  2. unsigned int Getnstorageitems( CPlayer* thisclient );
  3.  

Finally we need to put in a call to this new function in the place that we actually need it.
in WorldPackets.cpp
find
  1.  
  2.             BEGINPACKET( pak, 0x7ad );
  3.             ADDBYTE    ( pak, 0x00 );
  4.             ADDBYTE    ( pak, thisclient->nstorageitems ); //numero de items
  5.  

Replace with
  1.  
  2.             UINT nstorageitems = thisclient->Getnstorageitems(thisclient);
  3.             BEGINPACKET( pak, 0x7ad );
  4.             ADDBYTE    ( pak, 0x00 );            
  5.             ADDBYTE    ( pak, nstorageitems ); //numero de items
  6.  


Modifications included in [rev 43]
Need to lookup information on NARose items, skills, quests?
Now featuring a newly completed skill tree for all classes
Formatting fixed for different resolutions
Image

"A Gazelle is nothing but a giraffe plotted logarithmicaly"
User avatar
PurpleYouko
Rose Guru
Rose Guru
 
Posts: 4733
Joined: Fri Aug 10, 2007 2:05 pm

Re: Storage stacking fix

Postby wtfux on Mon May 19, 2008 6:10 pm

:?
Didn't noticed that, though I already used storage.
Thx for the fix :).
No.sig
wtfux
Pomic
Pomic
 
Posts: 130
Joined: Sun Apr 13, 2008 2:35 pm

Re: Storage stacking fix

Postby PurpleYouko on Mon May 19, 2008 8:07 pm

There is another bug with storage somewhere as well but i haven't tracked it down fully yet.

one of my testers has 147 items in storage and now his client locks up when he tries to open storage.
I have tested on his account and he is right. It just completely locks when you select the storage option from the NPC.

Not entirely sure why yet but i suspect it might have something to do with maximum storage capacity being different with osprose.
I really can't remember how many items you could store back then but it does seem kind of weird if it would be less than either irose or evo.
Need to lookup information on NARose items, skills, quests?
Now featuring a newly completed skill tree for all classes
Formatting fixed for different resolutions
Image

"A Gazelle is nothing but a giraffe plotted logarithmicaly"
User avatar
PurpleYouko
Rose Guru
Rose Guru
 
Posts: 4733
Joined: Fri Aug 10, 2007 2:05 pm


Return to Submit Code

Who is online

Users browsing this forum: No registered users and 7 guests