summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-03-04 16:29:14 +0100
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-03-04 20:20:52 +0100
commit5c7f9d1d216fd1edca231ed274ac3077cb34909f (patch)
tree234405f8f9d0b422a02d8cc44854aaa6992cf2d9
parentd5ebad4e74da011777f9ba1a13fbb37d18c827b9 (diff)
downloadMana-5c7f9d1d216fd1edca231ed274ac3077cb34909f.tar.gz
Mana-5c7f9d1d216fd1edca231ed274ac3077cb34909f.tar.bz2
Mana-5c7f9d1d216fd1edca231ed274ac3077cb34909f.tar.xz
Mana-5c7f9d1d216fd1edca231ed274ac3077cb34909f.zip
Fixed character display
This change fixes hair style to take into account "race", which makes the faces visible again. Hair colors should also be fixed now, with partial support for itemcolors.xml added. The Mana client now also supports per-character gender, and it now hides the hair style and color buttons on character creation, when there are none to choose from. Closes #43
-rw-r--r--src/being.cpp6
-rw-r--r--src/being.h11
-rw-r--r--src/gui/charcreatedialog.cpp43
-rw-r--r--src/gui/charcreatedialog.h2
-rw-r--r--src/gui/register.cpp2
-rw-r--r--src/net/charhandler.h6
-rw-r--r--src/net/logindata.h4
-rw-r--r--src/net/manaserv/beinghandler.cpp10
-rw-r--r--src/net/manaserv/charhandler.cpp4
-rw-r--r--src/net/tmwa/beinghandler.cpp57
-rw-r--r--src/net/tmwa/charserverhandler.cpp20
-rw-r--r--src/net/tmwa/charserverhandler.h1
-rw-r--r--src/net/tmwa/gamehandler.cpp2
-rw-r--r--src/net/tmwa/loginhandler.cpp4
-rw-r--r--src/net/tmwa/protocol.h20
-rw-r--r--src/net/tmwa/token.h2
-rw-r--r--src/resources/hairdb.cpp8
-rw-r--r--src/resources/hairdb.h2
-rw-r--r--src/resources/itemdb.cpp16
-rw-r--r--src/resources/iteminfo.cpp28
-rw-r--r--src/resources/iteminfo.h7
-rw-r--r--src/resources/settingsmanager.cpp16
22 files changed, 164 insertions, 107 deletions
diff --git a/src/being.cpp b/src/being.cpp
index ad43ec52..46b499af 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -942,9 +942,9 @@ void Being::showName()
{
if (config.getBoolValue("showgender"))
{
- if (getGender() == GENDER_FEMALE)
+ if (getGender() == Gender::FEMALE)
mDisplayName += " \u2640";
- else if (getGender() == GENDER_MALE)
+ else if (getGender() == Gender::MALE)
mDisplayName += " \u2642";
}
@@ -1041,7 +1041,7 @@ void Being::setSprite(unsigned int slot, int id, const std::string &color,
}
else
{
- std::string filename = itemDb->get(id).getSprite(mGender);
+ std::string filename = itemDb->get(id).getSprite(mGender, mSubType);
AnimatedSprite *equipmentSprite = nullptr;
if (!filename.empty())
diff --git a/src/being.h b/src/being.h
index 411db3b7..32cfcf99 100644
--- a/src/being.h
+++ b/src/being.h
@@ -51,11 +51,12 @@ struct Position;
class SpeechBubble;
class Text;
-enum Gender
+enum class Gender
{
- GENDER_MALE = 0,
- GENDER_FEMALE = 1,
- GENDER_UNSPECIFIED = 2
+ MALE = 0,
+ FEMALE = 1,
+ UNSPECIFIED = 2,
+ HIDDEN = 3
};
class Being : public ActorSprite, public EventListener
@@ -505,7 +506,7 @@ class Being : public ActorSprite, public EventListener
std::vector<int> mSpriteIDs;
std::vector<std::string> mSpriteColors;
- Gender mGender = GENDER_UNSPECIFIED;
+ Gender mGender = Gender::UNSPECIFIED;
// Character guild information
std::map<int, Guild*> mGuilds;
diff --git a/src/gui/charcreatedialog.cpp b/src/gui/charcreatedialog.cpp
index 0d8a928e..fa1144b6 100644
--- a/src/gui/charcreatedialog.cpp
+++ b/src/gui/charcreatedialog.cpp
@@ -21,18 +21,13 @@
#include "gui/charcreatedialog.h"
-#include "game.h"
#include "localplayer.h"
-#include "main.h"
-#include "units.h"
#include "gui/charselectdialog.h"
-#include "gui/confirmdialog.h"
#include "gui/okdialog.h"
#include "gui/widgets/button.h"
#include "gui/widgets/label.h"
-#include "gui/widgets/layout.h"
#include "gui/widgets/playerbox.h"
#include "gui/widgets/radiobutton.h"
#include "gui/widgets/slider.h"
@@ -55,7 +50,7 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot):
mSlot(slot)
{
mPlayer = new Being(0, ActorSprite::PLAYER, 0, nullptr);
- mPlayer->setGender(GENDER_MALE);
+ mPlayer->setGender(Gender::MALE);
const std::vector<int> &items = CharDB::getDefaultItems();
for (size_t i = 0; i < items.size(); ++i)
@@ -66,6 +61,7 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot):
mHairStyleId = rand() * mHairStylesIds.size() / RAND_MAX;
mHairColorsIds = hairDB.getHairColorIds(
+ Net::getCharHandler()->getCharCreateMinHairColorId(),
Net::getCharHandler()->getCharCreateMaxHairColorId());
mHairColorId = rand() * mHairColorsIds.size() / RAND_MAX;
@@ -137,12 +133,21 @@ CharCreateDialog::CharCreateDialog(CharSelectDialog *parent, int slot):
add(mPlayerBox);
add(mNameField);
add(mNameLabel);
- add(mNextHairColorButton);
- add(mPrevHairColorButton);
- add(mHairColorLabel);
- add(mNextHairStyleButton);
- add(mPrevHairStyleButton);
- add(mHairStyleLabel);
+
+ if (mHairColorsIds.size() > 1)
+ {
+ add(mNextHairColorButton);
+ add(mPrevHairColorButton);
+ add(mHairColorLabel);
+ }
+
+ if (mHairStylesIds.size() > 1)
+ {
+ add(mNextHairStyleButton);
+ add(mPrevHairStyleButton);
+ add(mHairStyleLabel);
+ }
+
add(mAttributesLeft);
add(mCreateButton);
add(mCancelButton);
@@ -226,9 +231,9 @@ void CharCreateDialog::action(const gcn::ActionEvent &event)
else if (event.getId() == "gender")
{
if (mMale->isSelected())
- mPlayer->setGender(GENDER_MALE);
+ mPlayer->setGender(Gender::MALE);
else
- mPlayer->setGender(GENDER_FEMALE);
+ mPlayer->setGender(Gender::FEMALE);
}
}
@@ -366,9 +371,9 @@ void CharCreateDialog::setAttributes(const std::vector<std::string> &labels,
center();
}
-void CharCreateDialog::setFixedGender(bool fixed, Gender gender)
+void CharCreateDialog::setDefaultGender(Gender gender)
{
- if (gender == GENDER_FEMALE)
+ if (gender == Gender::FEMALE)
{
mFemale->setSelected(true);
mMale->setSelected(false);
@@ -380,12 +385,6 @@ void CharCreateDialog::setFixedGender(bool fixed, Gender gender)
}
mPlayer->setGender(gender);
-
- if (fixed)
- {
- mMale->setEnabled(false);
- mFemale->setEnabled(false);
- }
}
void CharCreateDialog::updateHair()
diff --git a/src/gui/charcreatedialog.h b/src/gui/charcreatedialog.h
index 89706b54..46db6229 100644
--- a/src/gui/charcreatedialog.h
+++ b/src/gui/charcreatedialog.h
@@ -61,7 +61,7 @@ class CharCreateDialog : public Window, public gcn::ActionListener
unsigned available,
unsigned min, unsigned max);
- void setFixedGender(bool fixed, Gender gender = GENDER_FEMALE);
+ void setDefaultGender(Gender gender);
private:
void updateSliders();
diff --git a/src/gui/register.cpp b/src/gui/register.cpp
index 0e23777c..d4ebb59c 100644
--- a/src/gui/register.cpp
+++ b/src/gui/register.cpp
@@ -227,7 +227,7 @@ void RegisterDialog::action(const gcn::ActionEvent &event)
mLoginData->password = mPasswordField->getText();
if (mFemaleButton)
mLoginData->gender = mFemaleButton->isSelected() ?
- GENDER_FEMALE : GENDER_MALE;
+ Gender::FEMALE : Gender::MALE;
if (mEmailField)
mLoginData->email = mEmailField->getText();
mLoginData->registerLogin = true;
diff --git a/src/net/charhandler.h b/src/net/charhandler.h
index ee8f2298..cebf0b93 100644
--- a/src/net/charhandler.h
+++ b/src/net/charhandler.h
@@ -78,6 +78,12 @@ class CharHandler
virtual unsigned int maxSprite() const = 0;
/**
+ * Returns the min permitted hair color Id at character creation time,
+ * or 0 if there is no minimum.
+ */
+ virtual int getCharCreateMinHairColorId() const { return 0; }
+
+ /**
* Returns the max permitted hair color Id at character creation time,
* or 0 if no limit should be applied.
*/
diff --git a/src/net/logindata.h b/src/net/logindata.h
index 1e19b541..34b259fb 100644
--- a/src/net/logindata.h
+++ b/src/net/logindata.h
@@ -40,7 +40,7 @@ public:
std::string email;
std::string captchaResponse;
- Gender gender = GENDER_UNSPECIFIED;
+ Gender gender = Gender::UNSPECIFIED;
bool remember; /**< Whether to store the username. */
bool registerLogin; /**< Whether an account is being registered. */
@@ -64,7 +64,7 @@ public:
updateHost.clear();
email.clear();
captchaResponse.clear();
- gender = GENDER_UNSPECIFIED;
+ gender = Gender::UNSPECIFIED;
resetCharacterSlots();
}
};
diff --git a/src/net/manaserv/beinghandler.cpp b/src/net/manaserv/beinghandler.cpp
index 6193fed1..186239c1 100644
--- a/src/net/manaserv/beinghandler.cpp
+++ b/src/net/manaserv/beinghandler.cpp
@@ -115,12 +115,12 @@ void BeingHandler::handleBeingEnterMessage(MessageIn &msg)
auto direction = (BeingDirection)msg.readInt8();
Gender gender;
int genderAsInt = msg.readInt8();
- if (genderAsInt == ::GENDER_FEMALE)
- gender = ::GENDER_FEMALE;
- else if (genderAsInt == ::GENDER_MALE)
- gender = ::GENDER_MALE;
+ if (genderAsInt == GENDER_FEMALE)
+ gender = Gender::FEMALE;
+ else if (genderAsInt == GENDER_MALE)
+ gender = Gender::MALE;
else
- gender = ::GENDER_UNSPECIFIED;
+ gender = Gender::UNSPECIFIED;
Being *being;
switch (type)
diff --git a/src/net/manaserv/charhandler.cpp b/src/net/manaserv/charhandler.cpp
index 61e44506..83919d4e 100644
--- a/src/net/manaserv/charhandler.cpp
+++ b/src/net/manaserv/charhandler.cpp
@@ -102,8 +102,8 @@ void CharHandler::handleCharacterInfo(MessageIn &msg)
CachedCharacterInfo info;
info.slot = msg.readInt8();
info.name = msg.readString();
- info.gender = msg.readInt8() == ManaServ::GENDER_MALE ?
- ::GENDER_MALE : ::GENDER_FEMALE;
+ info.gender = msg.readInt8() == ManaServ::GENDER_MALE ? Gender::MALE
+ : Gender::FEMALE;
info.hairStyle = msg.readInt8();
info.hairColor = msg.readInt8();
info.level = msg.readInt16();
diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp
index 50585970..33adb93b 100644
--- a/src/net/tmwa/beinghandler.cpp
+++ b/src/net/tmwa/beinghandler.cpp
@@ -242,8 +242,8 @@ void BeingHandler::handleMessage(MessageIn &msg)
if (dstBeing->getType() == ActorSprite::PLAYER)
{
- dstBeing->setGender((gender == 0)
- ? GENDER_FEMALE : GENDER_MALE);
+ dstBeing->setGender(gender == 0 ? Gender::FEMALE
+ : Gender::MALE);
// Set these after the gender, as the sprites may be gender-specific
dstBeing->setSprite(SPRITE_HAIR, hairStyle * -1,
hairDB.getHairColor(hairColor));
@@ -415,53 +415,60 @@ void BeingHandler::handleMessage(MessageIn &msg)
break;
}
- int type = msg.readInt8();
- int id = msg.readInt16();
- int id2 = msg.readInt16();
+ const LOOK type = static_cast<LOOK>(msg.readInt8());
+ const int id = msg.readInt16();
+ const int id2 = msg.readInt16();
switch (type)
{
- case 1: // eAthena LOOK_HAIR
- dstBeing->setSpriteID(SPRITE_HAIR, id *-1);
+ case LOOK::HAIR:
+ {
+ // const int look = id / 256;
+ const int hair = id % 256;
+ dstBeing->setSpriteID(SPRITE_HAIR, hair * -1);
break;
- case 2: // Weapon ID in id, Shield ID in id2
- dstBeing->setSprite(SPRITE_WEAPON, id, "", true);
+ }
+ case LOOK::WEAPON: // Weapon ID in id, Shield ID in id2
+ dstBeing->setSprite(SPRITE_WEAPON, id, std::string(), true);
dstBeing->setSprite(SPRITE_SHIELD, id2);
break;
- case 3: // Change lower headgear for eAthena, pants for us
+ case LOOK::HEAD_BOTTOM: // Change lower headgear for eAthena, pants for us
dstBeing->setSprite(SPRITE_BOTTOMCLOTHES, id);
break;
- case 4: // Change upper headgear for eAthena, hat for us
+ case LOOK::HEAD_TOP: // Change upper headgear for eAthena, hat for us
dstBeing->setSprite(SPRITE_HAT, id);
break;
- case 5: // Change middle headgear for eathena, armor for us
+ case LOOK::HEAD_MID: // Change middle headgear for eathena, armor for us
dstBeing->setSprite(SPRITE_TOPCLOTHES, id);
break;
- case 6: // eAthena LOOK_HAIR_COLOR
+ case LOOK::HAIR_COLOR:
dstBeing->setSpriteColor(SPRITE_HAIR,
hairDB.getHairColor(id));
break;
- case 8: // eAthena LOOK_SHIELD
+ case LOOK::CLOTHES_COLOR:
+ // ignoring it
+ break;
+ case LOOK::SHIELD:
dstBeing->setSprite(SPRITE_SHIELD, id);
break;
- case 9: // eAthena LOOK_SHOES
+ case LOOK::SHOES:
dstBeing->setSprite(SPRITE_SHOE, id);
break;
- case 10: // LOOK_GLOVES
+ case LOOK::GLOVES:
dstBeing->setSprite(SPRITE_GLOVES, id);
break;
- case 11: // LOOK_CAPE
+ case LOOK::CAPE:
dstBeing->setSprite(SPRITE_CAPE, id);
break;
- case 12:
+ case LOOK::MISC1:
dstBeing->setSprite(SPRITE_MISC1, id);
break;
- case 13:
+ case LOOK::MISC2:
dstBeing->setSprite(SPRITE_MISC2, id);
break;
default:
logger->log("SMSG_BEING_CHANGE_LOOKS2: unsupported type: "
- "%d, id: %d", type, id);
+ "%d, id: %d", static_cast<int>(type), id);
break;
}
}
@@ -549,9 +556,8 @@ void BeingHandler::handleMessage(MessageIn &msg)
msg.readInt16(); // manner
dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3
msg.readInt8(); // karma
- dstBeing->setGender((msg.readInt8() == 0)
- ? GENDER_FEMALE : GENDER_MALE);
-
+ dstBeing->setGender(msg.readInt8() == 0 ? 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_SHIELD, shield);
@@ -629,9 +635,8 @@ void BeingHandler::handleMessage(MessageIn &msg)
dstBeing = actorSpriteManager->findBeing(id);
if (dstBeing)
{
- Uint16 x, y;
- x = msg.readInt16();
- y = msg.readInt16();
+ Uint16 x = msg.readInt16();
+ Uint16 y = msg.readInt16();
handlePosMessage(map, dstBeing, x, y);
}
}
diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp
index 324afd2d..d6b1f5a0 100644
--- a/src/net/tmwa/charserverhandler.cpp
+++ b/src/net/tmwa/charserverhandler.cpp
@@ -229,7 +229,7 @@ void CharServerHandler::readPlayerData(MessageIn &msg, Net::Character *character
msg.readInt32(); // option
msg.readInt32(); // karma
msg.readInt32(); // manner
- msg.skip(2); // unknown
+ msg.readInt16(); // character points left
character->data.mAttributes[HP] = msg.readInt16();
character->data.mAttributes[MAX_HP] = msg.readInt16();
@@ -237,8 +237,10 @@ void CharServerHandler::readPlayerData(MessageIn &msg, Net::Character *character
character->data.mAttributes[MAX_MP] = msg.readInt16();
msg.readInt16(); // speed
- tempPlayer->setSubtype(msg.readInt16()); // class (used for race)
- int hairStyle = msg.readInt16();
+ const uint16_t race = msg.readInt16(); // class (used for race)
+ int hairStyle = msg.readInt8();
+ msg.readInt8(); // look
+ tempPlayer->setSubtype(race);
Uint16 weapon = msg.readInt16();
tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true);
@@ -260,7 +262,8 @@ void CharServerHandler::readPlayerData(MessageIn &msg, Net::Character *character
character->data.mStats[i + STRENGTH].base = msg.readInt8();
character->slot = msg.readInt8(); // character slot
- msg.readInt8(); // unknown
+ const uint8_t sex = msg.readInt8();
+ tempPlayer->setGender(sex ? Gender::MALE : Gender::FEMALE);
}
void CharServerHandler::setCharSelectDialog(CharSelectDialog *window)
@@ -298,7 +301,7 @@ void CharServerHandler::setCharCreateDialog(CharCreateDialog *window)
sumStat = Attributes::getCreationPoints();
mCharCreateDialog->setAttributes(attributes, sumStat, minStat, maxStat);
- mCharCreateDialog->setFixedGender(true, token.sex);
+ mCharCreateDialog->setDefaultGender(token.sex);
}
void CharServerHandler::requestCharacters()
@@ -361,6 +364,11 @@ unsigned int CharServerHandler::maxSprite() const
return SPRITE_VECTOREND;
}
+int CharServerHandler::getCharCreateMinHairColorId() const
+{
+ return CharDB::getMinHairColor();
+}
+
int CharServerHandler::getCharCreateMaxHairColorId() const
{
const int max = CharDB::getMaxHairColor();
@@ -387,7 +395,7 @@ void CharServerHandler::connect()
// [Fate] The next word is unused by the old char server, so we squeeze in
// mana client version information
outMsg.writeInt16(CLIENT_PROTOCOL_VERSION);
- outMsg.writeInt8((token.sex == GENDER_MALE) ? 1 : 0);
+ outMsg.writeInt8(token.sex == Gender::MALE ? 1 : 0);
// We get 4 useless bytes before the real answer comes in (what are these?)
mNetwork->skip(4);
diff --git a/src/net/tmwa/charserverhandler.h b/src/net/tmwa/charserverhandler.h
index 1102bb08..c8ba4f6f 100644
--- a/src/net/tmwa/charserverhandler.h
+++ b/src/net/tmwa/charserverhandler.h
@@ -68,6 +68,7 @@ class CharServerHandler : public MessageHandler, public Net::CharHandler
unsigned int maxSprite() const override;
+ int getCharCreateMinHairColorId() const override;
int getCharCreateMaxHairColorId() const override;
int getCharCreateMaxHairStyleId() const override;
diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp
index 0f423d8d..6f276e66 100644
--- a/src/net/tmwa/gamehandler.cpp
+++ b/src/net/tmwa/gamehandler.cpp
@@ -140,7 +140,7 @@ void GameHandler::connect()
outMsg.writeInt32(mCharID);
outMsg.writeInt32(token.session_ID1);
outMsg.writeInt32(token.session_ID2);
- outMsg.writeInt8((token.sex == GENDER_MALE) ? 1 : 0);
+ outMsg.writeInt8(token.sex == Gender::MALE ? 1 : 0);
// We get 4 useless bytes before the real answer comes in (what are these?)
mNetwork->skip(4);
diff --git a/src/net/tmwa/loginhandler.cpp b/src/net/tmwa/loginhandler.cpp
index 725e0e35..1e0c6eda 100644
--- a/src/net/tmwa/loginhandler.cpp
+++ b/src/net/tmwa/loginhandler.cpp
@@ -126,7 +126,7 @@ void LoginHandler::handleMessage(MessageIn &msg)
mToken.account_ID = msg.readInt32();
mToken.session_ID2 = msg.readInt32();
msg.skip(30); // unknown
- mToken.sex = msg.readInt8() ? GENDER_MALE : GENDER_FEMALE;
+ mToken.sex = msg.readInt8() ? Gender::MALE : Gender::FEMALE;
for (int i = 0; i < worldCount; i++)
{
@@ -305,7 +305,7 @@ void LoginHandler::chooseServer(unsigned int server)
void LoginHandler::registerAccount(LoginData *loginData)
{
std::string username = loginData->username;
- username.append((loginData->gender == GENDER_FEMALE) ? "_F" : "_M");
+ username.append(loginData->gender == Gender::FEMALE ? "_F" : "_M");
sendLoginRegister(username, loginData->password);
}
diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h
index e50948c5..609b18a5 100644
--- a/src/net/tmwa/protocol.h
+++ b/src/net/tmwa/protocol.h
@@ -22,6 +22,8 @@
#ifndef TA_PROTOCOL_H
#define TA_PROTOCOL_H
+#include <cstdint>
+
namespace TmwAthena {
enum {
@@ -60,6 +62,24 @@ enum
SPRITE_VECTOREND
};
+enum class LOOK : uint8_t
+{
+ BASE = 0,
+ HAIR = 1,
+ WEAPON = 2,
+ HEAD_BOTTOM = 3,
+ HEAD_TOP = 4,
+ HEAD_MID = 5,
+ HAIR_COLOR = 6,
+ CLOTHES_COLOR = 7,
+ SHIELD = 8,
+ SHOES = 9,
+ GLOVES = 10,
+ CAPE = 11,
+ MISC1 = 12,
+ MISC2 = 13,
+};
+
enum NpcCommand
{
NPC_REQUEST_LANG = 0,
diff --git a/src/net/tmwa/token.h b/src/net/tmwa/token.h
index b5e84238..c0a2b3c8 100644
--- a/src/net/tmwa/token.h
+++ b/src/net/tmwa/token.h
@@ -36,7 +36,7 @@ struct Token
account_ID = 0;
session_ID1 = 0;
session_ID2 = 0;
- sex = GENDER_UNSPECIFIED;
+ sex = Gender::UNSPECIFIED;
}
};
diff --git a/src/resources/hairdb.cpp b/src/resources/hairdb.cpp
index ff301a23..09ac14f4 100644
--- a/src/resources/hairdb.cpp
+++ b/src/resources/hairdb.cpp
@@ -104,15 +104,15 @@ std::vector<int> HairDB::getHairStyleIds(int maxId) const
return hairStylesIds;
}
-std::vector<int> HairDB::getHairColorIds(int maxId) const
+std::vector<int> HairDB::getHairColorIds(int minId, int maxId) const
{
std::vector<int> hairColorsIds;
- for (const auto &hairColor : mHairColors)
+ for (const auto &[id, _] : mHairColors)
{
// Don't give ids higher than the requested maximum.
- if (maxId > 0 && hairColor.first > maxId)
+ if ((maxId > 0 && id > maxId) || id < minId)
continue;
- hairColorsIds.push_back(hairColor.first);
+ hairColorsIds.push_back(id);
}
return hairColorsIds;
}
diff --git a/src/resources/hairdb.h b/src/resources/hairdb.h
index b4374985..1f75a33a 100644
--- a/src/resources/hairdb.h
+++ b/src/resources/hairdb.h
@@ -64,7 +64,7 @@ public:
* @param maxId the max permited id. If not 0, the hairDb won't
* return ids > to the parameter.
*/
- std::vector<int> getHairColorIds(int maxId = 0) const;
+ std::vector<int> getHairColorIds(int minId, int maxId) const;
/**
* Add a hair style to the database.
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index b910c639..77fda11b 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -66,8 +66,9 @@ void ItemDB::loadEmptyItemDefinition()
mUnknown->mName = _("Unknown item");
mUnknown->mDisplay = SpriteDisplay();
std::string errFile = paths.getStringValue("spriteErrorFile");
- mUnknown->setSprite(errFile, GENDER_MALE);
- mUnknown->setSprite(errFile, GENDER_FEMALE);
+ mUnknown->setSprite(errFile, Gender::MALE, 0);
+ mUnknown->setSprite(errFile, Gender::FEMALE, 0);
+ mUnknown->setSprite(errFile, Gender::HIDDEN, 0);
mUnknown->setHitEffectId(paths.getIntValue("hitEffectId"));
mUnknown->setCriticalHitEffectId(paths.getIntValue("criticalHitEffectId"));
}
@@ -122,14 +123,13 @@ void ItemDB::loadSpriteRef(ItemInfo *itemInfo, xmlNodePtr node)
std::string gender = XML::getProperty(node, "gender", "unisex");
std::string filename = (const char*) node->xmlChildrenNode->content;
+ const int race = XML::getProperty(node, "race", 0);
if (gender == "male" || gender == "unisex")
- {
- itemInfo->setSprite(filename, GENDER_MALE);
- }
+ itemInfo->setSprite(filename, Gender::MALE, race);
if (gender == "female" || gender == "unisex")
- {
- itemInfo->setSprite(filename, GENDER_FEMALE);
- }
+ itemInfo->setSprite(filename, Gender::FEMALE, race);
+ if (gender == "hidden" || gender == "other" || gender == "unisex")
+ itemInfo->setSprite(filename, Gender::HIDDEN, race);
}
void ItemDB::loadSoundRef(ItemInfo *itemInfo, xmlNodePtr node)
diff --git a/src/resources/iteminfo.cpp b/src/resources/iteminfo.cpp
index 9e7fd6b7..b3208777 100644
--- a/src/resources/iteminfo.cpp
+++ b/src/resources/iteminfo.cpp
@@ -24,21 +24,22 @@
#include "resources/itemdb.h"
#include "configuration.h"
-const std::string &ItemInfo::getSprite(Gender gender) const
+const std::string &ItemInfo::getSprite(Gender gender, int race) const
{
if (mView)
{
// Forward the request to the item defining how to view this item
- return itemDb->get(mView).getSprite(gender);
+ return itemDb->get(mView).getSprite(gender, race);
}
- else
- {
- static const std::string empty;
- auto i =
- mAnimationFiles.find(gender);
- return (i != mAnimationFiles.end()) ? i->second : empty;
- }
+ auto i = mAnimationFiles.find(static_cast<int>(gender) + race * 4);
+
+ // Fall back to ignoring race
+ if (race != 0 && i == mAnimationFiles.end())
+ i = mAnimationFiles.find(static_cast<int>(gender));
+
+ static const std::string empty;
+ return i != mAnimationFiles.end() ? i->second : empty;
}
void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename)
@@ -49,8 +50,11 @@ void ItemInfo::addSound(EquipmentSoundEvent event, const std::string &filename)
const std::string &ItemInfo::getSound(EquipmentSoundEvent event) const
{
static const std::string empty;
- std::map< EquipmentSoundEvent, std::vector<std::string> >::const_iterator i;
- i = mSounds.find(event);
-
+ auto i = mSounds.find(event);
return i == mSounds.end() ? empty : i->second[rand() % i->second.size()];
}
+
+void ItemInfo::setSprite(const std::string &animationFile, Gender gender, int race)
+{
+ mAnimationFiles[static_cast<int>(gender) + race * 4] = animationFile;
+}
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index 5763e423..7344d668 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -106,7 +106,7 @@ class ItemInfo
int getWeight() const
{ return mWeight; }
- const std::string &getSprite(Gender gender) const;
+ const std::string &getSprite(Gender gender, int race) const;
// Handlers for seting and getting the string used for particles when attacking
void setMissileParticleFile(const std::string &s)
@@ -145,9 +145,8 @@ class ItemInfo
{ return mType; }
private:
-
- void setSprite(const std::string &animationFile, Gender gender)
- { mAnimationFiles[gender] = animationFile; }
+ void setSprite(const std::string &animationFile,
+ Gender gender, int race);
void addSound(EquipmentSoundEvent event, const std::string &filename);
diff --git a/src/resources/settingsmanager.cpp b/src/resources/settingsmanager.cpp
index 28c08617..eceedcf4 100644
--- a/src/resources/settingsmanager.cpp
+++ b/src/resources/settingsmanager.cpp
@@ -68,7 +68,7 @@ namespace SettingsManager
loadFile("npcs.xml");
loadFile("emotes.xml");
loadFile("status-effects.xml");
- loadFile("hair.xml");
+ loadFile("itemcolors.xml");
loadFile("units.xml");
}
@@ -194,6 +194,20 @@ namespace SettingsManager
{
hairDB.readHairColorNode(childNode, filename);
}
+ else if (xmlStrEqual(childNode->name, BAD_CAST "list"))
+ {
+ // todo: consider if we need a "color DB", but in tmwa clientdata
+ // I only see hair colors in the itemcolors.xml file.
+ const std::string name = XML::getProperty(childNode, "name", std::string());
+ if (name == "hair")
+ {
+ for_each_xml_child_node(hairColorNode, childNode)
+ {
+ if (xmlStrEqual(hairColorNode->name, BAD_CAST "color"))
+ hairDB.readHairColorNode(hairColorNode, filename);
+ }
+ }
+ }
else if (xmlStrEqual(childNode->name, BAD_CAST "item"))
{
itemDb->readItemNode(childNode, filename);