summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/actorsprite.cpp9
-rw-r--r--src/actorsprite.h3
-rw-r--r--src/actorspritemanager.cpp6
-rw-r--r--src/actorspritemanager.h3
-rw-r--r--src/being.cpp16
-rw-r--r--src/being.h3
-rw-r--r--src/flooritem.cpp9
-rw-r--r--src/flooritem.h4
-rw-r--r--src/gui/outfitwindow.cpp3
-rw-r--r--src/inventory.cpp2
-rw-r--r--src/item.cpp13
-rw-r--r--src/item.h2
-rw-r--r--src/net/manaserv/beinghandler.cpp2
-rw-r--r--src/net/manaserv/buysellhandler.cpp2
-rw-r--r--src/net/manaserv/itemhandler.cpp2
-rw-r--r--src/net/tmwa/beinghandler.cpp29
-rw-r--r--src/net/tmwa/charserverhandler.cpp2
-rw-r--r--src/net/tmwa/inventoryhandler.cpp20
-rw-r--r--src/net/tmwa/itemhandler.cpp6
-rw-r--r--src/resources/iteminfo.cpp28
-rw-r--r--src/resources/iteminfo.h4
-rw-r--r--src/utils/stringutils.cpp10
-rw-r--r--src/utils/stringutils.h2
23 files changed, 128 insertions, 52 deletions
diff --git a/src/actorsprite.cpp b/src/actorsprite.cpp
index fc648741c..4188ff224 100644
--- a/src/actorsprite.cpp
+++ b/src/actorsprite.cpp
@@ -301,7 +301,8 @@ void ActorSprite::handleStatusEffect(StatusEffect *effect, int effectId)
}
void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
- bool forceDisplay, int imageType)
+ bool forceDisplay, int imageType,
+ std::string color)
{
clear();
@@ -310,7 +311,9 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
for (it = display.sprites.begin(), it_end = display.sprites.end();
it != it_end; ++it)
{
- std::string file = "graphics/sprites/" + (*it)->sprite;
+ std::string file = "graphics/sprites/"
+ + combineDye((*it)->sprite, color);
+
int variant = (*it)->variant;
addSprite(AnimatedSprite::load(file, variant));
}
@@ -336,6 +339,8 @@ void ActorSprite::setupSpriteDisplay(const SpriteDisplay &display,
imagePath = "graphics/items/" + display.floor;
break;
}
+ imagePath = combineDye(imagePath, color);
+
Image *img = resman->getImage(imagePath);
if (!img)
diff --git a/src/actorsprite.h b/src/actorsprite.h
index 00b694e26..7ec5cc391 100644
--- a/src/actorsprite.h
+++ b/src/actorsprite.h
@@ -211,7 +211,8 @@ protected:
virtual void handleStatusEffect(StatusEffect *effect, int effectId);
void setupSpriteDisplay(const SpriteDisplay &display,
- bool forceDisplay = true, int imageType = 0);
+ bool forceDisplay = true, int imageType = 0,
+ std::string color = "");
int mId;
Uint16 mStunMode; /**< Stun mode; zero if not stunned */
diff --git a/src/actorspritemanager.cpp b/src/actorspritemanager.cpp
index 0c5cfe04d..03ed09835 100644
--- a/src/actorspritemanager.cpp
+++ b/src/actorspritemanager.cpp
@@ -190,10 +190,10 @@ Being *ActorSpriteManager::createBeing(int id, ActorSprite::Type type,
return being;
}
-FloorItem *ActorSpriteManager::createItem(int id, int itemId,
- int x, int y, int amount)
+FloorItem *ActorSpriteManager::createItem(int id, int itemId, int x, int y,
+ int amount, unsigned char color)
{
- FloorItem *floorItem = new FloorItem(id, itemId, x, y, mMap, amount);
+ FloorItem *floorItem = new FloorItem(id, itemId, x, y, mMap, amount, color);
mActors.insert(floorItem);
return floorItem;
diff --git a/src/actorspritemanager.h b/src/actorspritemanager.h
index 3af157f17..c7deba867 100644
--- a/src/actorspritemanager.h
+++ b/src/actorspritemanager.h
@@ -68,7 +68,8 @@ class ActorSpriteManager: public ConfigListener
/**
* Create a FloorItem and add it to the list of ActorSprites.
*/
- FloorItem *createItem(int id, int itemId, int x, int y, int amount);
+ FloorItem *createItem(int id, int itemId, int x, int y,
+ int amount, unsigned char color);
/**
* Destroys the given ActorSprite at the end of
diff --git a/src/being.cpp b/src/being.cpp
index 7265aa337..2f2e69d16 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -1483,8 +1483,8 @@ void Being::updateColors()
}
}
-void Being::setSprite(unsigned int slot, int id, const std::string &color,
- bool isWeapon, bool isTempSprite)
+void Being::setSprite(unsigned int slot, int id, std::string color,
+ unsigned char colorId, bool isWeapon, bool isTempSprite)
{
if (slot >= Net::getCharHandler()->maxSprite())
return;
@@ -1508,13 +1508,15 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color,
}
else
{
- std::string filename = ItemDB::get(id).getSprite(mGender);
+ ItemInfo info = ItemDB::get(id);
+ std::string filename = info.getSprite(mGender);
AnimatedSprite *equipmentSprite = NULL;
if (!filename.empty())
{
- if (!color.empty())
- filename += "|" + color;
+ if (color.empty())
+ color = info.getDyeColorsString(colorId);
+ filename = combineDye(filename, color);
equipmentSprite = AnimatedSprite::load(
paths.getStringValue("sprites") + filename);
@@ -1931,7 +1933,7 @@ void Being::recalcSpritesOrder()
if (repIt->second != 1)
{
setSprite(removeSprite, repIt->second,
- mSpriteColors[removeSprite], false, true);
+ mSpriteColors[removeSprite], 1, false, true);
}
}
}
@@ -2066,7 +2068,7 @@ void Being::recalcSpritesOrder()
if (!id)
continue;
- setSprite(slot, id, mSpriteColors[slot], false, true);
+ setSprite(slot, id, mSpriteColors[slot], 1, false, true);
}
// logger->log("slot %d = %d", slot, mSpriteRemap[slot]);
}
diff --git a/src/being.h b/src/being.h
index 49127629f..1d5ca7c19 100644
--- a/src/being.h
+++ b/src/being.h
@@ -333,7 +333,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,
+ std::string color = "",
+ unsigned char colorId = 1, bool isWeapon = false,
bool isTempSprite = false);
void setSpriteID(unsigned int slot, int id);
diff --git a/src/flooritem.cpp b/src/flooritem.cpp
index 619be25ea..700d9ed25 100644
--- a/src/flooritem.cpp
+++ b/src/flooritem.cpp
@@ -41,7 +41,8 @@ FloorItem::FloorItem(int id,
int x,
int y,
Map *map,
- int amount):
+ int amount,
+ unsigned char color):
ActorSprite(id),
mItemId(itemId),
mX(x),
@@ -49,7 +50,8 @@ FloorItem::FloorItem(int id,
mMap(map),
// mAlpha(1.0f),
mAmount(amount),
- mPickupCount(0)
+ mPickupCount(0),
+ mColor(color)
{
mDropTime = cur_time;
@@ -69,7 +71,8 @@ FloorItem::FloorItem(int id,
mPos.y = 0;
}
- setupSpriteDisplay(ItemDB::get(itemId).getDisplay(), true, 1);
+ ItemInfo info = ItemDB::get(itemId);
+ setupSpriteDisplay(info.getDisplay(), true, 1, info.getDyeString(mColor));
}
const ItemInfo &FloorItem::getInfo() const
diff --git a/src/flooritem.h b/src/flooritem.h
index deff05bc8..f1d19b89f 100644
--- a/src/flooritem.h
+++ b/src/flooritem.h
@@ -48,7 +48,8 @@ class FloorItem : public ActorSprite
int x,
int y,
Map *map,
- int amount);
+ int amount,
+ unsigned char color);
Type getType() const
{ return FLOOR_ITEM; }
@@ -88,6 +89,7 @@ class FloorItem : public ActorSprite
int mDropTime;
int mAmount;
unsigned mPickupCount;
+ unsigned char mColor;
};
#endif
diff --git a/src/gui/outfitwindow.cpp b/src/gui/outfitwindow.cpp
index 2796e13c8..ea2b7980c 100644
--- a/src/gui/outfitwindow.cpp
+++ b/src/gui/outfitwindow.cpp
@@ -292,7 +292,8 @@ void OutfitWindow::draw(gcn::Graphics *graphics)
}
if (!foundItem)
{
- Image *image = Item::getImage(mItems[mCurrentOutfit][i]);
+ //+++ need use colors in outfits
+ Image *image = Item::getImage(mItems[mCurrentOutfit][i], 1);
if (image)
g->drawImage(image, itemX, itemY);
}
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 4544c09be..705ae9329 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -100,7 +100,7 @@ void Inventory::setItem(int index, int id, int quantity,
if (!mItems[index] && id > 0)
{
- Item *item = new Item(id, quantity, refine, equipment);
+ Item *item = new Item(id, quantity, refine, color, equipment);
item->setInvIndex(index);
mItems[index] = item;
mUsed++;
diff --git a/src/item.cpp b/src/item.cpp
index c3c9b9c18..02f775834 100644
--- a/src/item.cpp
+++ b/src/item.cpp
@@ -75,8 +75,9 @@ void Item::setId(int id, unsigned char color)
SpriteDisplay display = info.getDisplay();
std::string imagePath = paths.getStringValue("itemIcons")
+ display.image;
- mImage = resman->getImage(imagePath);
- mDrawImage = resman->getImage(imagePath);
+ std::string dye = combineDye(imagePath, info.getDyeString(color));
+ mImage = resman->getImage(dye);
+ mDrawImage = resman->getImage(dye);
if (!mImage)
{
@@ -98,12 +99,14 @@ bool Item::isHaveTag(int tagId)
return mTags[tagId] > 0;
}
-Image *Item::getImage(int id)
+Image *Item::getImage(int id, unsigned char color)
{
ResourceManager *resman = ResourceManager::getInstance();
- SpriteDisplay display = ItemDB::get(id).getDisplay();
+ ItemInfo info = ItemDB::get(id);
+ SpriteDisplay display = info.getDisplay();
std::string imagePath = "graphics/items/" + display.image;
- Image *image = resman->getImage(imagePath);
+ Image *image;
+ image = resman->getImage(combineDye(imagePath, info.getDyeString(color)));
if (!image)
image = Theme::getImageFromTheme("unknown-item.png");
diff --git a/src/item.h b/src/item.h
index cb58f6f9f..ae2cc9dfb 100644
--- a/src/item.h
+++ b/src/item.h
@@ -154,7 +154,7 @@ class Item
const ItemInfo &getInfo() const
{ return ItemDB::get(mId); }
- static Image *getImage(int id);
+ static Image *getImage(int id, unsigned char color);
bool isHaveTag(int tagId);
diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp
index f5fa7d26c..8ba2e5967 100644
--- a/src/net/manaserv/beinghandler.cpp
+++ b/src/net/manaserv/beinghandler.cpp
@@ -155,7 +155,7 @@ static void handleLooks(Being *being, Net::MessageIn &msg)
{
if (!(mask & (1 << i))) continue;
int id = msg.readInt16();
- being->setSprite(slots[i], id, "", (slots[i] == SPRITE_WEAPON));
+ being->setSprite(slots[i], id, "", 1, (slots[i] == SPRITE_WEAPON));
}
}
diff --git a/src/net/manaserv/buysellhandler.cpp b/src/net/manaserv/buysellhandler.cpp
index 7334fe928..07737e20b 100644
--- a/src/net/manaserv/buysellhandler.cpp
+++ b/src/net/manaserv/buysellhandler.cpp
@@ -96,7 +96,7 @@ void BuySellHandler::handleMessage(Net::MessageIn &msg)
int itemId = msg.readInt16();
int amount = msg.readInt16();
int value = msg.readInt16();
- dialog->addItem(new Item(itemId, amount, false), value);
+ dialog->addItem(new Item(itemId, amount, 1, false), value);
}
break;
}
diff --git a/src/net/manaserv/itemhandler.cpp b/src/net/manaserv/itemhandler.cpp
index ce1d0965a..0afd12d21 100644
--- a/src/net/manaserv/itemhandler.cpp
+++ b/src/net/manaserv/itemhandler.cpp
@@ -68,7 +68,7 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
actorSpriteManager->createItem(id, itemId,
x / map->getTileWidth(),
y / map->getTileHeight(),
- 0);
+ 0, 1);
}
else
{
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index b6589e260..15792cf3a 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -620,15 +620,18 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
int type = msg.readInt8();
int id = 0;
int id2 = 0;
+ std::string color;
if (msg.getId() == SMSG_BEING_CHANGE_LOOKS)
{
id = msg.readInt8();
+ id2 = 1; // default color
}
else
{ // SMSG_BEING_CHANGE_LOOKS2
id = msg.readInt16();
id2 = msg.readInt16();
+ color = "";
}
if (dstBeing->getType() == Being::PLAYER)
@@ -646,21 +649,21 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
dstBeing->setSpriteID(SPRITE_HAIR, id *-1);
break;
case 2: // Weapon ID in id, Shield ID in id2
- dstBeing->setSprite(SPRITE_WEAPON, id, "", true);
+ dstBeing->setSprite(SPRITE_WEAPON, id, "", 1, true);
if (!config.getBoolValue("hideShield"))
dstBeing->setSprite(SPRITE_SHIELD, id2);
player_node->imitateOutfit(dstBeing, SPRITE_SHIELD);
break;
case 3: // Change lower headgear for eAthena, pants for us
- dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id);
+ dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_BOTTOMCLOTHES);
break;
case 4: // Change upper headgear for eAthena, hat for us
- dstBeing->setSprite(SPRITE_HAT, id);
+ dstBeing->setSprite(SPRITE_HAT, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_HAT);
break;
case 5: // Change middle headgear for eathena, armor for us
- dstBeing->setSprite(SPRITE_TOPCLOTHES, id);
+ dstBeing->setSprite(SPRITE_TOPCLOTHES, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_TOPCLOTHES);
break;
case 6: // eAthena LOOK_HAIR_COLOR
@@ -668,35 +671,35 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
break;
case 8: // eAthena LOOK_SHIELD
if (!config.getBoolValue("hideShield"))
- dstBeing->setSprite(SPRITE_SHIELD, id);
+ dstBeing->setSprite(SPRITE_SHIELD, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_SHIELD);
break;
case 9: // eAthena LOOK_SHOES
- dstBeing->setSprite(SPRITE_SHOE, id);
+ dstBeing->setSprite(SPRITE_SHOE, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_SHOE);
break;
case 10: // LOOK_GLOVES
- dstBeing->setSprite(SPRITE_GLOVES, id);
+ dstBeing->setSprite(SPRITE_GLOVES, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_GLOVES);
break;
case 11: // LOOK_CAPE
- dstBeing->setSprite(SPRITE_CAPE, id);
+ dstBeing->setSprite(SPRITE_CAPE, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_CAPE);
break;
case 12:
- dstBeing->setSprite(SPRITE_MISC1, id);
+ dstBeing->setSprite(SPRITE_MISC1, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_MISC1);
break;
case 13:
- dstBeing->setSprite(SPRITE_MISC2, id);
+ dstBeing->setSprite(SPRITE_MISC2, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_MISC2);
break;
case 14:
- dstBeing->setSprite(SPRITE_EVOL1, id);
+ dstBeing->setSprite(SPRITE_EVOL1, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_EVOL1);
break;
case 15:
- dstBeing->setSprite(SPRITE_EVOL2, id);
+ dstBeing->setSprite(SPRITE_EVOL2, id, color, id2);
player_node->imitateOutfit(dstBeing, SPRITE_EVOL2);
break;
default:
@@ -890,7 +893,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_WEAPON, weapon, "", true);
+ dstBeing->setSprite(SPRITE_WEAPON, weapon, "", 1, true);
if (!config.getBoolValue("hideShield"))
dstBeing->setSprite(SPRITE_SHIELD, shield);
//dstBeing->setSprite(SPRITE_SHOE, shoes);
diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp
index 5e2efbdd5..ec61b4be2 100644
--- a/src/net/tmwa/charserverhandler.cpp
+++ b/src/net/tmwa/charserverhandler.cpp
@@ -273,7 +273,7 @@ void CharServerHandler::readPlayerData(Net::MessageIn &msg,
tempPlayer->setSubtype(msg.readInt16()); // class (used for race)
int hairStyle = msg.readInt16();
Uint16 weapon = msg.readInt16();
- tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true);
+ tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", 1, true);
character->data.mAttributes[LEVEL] = msg.readInt16();
diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp
index 340f0c4b2..fc32c3ec3 100644
--- a/src/net/tmwa/inventoryhandler.cpp
+++ b/src/net/tmwa/inventoryhandler.cpp
@@ -217,7 +217,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
if (inventory)
{
inventory->setItem(index, itemId, amount,
- 0, isEquipment);
+ 0, identified, isEquipment);
}
}
else
@@ -300,7 +300,7 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
amount += inventory->getItem(index)->getQuantity();
inventory->setItem(index, itemId, amount, refine,
- equipType != 0);
+ identified, equipType != 0);
}
}
} break;
@@ -458,19 +458,29 @@ void InventoryHandler::handleMessage(Net::MessageIn &msg)
{
index = msg.readInt16() - INVENTORY_OFFSET;
itemId = msg.readInt16();
- msg.readInt8(); // type
- msg.readInt8(); // identify flag
+ if (itemId == 1172)
+ logger->log("step1");
+ int itemType = msg.readInt8(); // type
+ identified = msg.readInt8(); // identify flag
msg.readInt16(); // equip type
equipType = msg.readInt16();
msg.readInt8(); // attribute
refine = msg.readInt8();
msg.skip(8); // card
+ if (itemId == 1172)
+ logger->log("step2");
if (inventory)
- inventory->setItem(index, itemId, 1, refine, true);
+ inventory->setItem(index, itemId, 1, refine, identified, true);
if (equipType)
mEquips.setEquipment(getSlot(equipType), index);
+
+ if (debugInventory)
+ {
+ logger->log("Index: %d, ID: %d, Type: %d, Identified: %d",
+ index, itemId, itemType, identified);
+ }
}
break;
diff --git a/src/net/tmwa/itemhandler.cpp b/src/net/tmwa/itemhandler.cpp
index 5840d99b2..897ed1fb5 100644
--- a/src/net/tmwa/itemhandler.cpp
+++ b/src/net/tmwa/itemhandler.cpp
@@ -52,7 +52,7 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
{
int id = msg.readInt32();
int itemId = msg.readInt16();
- msg.readInt8(); // identify flag
+ unsigned char identify = msg.readInt8(); // identify flag
int x = msg.readInt16();
int y = msg.readInt16();
// msg.skip(4); // amount,subX,subY / subX,subY,amount
@@ -64,12 +64,12 @@ void ItemHandler::handleMessage(Net::MessageIn &msg)
if (msg.getId() == SMSG_ITEM_VISIBLE)
{
actorSpriteManager->createItem(id, itemId,
- x, y, amount1);
+ x, y, amount1, identify);
}
else
{
actorSpriteManager->createItem(id, itemId,
- x, y, amount2);
+ x, y, amount2, identify);
}
}
}
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index 255a9a7b3..49aadc23d 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -81,3 +81,31 @@ std::map<int, int> &ItemInfo::addReplaceSprite(int sprite)
}
return it->second;
}
+
+std::string ItemInfo::getDyeString(int color) const
+{
+ if (mId == 1172)
+ {
+ 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";
+ }
+ 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 "";
+} \ No newline at end of file
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index 5ea537fae..3b72c7830 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -231,6 +231,10 @@ class ItemInfo
std::map<int, std::map<int, int> > getSpriteToItemReplaceMap() const
{ return mSpriteToItemReplaceMap; }
+ std::string getDyeString(int color) const;
+
+ std::string getDyeColorsString(int color) const;
+
protected:
SpriteDisplay mDisplay; /**< Display info (like icon) */
std::string mName;
diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp
index d914efe30..835f9ce00 100644
--- a/src/utils/stringutils.cpp
+++ b/src/utils/stringutils.cpp
@@ -387,3 +387,13 @@ std::list<int> splitToIntList(const std::string &text, char separator)
return tokens;
}
+
+std::string combineDye(std::string file, std::string dye)
+{
+ if (dye.empty())
+ return file;
+ size_t pos = file.find_last_of("|");
+ if (pos != std::string::npos)
+ return file.substr(0, pos) + "|" + dye;
+ return file + "|" + dye;
+}
diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h
index ab16bb64b..52b47e6a2 100644
--- a/src/utils/stringutils.h
+++ b/src/utils/stringutils.h
@@ -170,4 +170,6 @@ std::set<int> splitToIntSet(const std::string &text, char separator);
std::list<int> splitToIntList(const std::string &text, char separator);
+std::string combineDye(std::string file, std::string dye);
+
#endif // UTILS_STRINGUTILS_H