From 22f79fd0d623c8e11994905534f53da267e22935 Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Thu, 3 Mar 2011 01:25:21 +0200
Subject: Dehardcode item colors. Now reading all from configs.

---
 src/actorsprite.cpp                |  4 +--
 src/flooritem.cpp                  |  2 +-
 src/gui/charcreatedialog.cpp       |  8 ++---
 src/item.cpp                       |  4 +--
 src/net/manaserv/beinghandler.cpp  |  4 +--
 src/net/manaserv/charhandler.cpp   |  2 +-
 src/net/tmwa/beinghandler.cpp      |  6 ++--
 src/net/tmwa/charserverhandler.cpp |  2 +-
 src/resources/colordb.cpp          | 74 ++++++++++++++++++++++++++++++++------
 src/resources/colordb.h            | 32 +++++++++++++++--
 src/resources/itemdb.cpp           |  2 ++
 src/resources/iteminfo.cpp         | 36 +++++++++----------
 src/resources/iteminfo.h           | 12 ++++++-
 src/utils/stringutils.cpp          | 41 +++++++++++++++++++++
 src/utils/stringutils.h            |  5 +++
 15 files changed, 186 insertions(+), 48 deletions(-)

(limited to 'src')

diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp
index 4188ff224..686c871e7 100644
--- a/src/actorsprite.cpp
+++ b/src/actorsprite.cpp
@@ -312,7 +312,7 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
          it != it_end; ++it)
     {
         std::string file = "graphics/sprites/"
-            + combineDye((*it)->sprite, color);
+            + combineDye2((*it)->sprite, color);
 
         int variant = (*it)->variant;
         addSprite(AnimatedSprite::load(file, variant));
@@ -339,7 +339,7 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
                     imagePath = "graphics/items/" + display.floor;
                     break;
             }
-            imagePath = combineDye(imagePath, color);
+            imagePath = combineDye2(imagePath, color);
 
             Image *img = resman->getImage(imagePath);
 
diff --git a/src/flooritem.cpp b/src/flooritem.cpp
index 700d9ed25..740daf387 100644
--- a/src/flooritem.cpp
+++ b/src/flooritem.cpp
@@ -72,7 +72,7 @@ FloorItem::FloorItem(int id,
     }
 
     ItemInfo info = ItemDB::get(itemId);
-    setupSpriteDisplay(info.getDisplay(), true, 1, info.getDyeString(mColor));
+    setupSpriteDisplay(info.getDisplay(), true, 1, info.getDyeColorsString(mColor));
 }
 
 const ItemInfo &FloorItem::getInfo() const
diff --git a/src/gui/charcreatedialog.cpp b/src/gui/charcreatedialog.cpp
index dff591dd9..ae4401572 100644
--- a/src/gui/charcreatedialog.cpp
+++ b/src/gui/charcreatedialog.cpp
@@ -58,7 +58,7 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot):
     mPlayer = new Being(0, ActorSprite::PLAYER, 0, NULL);
     mPlayer->setGender(GENDER_MALE);
 
-    int numberOfHairColors = ColorDB::size();
+    int numberOfHairColors = ColorDB::getHairSize();
 
     mHairStyle = rand() % mPlayer->getNumOfHairstyles();
     mHairColor = rand() % numberOfHairColors;
@@ -364,10 +364,10 @@ void CharCreateDialog::updateHair()
     if (mHairStyle < 0)
         mHairStyle += Being::getNumOfHairstyles();
 
-    mHairColor %= ColorDB::size();
+    mHairColor %= ColorDB::getHairSize();
     if (mHairColor < 0)
-        mHairColor += ColorDB::size();
+        mHairColor += ColorDB::getHairSize();
 
     mPlayer->setSprite(Net::getCharHandler()->hairSprite(),
-                       mHairStyle * -1, ColorDB::get(mHairColor));
+                       mHairStyle * -1, ColorDB::getHairColor(mHairColor));
 }
diff --git a/src/item.cpp b/src/item.cpp
index 02f775834..ed0685a9d 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -75,7 +75,7 @@ void Item::setId(int id, unsigned char color)
     SpriteDisplay display = info.getDisplay();
     std::string imagePath = paths.getStringValue("itemIcons")
                             + display.image;
-    std::string dye = combineDye(imagePath, info.getDyeString(color));
+    std::string dye = combineDye2(imagePath, info.getDyeColorsString(color));
     mImage = resman->getImage(dye);
     mDrawImage = resman->getImage(dye);
 
@@ -106,7 +106,7 @@ Image *Item::getImage(int id, unsigned char color)
     SpriteDisplay display = info.getDisplay();
     std::string imagePath = "graphics/items/" + display.image;
     Image *image;
-    image = resman->getImage(combineDye(imagePath, info.getDyeString(color)));
+    image = resman->getImage(combineDye2(imagePath, info.getDyeColorsString(color)));
 
     if (!image)
         image = Theme::getImageFromTheme("unknown-item.png");
diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp
index 8ba2e5967..b726bc52e 100644
--- a/src/net/manaserv/beinghandler.cpp
+++ b/src/net/manaserv/beinghandler.cpp
@@ -185,7 +185,7 @@ void BeingHandler::handleBeingEnterMessage(Net::MessageIn &msg)
                 being->setName(name);
             }
             int hs = msg.readInt8(), hc = msg.readInt8();
-            being->setSprite(SPRITE_HAIR, hs * -1, ColorDB::get(hc));
+            being->setSprite(SPRITE_HAIR, hs * -1, ColorDB::getHairColor(hc));
             being->setGender(msg.readInt8() == GENDER_MALE ?
                              GENDER_MALE : GENDER_FEMALE);
             handleLooks(being, msg);
@@ -350,7 +350,7 @@ void BeingHandler::handleBeingLooksChangeMessage(Net::MessageIn &msg)
     {
         int style = msg.readInt16();
         int color = msg.readInt16();
-        being->setSprite(SPRITE_HAIR, style * -1, ColorDB::get(color));
+        being->setSprite(SPRITE_HAIR, style * -1, ColorDB::getHairColor(color));
     }
 }
 
diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp
index 20dda5b70..163aad988 100644
--- a/src/net/manaserv/charhandler.cpp
+++ b/src/net/manaserv/charhandler.cpp
@@ -377,7 +377,7 @@ void CharHandler::updateCharacters()
         player->setName(info.name);
         player->setGender(info.gender);
         player->setSprite(SPRITE_HAIR, info.hairStyle * -1,
-                          ColorDB::get(info.hairColor));
+                          ColorDB::getHairColor(info.hairColor));
         character->data.mAttributes[LEVEL] = info.level;
         character->data.mAttributes[CHAR_POINTS] = info.characterPoints;
         character->data.mAttributes[CORR_POINTS] = info.correctionPoints;
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 0548a2715..b1c173df6 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -290,7 +290,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
                                     ? GENDER_FEMALE : GENDER_MALE);
                 // Set these after the gender, as the sprites may be gender-specific
                 dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1,
-                                    ColorDB::get(hairColor));
+                                    ColorDB::getHairColor(hairColor));
                 dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, headBottom);
                 dstBeing->setSprite(SPRITE_TOPCLOTHES, headMid);
                 dstBeing->setSprite(SPRITE_HAT, headTop);
@@ -671,7 +671,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
                     player_node->imitateOutfit(dstBeing, SPRITE_TOPCLOTHES);
                     break;
                 case 6:     // eAthena LOOK_HAIR_COLOR
-                    dstBeing->setSpriteColor(SPRITE_HAIR, ColorDB::get(id));
+                    dstBeing->setSpriteColor(SPRITE_HAIR, ColorDB::getHairColor(id));
                     break;
                 case 8:     // eAthena LOOK_SHIELD
                     if (!config.getBoolValue("hideShield"))
@@ -927,7 +927,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
             //dstBeing->setSprite(SPRITE_MISC1, misc1);
             //dstBeing->setSprite(SPRITE_MISC2, misc2);
             dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1,
-                                ColorDB::get(hairColor));
+                                ColorDB::getHairColor(hairColor));
 
             player_node->imitateOutfit(dstBeing);
 
diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp
index 35cca6f07..daf531f04 100644
--- a/src/net/tmwa/charserverhandler.cpp
+++ b/src/net/tmwa/charserverhandler.cpp
@@ -309,7 +309,7 @@ void CharServerHandler::readPlayerData(Net::MessageIn &msg,
     int topClothes = msg.readInt16();
 
     tempPlayer->setSprite(SPRITE_HAIR, hairStyle * -1,
-        ColorDB::get(msg.readInt16()));
+        ColorDB::getHairColor(msg.readInt16()));
 
     int misc2 = msg.readInt16();
     tempPlayer->setName(msg.readString(24));
diff --git a/src/resources/colordb.cpp b/src/resources/colordb.cpp
index c35cec95e..79622e8ed 100644
--- a/src/resources/colordb.cpp
+++ b/src/resources/colordb.cpp
@@ -28,9 +28,10 @@
 
 namespace
 {
-    ColorDB::Colors mColors;
+    ColorDB::Colors mHairColors;
     bool mLoaded = false;
     std::string mFail = "#ffffff";
+    ColorDB::ColorLists mColorLists;
 }
 
 void ColorDB::load()
@@ -38,6 +39,12 @@ void ColorDB::load()
     if (mLoaded)
         unload();
 
+    loadHair();
+    loadColorLists();
+}
+
+void ColorDB::loadHair()
+{
     XML::Document *doc = new XML::Document("hair.xml");
     xmlNodePtr root = doc->rootNode();
     bool hairXml = true;
@@ -55,7 +62,7 @@ void ColorDB::load()
         if (!root || !xmlStrEqual(root->name, BAD_CAST "colors"))
         {
             logger->log1("ColorDB: Failed to find any color files.");
-            mColors[0] = mFail;
+            mHairColors[0] = mFail;
             mLoaded = true;
 
             delete doc;
@@ -69,10 +76,10 @@ void ColorDB::load()
         {
             int id = XML::getProperty(node, "id", 0);
 
-            if (mColors.find(id) != mColors.end())
+            if (mHairColors.find(id) != mHairColors.end())
                 logger->log("ColorDB: Redefinition of dye ID %d", id);
 
-            mColors[id] = hairXml ?
+            mHairColors[id] = hairXml ?
                 XML::getProperty(node, "value", "#FFFFFF") :
                 XML::getProperty(node, "dye", "#FFFFFF");
         }
@@ -83,22 +90,59 @@ void ColorDB::load()
     mLoaded = true;
 }
 
+void ColorDB::loadColorLists()
+{
+    XML::Document *doc = new XML::Document("itemcolors.xml");
+    xmlNodePtr root = doc->rootNode();
+    if (!root)
+        return;
+
+    for_each_xml_child_node(node, root)
+    {
+        if (xmlStrEqual(node->name, BAD_CAST "list"))
+        {
+            std::string name = XML::getProperty(node, "name", "");
+            if (name.empty())
+                continue;
+
+            std::map <int, ItemColor> colors;
+            ColorListsIterator it = mColorLists.find(name);
+
+            if (it != mColorLists.end())
+                colors = it->second;
+
+            for_each_xml_child_node(colorNode, node)
+            {
+                if (xmlStrEqual(colorNode->name, BAD_CAST "color"))
+                {
+                    ItemColor c(XML::getProperty(colorNode, "id", -1),
+                        XML::getProperty(colorNode, "name", ""),
+                        XML::getProperty(colorNode, "value", ""));
+                    if (c.id > -1)
+                        colors[c.id] = c;
+                }
+            }
+            mColorLists[name] = colors;
+        }
+    }
+}
+
 void ColorDB::unload()
 {
     logger->log1("Unloading color database...");
 
-    mColors.clear();
+    mHairColors.clear();
     mLoaded = false;
 }
 
-std::string &ColorDB::get(int id)
+std::string &ColorDB::getHairColor(int id)
 {
     if (!mLoaded)
         load();
 
-    ColorIterator i = mColors.find(id);
+    ColorIterator i = mHairColors.find(id);
 
-    if (i == mColors.end())
+    if (i == mHairColors.end())
     {
         logger->log("ColorDB: Error, unknown dye ID# %d", id);
         return mFail;
@@ -109,7 +153,17 @@ std::string &ColorDB::get(int id)
     }
 }
 
-int ColorDB::size()
+int ColorDB::getHairSize()
 {
-    return static_cast<int>(mColors.size());
+    return static_cast<int>(mHairColors.size());
+}
+
+std::map <int, ColorDB::ItemColor> *ColorDB::getColorsList(std::string name)
+{
+    std::map <int, ItemColor> colors;
+    ColorListsIterator it = mColorLists.find(name);
+
+    if (it != mColorLists.end())
+        return &it->second;
+    return 0;
 }
diff --git a/src/resources/colordb.h b/src/resources/colordb.h
index 72d34afe8..fb0da0036 100644
--- a/src/resources/colordb.h
+++ b/src/resources/colordb.h
@@ -29,23 +29,51 @@
  */
 namespace ColorDB
 {
+    class ItemColor
+    {
+        public:
+            ItemColor()
+            { }
+            ItemColor(int id, std::string name, std::string color)
+            {
+                this->id = id;
+                this->name = name;
+                this->color = color;
+            }
+
+            int id;
+            std::string name;
+            std::string color;
+    };
+
     /**
      * Loads the color data from <code>colors.xml</code>.
      */
     void load();
 
+    /**
+     * Loads the color data from <code>colors.xml</code>.
+     */
+    void loadHair();
+
+    void loadColorLists();
+
     /**
      * Clear the color data
      */
     void unload();
 
-    std::string &get(int id);
+    std::string &getHairColor(int id);
+
+    int getHairSize();
 
-    int size();
+    std::map <int, ItemColor> *getColorsList(std::string name);
 
     // Color DB
     typedef std::map<int, std::string> Colors;
     typedef Colors::iterator ColorIterator;
+    typedef std::map <std::string, std::map <int, ItemColor> > ColorLists;
+    typedef ColorLists::iterator ColorListsIterator;
 }
 
 #endif
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 418bfb848..d515495de 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -207,6 +207,7 @@ 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 colors = XML::getProperty(node, "colors", "");
 
         std::string tags[3];
         tags[0] = XML::getProperty(node, "tag",
@@ -266,6 +267,7 @@ void ItemDB::load()
         itemInfo->setDrawBefore(parseSpriteName(drawBefore));
         itemInfo->setDrawAfter(parseSpriteName(drawAfter));
         itemInfo->setDrawPriority(drawPriority);
+        itemInfo->setColorsList(colors);
 
         std::string effect;
         for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i)
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index 49aadc23d..990c78f45 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -82,30 +82,28 @@ std::map<int, int> &ItemInfo::addReplaceSprite(int sprite)
     return it->second;
 }
 
-std::string ItemInfo::getDyeString(int color) const
+void ItemInfo::setColorsList(std::string name)
 {
-    if (mId == 1172)
+    if (name.empty())
     {
-        if (color == 1)
-            return "W:#115511,22aa22,99dd99;R:#547000,a5dc00,d1ff46";
-        if (color == 0)
-            return "W:#547000,a5dc00,d1ff46;R:#115511,22aa22,99dd99";
-        if (color == 3)
-            return "W:#ffffff,000000,000000;R:#333333,333333,333333";
+        mColors = 0;
+        mColorList = "";
+    }
+    else
+    {
+        mColors = ColorDB::getColorsList(name);
+        mColorList = name;
     }
-    return "";
 }
 
 std::string ItemInfo::getDyeColorsString(int color) const
 {
-    if (mId == 1172)
-    {
-        if (color == 1)
-            return "#115511,22aa22,99dd99;#547000,a5dc00,d1ff46";
-        if (color == 0)
-            return "#547000,a5dc00,d1ff46;#115511,22aa22,99dd99";
-        if (color == 3)
-            return "#ffffff,000000,000000;#333333,333333,333333";
-    }
-    return "";
+    if (!mColors || mColorList.empty())
+        return "";
+
+    std::map <int, ColorDB::ItemColor>::iterator it = mColors->find(color);
+    if (it == mColors->end())
+        return "";
+
+    return it->second.color;
 }
\ No newline at end of file
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index 3b72c7830..297c1b036 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -25,6 +25,7 @@
 
 #include "being.h"
 
+#include "resources/colordb.h"
 #include "resources/spritedef.h"
 
 #include <map>
@@ -111,7 +112,9 @@ class ItemInfo
             mDrawPriority(0),
             mIsRemoveSprites(false),
             mAttackAction(SpriteAction::INVALID),
-            mAttackRange(0)
+            mAttackRange(0),
+            mColors(0),
+            mColorList("")
         {
         }
 
@@ -235,6 +238,11 @@ class ItemInfo
 
         std::string getDyeColorsString(int color) const;
 
+        void setColorsList(std::string name);
+
+        bool isHaveColors()
+        { return !mColorList.empty(); }
+
     protected:
         SpriteDisplay mDisplay;     /**< Display info (like icon) */
         std::string mName;
@@ -269,6 +277,8 @@ class ItemInfo
         /** Stores the names of sounds to be played at certain event. */
         std::map < EquipmentSoundEvent, std::vector<std::string> > mSounds;
         std::map <int, int> mTags;
+        std::map <int, ColorDB::ItemColor> *mColors;
+        std::string mColorList;
 };
 
 #endif
diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp
index 835f9ce00..63924eb78 100644
--- a/src/utils/stringutils.cpp
+++ b/src/utils/stringutils.cpp
@@ -388,6 +388,19 @@ std::list<int> splitToIntList(const std::string &text, char separator)
     return tokens;
 }
 
+
+std::list<std::string> splitToStringList(const std::string &text,
+                                         char separator)
+{
+    std::list<std::string> tokens;
+    std::stringstream ss(text);
+    std::string item;
+    while(std::getline(ss, item, separator))
+        tokens.push_back(item);
+
+    return tokens;
+}
+
 std::string combineDye(std::string file, std::string dye)
 {
     if (dye.empty())
@@ -397,3 +410,31 @@ std::string combineDye(std::string file, std::string dye)
         return file.substr(0, pos) + "|" + dye;
     return file + "|" + dye;
 }
+
+std::string combineDye2(std::string file, std::string dye)
+{
+    if (dye.empty())
+        return file;
+
+    size_t pos = file.find_last_of("|");
+    if (pos != std::string::npos)
+    {
+        std::string dye1 = file.substr(pos + 1);
+        std::string str = "";
+        file = file.substr(0, pos);
+        std::list<std::string> list1 = splitToStringList(dye1, ';');
+        std::list<std::string> list2 = splitToStringList(dye, ';');
+        std::list<std::string>::iterator it1, it1_end = list1.end();
+        std::list<std::string>::iterator it2, it2_end = list2.end();
+        for (it1 = list1.begin(), it2 = list2.begin();
+             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
+        {
+            str += (*it1) + ":" + (*it2) + ";";
+        }
+        return file + "|" + str;
+    }
+    else
+    {
+        return file;
+    }
+}
diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h
index 52b47e6a2..02c25eddb 100644
--- a/src/utils/stringutils.h
+++ b/src/utils/stringutils.h
@@ -170,6 +170,11 @@ std::set<int> splitToIntSet(const std::string &text, char separator);
 
 std::list<int> splitToIntList(const std::string &text, char separator);
 
+std::list<std::string> splitToStringList(const std::string &text,
+                                         char separator);
+
 std::string combineDye(std::string file, std::string dye);
 
+std::string combineDye2(std::string file, std::string dye);
+
 #endif // UTILS_STRINGUTILS_H
-- 
cgit v1.2.3-70-g09d2