From 3805d1384894a33ecb09e4852d47afb04ddb0687 Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Mon, 14 Feb 2011 03:54:55 +0200
Subject: Replace sprites functionality (need support in client data).

---
 src/being.cpp              | 67 ++++++++++++++++++++++++++++++++++++----------
 src/being.h                |  4 ++-
 src/resources/itemdb.cpp   | 26 +++++++++++++++---
 src/resources/iteminfo.cpp | 17 +++++++-----
 src/resources/iteminfo.h   | 29 +++++++++++---------
 src/utils/stringutils.cpp  | 11 ++++++++
 src/utils/stringutils.h    |  2 ++
 7 files changed, 118 insertions(+), 38 deletions(-)

diff --git a/src/being.cpp b/src/being.cpp
index 6d26f74a7..88a923268 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -1483,7 +1483,7 @@ void Being::updateColors()
 }
 
 void Being::setSprite(unsigned int slot, int id, const std::string &color,
-                      bool isWeapon)
+                      bool isWeapon, bool isTempSprite)
 {
     if (slot >= Net::getCharHandler()->maxSprite())
         return;
@@ -1530,9 +1530,12 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color,
         setAction(mAction);
     }
 
-    mSpriteIDs[slot] = id;
-    mSpriteColors[slot] = color;
-    recalcSpritesOrder();
+    if (!isTempSprite)
+    {
+        mSpriteIDs[slot] = id;
+        mSpriteColors[slot] = color;
+        recalcSpritesOrder();
+    }
 }
 
 void Being::setSpriteID(unsigned int slot, int id)
@@ -1702,10 +1705,10 @@ bool Being::draw(Graphics *graphics, int offsetX, int offsetY) const
 
 void Being::drawSprites(Graphics* graphics, int posX, int posY) const
 {
-//    CompoundSprite::drawSprites(graphics, posX, posY);
     for (int f = 0; f < getNumberOfLayers(); f ++)
     {
-        if (mSpriteHide[mSpriteRemap[f]])
+        const int rSprite = mSpriteHide[mSpriteRemap[f]];
+        if (rSprite == 1)
             continue;
 
         Sprite *sprite = getSprite(mSpriteRemap[f]);
@@ -1719,13 +1722,10 @@ void Being::drawSprites(Graphics* graphics, int posX, int posY) const
 
 void Being::drawSpritesSDL(Graphics* graphics, int posX, int posY) const
 {
-//    CompoundSprite::drawSprites(graphics, posX, posY);
-
-//    logger->log("getNumberOfLayers: %d", getNumberOfLayers());
-
     for (unsigned f = 0; f < size(); f ++)
     {
-        if (mSpriteHide[mSpriteRemap[f]])
+        const int rSprite = mSpriteHide[mSpriteRemap[f]];
+        if (rSprite == 1)
             continue;
 
         Sprite *sprite = getSprite(mSpriteRemap[f]);
@@ -1887,9 +1887,13 @@ void Being::recalcSpritesOrder()
 
 //    logger->log("preparation start");
     std::vector<int>::iterator it;
+    int *oldHide = new int[20];
 
     for (unsigned slot = 0; slot < sz; slot ++)
+    {
+        oldHide[slot] = mSpriteHide[slot];
         mSpriteHide[slot] = 0;
+    }
 
     for (unsigned slot = 0; slot < sz; slot ++)
     {
@@ -1900,10 +1904,37 @@ void Being::recalcSpritesOrder()
             continue;
 
         const ItemInfo &info = ItemDB::get(id);
-        if (info.getRemoveSprite() > 0)
+        bool isRemove = false;
+        bool isRemoved = mSpriteHide[slot] != 0 && mSpriteHide[slot] != 1;
+
+        if (info.isRemoveSprites())
         {
-            if (info.isRemoveSpriteId(mSpriteIDs[info.getRemoveSprite()]))
-                mSpriteHide[info.getRemoveSprite()] = 1;
+            std::map<int, std::map<int, int> > spriteToItems
+                = info.getSpriteToItemReplaceMap();
+
+            std::map<int, std::map<int, int> >::iterator it;
+
+            for (it = spriteToItems.begin(); it != spriteToItems.end(); ++it)
+            {
+                int removeSprite = it->first;
+                std::map<int, int> &itemReplacer = it->second;
+                if (itemReplacer.size() == 0)
+                {
+                    mSpriteHide[removeSprite] = 1;
+                }
+                else
+                {
+                    std::map<int, int>::iterator repIt
+                        = itemReplacer.find(mSpriteIDs[removeSprite]);
+                    if (repIt != itemReplacer.end())
+                    {
+                        mSpriteHide[removeSprite] = repIt->second;
+                        setSprite(removeSprite, repIt->second,
+                            mSpriteColors[removeSprite], false, true);
+                    }
+                }
+            }
+
         }
 
         if (info.getDrawBefore() > 0)
@@ -2027,6 +2058,14 @@ void Being::recalcSpritesOrder()
     for (unsigned slot = 0; slot < sz; slot ++)
     {
         mSpriteRemap[slot] = slotRemap[slot];
+        if (oldHide[slot] != 0 && oldHide[slot] != 1 && mSpriteHide[slot] == 0)
+        {
+            int id = mSpriteIDs[slot];
+            if (!id)
+                continue;
+
+            setSprite(slot, id, mSpriteColors[slot], false, true);
+        }
 //        logger->log("slot %d = %d", slot, mSpriteRemap[slot]);
     }
 }
diff --git a/src/being.h b/src/being.h
index db170af30..1dfc9bb4d 100644
--- a/src/being.h
+++ b/src/being.h
@@ -50,6 +50,7 @@
 #define SPEECH_TIME 500
 #define SPEECH_MAX_TIME 1000
 
+class AnimatedSprite;
 class BeingCacheEntry;
 class BeingInfo;
 class FlashText;
@@ -331,7 +332,8 @@ class Being : public ActorSprite, public ConfigListener
          * Sets visible equipments for this being.
          */
         void setSprite(unsigned int slot, int id,
-                       const std::string &color = "", bool isWeapon = false);
+                       const std::string &color = "", bool isWeapon = false,
+                       bool isTempSprite = false);
 
         void setSpriteID(unsigned int slot, int id);
 
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 00987ff9d..ce2ec40a2 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -50,6 +50,7 @@ namespace
 static void loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node);
 static void loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node);
 static void loadFloorSprite(SpriteDisplay *display, xmlNodePtr node);
+static void loadReplaceSprite(ItemInfo *itemInfo, xmlNodePtr replaceNode);
 static int parseSpriteName(std::string &name);
 
 static char const *const fields[][2] =
@@ -205,8 +206,6 @@ void ItemDB::load()
         std::string drawBefore = XML::getProperty(node, "drawBefore", "");
         std::string drawAfter = XML::getProperty(node, "drawAfter", "");
         std::string removeSprite = XML::getProperty(node, "removeSprite", "");
-        std::string removeSpriteIds = XML::getProperty(node, "removeSpriteIds", "");
-        std::set<int> rSprites = splitToIntSet(removeSpriteIds, ',');
 
         std::string tags[3];
         tags[0] = XML::getProperty(node, "tag",
@@ -266,8 +265,6 @@ void ItemDB::load()
         itemInfo->setDrawBefore(parseSpriteName(drawBefore));
         itemInfo->setDrawAfter(parseSpriteName(drawAfter));
         itemInfo->setDrawPriority(drawPriority);
-        itemInfo->setRemoveSprite(parseSpriteName(removeSprite));
-        itemInfo->setRemoveSpriteIds(rSprites);
 
         std::string effect;
         for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i)
@@ -313,6 +310,10 @@ void ItemDB::load()
             {
                 loadFloorSprite(&display, itemChild);
             }
+            else if (xmlStrEqual(itemChild->name, BAD_CAST "replace"))
+            {
+                loadReplaceSprite(itemInfo, itemChild);
+            }
         }
 
         itemInfo->setDisplay(display);
@@ -554,3 +555,20 @@ void loadFloorSprite(SpriteDisplay *display, xmlNodePtr floorNode)
         }
     }
 }
+
+void loadReplaceSprite(ItemInfo *itemInfo, xmlNodePtr replaceNode)
+{
+    std::string removeSprite = XML::getProperty(replaceNode, "sprite", "");
+    std::map<int,int> &mapList = itemInfo->addReplaceSprite(parseSpriteName(removeSprite));
+    itemInfo->setRemoveSprites();
+
+    for_each_xml_child_node(itemNode, replaceNode)
+    {
+        if (xmlStrEqual(itemNode->name, BAD_CAST "item"))
+        {
+            int from = XML::getProperty(itemNode, "from", 0);
+            int to = XML::getProperty(itemNode, "to", 1);
+            mapList[from] = to;
+        }
+    }
+}
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index f65e0396a..c2d3aafef 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -25,6 +25,7 @@
 #include "configuration.h"
 
 #include <set>
+#include <map>
 
 const std::string &ItemInfo::getSprite(Gender gender) const
 {
@@ -67,13 +68,15 @@ const std::string &ItemInfo::getSound(EquipmentSoundEvent event) const
     return i == mSounds.end() ? empty : i->second[rand() % i->second.size()];
 }
 
-bool ItemInfo::isRemoveSpriteId(int id) const
+std::map<int,int> &ItemInfo::addReplaceSprite(int sprite)
 {
-    if (!mRemoveSpriteIds.size()
-        || mRemoveSpriteIds.find(id) != mRemoveSpriteIds.end())
+    std::map<int, std::map<int, int> >::iterator it
+        = mSpriteToItemReplaceMap.find(sprite);
+    if (it == mSpriteToItemReplaceMap.end())
     {
-        return true;
+        std::map<int, int> tmp;
+        mSpriteToItemReplaceMap[sprite] = tmp;
+        it = mSpriteToItemReplaceMap.find(sprite);
     }
-
-    return false;
-}
\ No newline at end of file
+    return it->second;
+}
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index ba7866518..28f4b2e35 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -108,7 +108,7 @@ class ItemInfo
             mDrawBefore(-1),
             mDrawAfter(-1),
             mDrawPriority(0),
-            mRemoveSprite(0),
+            mIsRemoveSprites(false),
             mAttackAction(SpriteAction::INVALID),
             mAttackRange(0)
         {
@@ -209,22 +209,26 @@ class ItemInfo
         void setDrawPriority(int n)
         { mDrawPriority = n; }
 
-        int getRemoveSprite() const
-        { return mRemoveSprite; }
-
-        void setRemoveSprite(int n)
-        { mRemoveSprite = n; }
-
         std::map<int, int> getTags() const
         { return mTags; }
 
         void addTag(int tag)
         { mTags[tag] = 1; }
 
-        void setRemoveSpriteIds(std::set<int> ids)
-        { mRemoveSpriteIds = ids; }
+        void setRemoveSprites()
+        { mIsRemoveSprites = true; }
+
+        bool isRemoveSprites() const
+        { return mIsRemoveSprites; }
+
+        bool isRemoveItemId(int id) const;
+
+        int getReplaceToSpriteId(int id) const;
+
+        std::map<int,int> &addReplaceSprite(int sprite);
 
-        bool isRemoveSpriteId(int id) const;
+        std::map<int, std::map<int, int> > getSpriteToItemReplaceMap() const
+        { return mSpriteToItemReplaceMap; }
 
     protected:
         SpriteDisplay mDisplay;     /**< Display info (like icon) */
@@ -239,8 +243,9 @@ class ItemInfo
         int mDrawBefore;
         int mDrawAfter;
         int mDrawPriority;
-        int mRemoveSprite;
-        std::set<int> mRemoveSpriteIds;
+        bool mIsRemoveSprites;
+        // sprite, <itemfrom, itemto>
+        std::map<int, std::map<int, int> > mSpriteToItemReplaceMap;
 
         // Equipment related members.
         /** Attack type, in case of weapon.
diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp
index 99316ce32..357938fb8 100644
--- a/src/utils/stringutils.cpp
+++ b/src/utils/stringutils.cpp
@@ -375,3 +375,14 @@ std::set<int> splitToIntSet(const std::string &text, char separator)
 
     return tokens;
 }
+
+std::list<int> splitToIntList(const std::string &text, char separator)
+{
+    std::list<int> tokens;
+    std::stringstream ss(text);
+    std::string item;
+    while(std::getline(ss, item, separator))
+        tokens.push_back(atoi(item.c_str()));
+
+    return tokens;
+}
diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h
index 934c0f82d..a69d30914 100644
--- a/src/utils/stringutils.h
+++ b/src/utils/stringutils.h
@@ -167,4 +167,6 @@ std::string normalize(const std::string &name);
 
 std::set<int> splitToIntSet(const std::string &text, char separator);
 
+std::list<int> splitToIntList(const std::string &text, char separator);
+
 #endif // UTILS_STRINGUTILS_H
-- 
cgit v1.2.3-70-g09d2