All pastes #1719278 Raw Edit

Mine

public text v1 · immutable
#1719278 ·published 2009-12-18 10:09 UTC
rendered paste body
Index: src/server/psserverchar.cpp
===================================================================
--- src/server/psserverchar.cpp	(revision 4983)
+++ src/server/psserverchar.cpp	(working copy)
@@ -24,6 +24,7 @@
 #include <iutil/databuff.h>
 #include <iutil/object.h>
 #include <csutil/csstring.h>
+#include <csutil/list.h>
 
 //=============================================================================
 // Project Includes
@@ -743,94 +744,153 @@
             if (count <= 0) return;
         }
 
+        csList<psItem *> newitem;
+        bool error = false;
         // if item is to be personalised, then duplicate the item_stats and personalise
         // by given it a unique name for the purchaser.
-        psItem* newitem;
         if (item->GetBuyPersonalise())
         {
-            // only 1 personalised thing can be bought at a time
-            if (count != 1)
+            for (int i = 0; i < count; i++)
             {
-                psserver->SendSystemError(client->GetClientNum(),"You can only purchase 1 Personalised thing at a time!");
-                return;
-            }
+                // copy 'item' item_stats to create unique item...
+                // personalised name is "<item> of <purchaser>"
+                // If "<item> of <purchaser>" already exists, add " (<number>)" (being the row count+1 of item_stats)
+                // if item is 'public', then name is "<item> (<number>)"
+                psItem * newpersonaliseditem;
+                PSITEMSTATS_CREATORSTATUS creatorStatus;
+                item->GetBaseStats()->GetCreator(creatorStatus);
+                csString itemName(item->GetName());
+                if (creatorStatus != PSITEMSTATS_CREATOR_PUBLIC)
+                    itemName.AppendFmt(" of %s", client->GetName());
 
-            // copy 'item' item_stats to create unique item...
-            // personalised name is "<item> of <purchaser>"
-            // If "<item> of <purchaser>" already exists, add " (<number>)" (being the row count+1 of item_stats)
-            // if item is 'public', then name is "<item> (<number>)"
-            csString personalisedName(item->GetName());
-            PSITEMSTATS_CREATORSTATUS creatorStatus;
-            item->GetBaseStats()->GetCreator(creatorStatus);
-            if (creatorStatus == PSITEMSTATS_CREATOR_PUBLIC)
-            {
-                personalisedName.AppendFmt(" (%zu)", CacheManager::GetSingleton().ItemStatsSize()+1);
-            }
-            else
-            {
-                personalisedName.AppendFmt(" of %s", client->GetName());
-                if (CacheManager::GetSingleton().BasicItemStatsByNameExist(personalisedName) > 0)
-                    personalisedName.AppendFmt(" (%zu)", CacheManager::GetSingleton().ItemStatsSize()+1);
-            }
+                csString personalisedName(itemName);
 
-            psItemStats* newCreation = CacheManager::GetSingleton().CopyItemStats(item->GetBaseStats()->GetUID(),
+                for(int i = 1; CacheManager::GetSingleton().BasicItemStatsByNameExist(personalisedName) > 0; i++)
+                {
+                    personalisedName = itemName;
+                    personalisedName.AppendFmt(" (%zu)", CacheManager::GetSingleton().ItemStatsSize()+i);
+                }
+
+                psItemStats * newCreation = CacheManager::GetSingleton().CopyItemStats(item->GetBaseStats()->GetUID(),
                                                                                   personalisedName);
 
-            if (!newCreation)
-               return;
+                if (!newCreation)
+                {
+                    error = true;
+                    break;
+                }
 
-            newCreation->SetUnique();
+                newCreation->SetUnique();
 
-            newCreation->Save();
+                newCreation->Save();
 
-            // instantiate it
-            newitem = newCreation->InstantiateBasicItem();
-            if (newitem)
-               newitem->SetLoaded();
+                // instantiate it
+                newpersonaliseditem = newCreation->InstantiateBasicItem();
+
+                if (!newpersonaliseditem)
+                {
+                    error = true;
+                    break;
+                }
+
+                newpersonaliseditem->SetLoaded();
+                newitem.PushBack(newpersonaliseditem);
+            }
         }
         else // normal purchase
         {
-            newitem = item->Copy(count);
+            int maxcount = MAX_STACK_COUNT;
+            if (item->GetIsContainer())
+                maxcount = 1;
+
+            // split it into several stacks if it doesn't fit into a single one
+            for (int i = 0; i < count/maxcount && !error; i++)
+                if(!*newitem.PushBack(item->Copy(MAX_STACK_COUNT)))
+                    error = true;
+
+            if(!error && count % maxcount)
+                newitem.PushBack(item->Copy(count % maxcount));
         }
 
-        if (newitem == NULL)
+        csList<psBuyEvent> buyevents;
+        psMoney cost;
+        int newcount = 0; // count what we really got
+
+        if (!error)
         {
-            Error2("Error: failed to create item %s.", itemName.GetData());
-            psserver->SendSystemError(client->GetClientNum(), "Error: failed to create item %s.", itemName.GetData());
-            return;
+            for (csList<psItem *>::Iterator newitemitr(newitem); newitemitr.HasNext(); )
+            {
+                psItem *& currentitem = newitemitr.Next();
+                if (!currentitem)
+                    break;
+    
+                bool stackable = currentitem->GetBaseStats()->GetIsStackable();
+    
+                // we have to get the count of it before stacking it up
+                int partcount = 1;
+                if (stackable)
+                    partcount = currentitem->GetStackCount();
+    
+                if (character->Inventory().Add(currentitem, false, stackable))
+                {
+                    newcount += partcount;
+                    psMoney partcost;
+                    partcost = (price * partcount).Normalized();
+                    cost += partcost;
+    
+                    psBuyEvent evt(
+                        character->GetPID(),
+                        merchant->GetPID(),
+                        currentitem->GetUID(),
+                        partcount,
+                        (int)currentitem->GetCurrentStats()->GetQuality(),
+                        partcost.GetTotal()
+                        );
+                    buyevents.PushBack(evt);
+                }
+                else
+                {
+                    // No empty or stackable slot in bulk or any container
+                    break;
+                }
+            }
         }
-        // If we managed to buy some items, we pay some money
 
-        bool stackable = newitem->GetBaseStats()->GetIsStackable();
-
-        if (character->Inventory().Add(newitem, false, stackable))
+        if (newcount != count) // not enough empty or stackable slots
         {
-            psMoney cost;
-            cost = (price * count).Normalized();
+            if (error)
+            {
+                Error2("Error: failed to create item %s.", itemName.GetData());
+                psserver->SendSystemError(client->GetClientNum(), "Error: failed to create item %s.", itemName.GetData());
+            }
+            else
+            {
+                psserver->SendSystemError(client->GetClientNum(),"You're carrying too many items");
+            }
 
-            character->SetMoney(money - cost);
 
-            psserver->SendSystemOK( client->GetClientNum(), "You bought %d %s for %s a total of %d Trias.",
-                count, itemName.GetData(), cost.ToUserString().GetDataSafe(),cost.GetTotal());
+            // destroy the created items
+            for (csList<psItem *>::Iterator newitemitr(newitem); newitemitr.HasNext(); )
+            {
+                psItem * currentitem = newitemitr.Next();
+                if (!currentitem)
+                    continue;
+                character->Inventory().RemoveItemID(currentitem->GetUID());
+                CacheManager::GetSingleton().RemoveInstance(currentitem);
+            }
 
-            psBuyEvent evt(
-                character->GetPID(),
-                merchant->GetPID(),
-                item->GetUID(),
-                count,
-                (int)item->GetCurrentStats()->GetQuality(),
-                cost.GetTotal()
-                );
-            evt.FireEvent();
-        }
-        else
-        {
-            // No empty or stackable slot in bulk or any container
-            psserver->SendSystemError(client->GetClientNum(),"You're carrying too many items");
-            CacheManager::GetSingleton().RemoveInstance(newitem);
             return;
         }
 
+        // If we managed to buy some items, we pay some money
+        character->SetMoney(money - cost);
+
+        psserver->SendSystemOK( client->GetClientNum(), "You bought %d %s for %s a total of %d Trias.",
+            count, itemName.GetData(), cost.ToUserString().GetDataSafe(),cost.GetTotal());
+
+        for (csList<psBuyEvent>::Iterator buyeventsitr(buyevents); buyeventsitr.HasNext(); )
+            buyeventsitr.Next().FireEvent();
+
         // Update client views
         SendPlayerMoney( client );
         SendMerchantItems( client, merchant, item->GetCategory() );