| Attached Files | race bug and monster bug.png [^] (825,185 bytes) 2010-04-14 23:27
0001-Add-race-support-for-eAthena.patch [^] (16,035 bytes) 2010-04-16 17:32 [Show Content] [Hide Content]From 4a9a90abe346d36da7c8d9ca3589ffe1d5db8db1 Mon Sep 17 00:00:00 2001
From: Jared Adams <jaxad0127@gmail.com>
Date: Tue, 13 Apr 2010 22:48:28 -0600
Subject: [PATCH] Add race support for eAthena
The job/class field is used to select the race. If the given race isn't defined,
it falls back on the first race (so servers can use jobs/classes without races).
Also rename job to subtype for Being and subclasses, and begin support for
changing monster and NPC subtypes on the fly (particle effects still need to be
reset when they change).
---
src/being.cpp | 4 +-
src/being.h | 14 ++++----
src/localplayer.cpp | 4 +-
src/localplayer.h | 2 +-
src/monster.cpp | 69 +++++++++++++++++++++----------------
src/monster.h | 4 ++-
src/net/ea/beinghandler.cpp | 4 +-
src/net/ea/charserverhandler.cpp | 2 +-
src/npc.cpp | 40 +++++++++++++---------
src/npc.h | 4 ++-
src/player.cpp | 21 ++++++++----
src/player.h | 4 ++-
src/resources/itemdb.cpp | 11 ++++++
src/resources/itemdb.h | 2 +
src/resources/iteminfo.h | 28 ++++++++-------
15 files changed, 129 insertions(+), 84 deletions(-)
diff --git a/src/being.cpp b/src/being.cpp
index 4429373..47c31c3 100644
--- a/src/being.cpp
+++ b/src/being.cpp
@@ -67,14 +67,14 @@ static const int DEFAULT_BEING_HEIGHT = 32;
int Being::mNumberOfHairstyles = 1;
// TODO: mWalkTime used by eAthena only
-Being::Being(int id, int job, Map *map):
+Being::Being(int id, int subtype, Map *map):
mFrame(0),
mWalkTime(0),
mEmotion(0), mEmotionTime(0),
mSpeechTime(0),
mAttackSpeed(350),
mAction(STAND),
- mJob(job),
+ mSubType(subtype),
mId(id),
mDirection(DOWN),
mSpriteDirection(DIRECTION_DOWN),
diff --git a/src/being.h b/src/being.h
index 3479a9a..3d3dfa7 100644
--- a/src/being.h
+++ b/src/being.h
@@ -118,11 +118,11 @@ class Being : public Sprite, public ConfigListener
/**
* Constructor.
*
- * @param id a unique being id
- * @param job partly determines the type of the being
- * @param map the map the being is on
+ * @param id a unique being id
+ * @param subtype partly determines the type of the being
+ * @param map the map the being is on
*/
- Being(int id, int job, Map *map);
+ Being(int id, int subtype, Map *map);
virtual ~Being();
@@ -284,12 +284,12 @@ class Being : public Sprite, public ConfigListener
/**
* Return Being's current Job (player job, npc, monster, creature )
*/
- Uint16 getJob() const { return mJob; }
+ Uint16 getSubType() const { return mSubType; }
/**
* Set Being's current Job (player job, npc, monster, creature )
*/
- void setJob(Uint16 job) { mJob = job; }
+ virtual void setSubtype(Uint16 subtype) { mSubType = subtype; }
/**
* Sets the walk speed.
@@ -611,7 +611,7 @@ class Being : public Sprite, public ConfigListener
int mAttackSpeed; /**< Attack speed */
Action mAction; /**< Action the being is performing */
- Uint16 mJob; /**< Job (player job, npc, monster, creature ) */
+ Uint16 mSubType; /**< Subtype (graphical view, basically) */
int mId; /**< Unique sprite id */
Uint8 mDirection; /**< Facing direction */
diff --git a/src/localplayer.cpp b/src/localplayer.cpp
index ef2d7e4..961248d 100644
--- a/src/localplayer.cpp
+++ b/src/localplayer.cpp
@@ -75,8 +75,8 @@ const short walkingKeyboardDelay = 1000;
LocalPlayer *player_node = NULL;
-LocalPlayer::LocalPlayer(int id, int job):
- Player(id, job, 0),
+LocalPlayer::LocalPlayer(int id, int subtype):
+ Player(id, subtype, 0),
mEquipment(new Equipment),
mAttackRange(0),
mTargetTime(-1),
diff --git a/src/localplayer.h b/src/localplayer.h
index 65653d5..dd7b94d 100644
--- a/src/localplayer.h
+++ b/src/localplayer.h
@@ -105,7 +105,7 @@ class LocalPlayer : public Player
/**
* Constructor.
*/
- LocalPlayer(int id= 65535, int job = 0);
+ LocalPlayer(int id= 65535, int subtype = 0);
/**
* Destructor.
diff --git a/src/monster.cpp b/src/monster.cpp
index 23be939..0876b08 100644
--- a/src/monster.cpp
+++ b/src/monster.cpp
@@ -35,37 +35,11 @@
#include "resources/monsterdb.h"
#include "resources/monsterinfo.h"
-Monster::Monster(int id, int job, Map *map):
- Being(id, job, map),
+Monster::Monster(int id, int subtype, Map *map):
+ Being(id, subtype, map),
mAttackType(1)
{
- const MonsterInfo &info = getInfo();
-
- // Setup Monster sprites
- const std::list<std::string> &sprites = info.getSprites();
-
- for (std::list<std::string>::const_iterator i = sprites.begin();
- i != sprites.end(); i++)
- {
- std::string file = "graphics/sprites/" + *i;
- mSprites.push_back(AnimatedSprite::load(file));
- }
-
- // Ensure that something is shown
- if (mSprites.size() == 0)
- {
- mSprites.push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
- }
-
- if (Particle::enabled)
- {
- const std::list<std::string> &particleEffects = info.getParticleEffects();
- for (std::list<std::string>::const_iterator i = particleEffects.begin();
- i != particleEffects.end(); i++)
- {
- controlParticle(particleEngine->addEffect((*i), 0, 0));
- }
- }
+ setSubtype(subtype);
mNameColor = &userPalette->getColor(UserPalette::MONSTER);
mTextColor = &userPalette->getColor(UserPalette::MONSTER);
@@ -86,6 +60,7 @@ void Monster::logic()
Being::logic();
}
+
void Monster::setAction(Action action, int attackType)
{
SpriteAction currentAction = ACTION_INVALID;
@@ -144,6 +119,40 @@ void Monster::setAction(Action action, int attackType)
}
}
+void Monster::setSubtype(Uint16 subtype)
+{
+ Being::setSubtype(subtype);
+
+ const MonsterInfo &info = getInfo();
+
+ // Setup Monster sprites
+ const std::list<std::string> &sprites = info.getSprites();
+
+ mSprites.clear();
+ for (std::list<std::string>::const_iterator i = sprites.begin();
+ i != sprites.end(); i++)
+ {
+ std::string file = "graphics/sprites/" + *i;
+ mSprites.push_back(AnimatedSprite::load(file));
+ }
+
+ // Ensure that something is shown
+ if (mSprites.size() == 0)
+ {
+ mSprites.push_back(AnimatedSprite::load("graphics/sprites/error.xml"));
+ }
+
+ if (Particle::enabled)
+ {
+ const std::list<std::string> &particleEffects = info.getParticleEffects();
+ for (std::list<std::string>::const_iterator i = particleEffects.begin();
+ i != particleEffects.end(); i++)
+ {
+ controlParticle(particleEngine->addEffect((*i), 0, 0));
+ }
+ }
+}
+
void Monster::handleAttack(Being *victim, int damage, AttackType type)
{
Being::handleAttack(victim, damage, type);
@@ -170,7 +179,7 @@ Being::TargetCursorSize Monster::getTargetCursorSize() const
const MonsterInfo &Monster::getInfo() const
{
- return MonsterDB::get(mJob);
+ return MonsterDB::get(mSubType);
}
void Monster::updateCoords()
diff --git a/src/monster.h b/src/monster.h
index 6fb82c7..9bb8e3b 100644
--- a/src/monster.h
+++ b/src/monster.h
@@ -30,7 +30,7 @@ class Text;
class Monster : public Being
{
public:
- Monster(int id, int job, Map *map);
+ Monster(int id, int subtype, Map *map);
virtual void logic();
@@ -38,6 +38,8 @@ class Monster : public Being
virtual Type getType() const { return MONSTER; }
+ virtual void setSubtype(Uint16 subtype);
+
virtual TargetCursorSize
getTargetCursorSize() const;
diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp
index 6dcf963..649e93e 100644
--- a/src/net/ea/beinghandler.cpp
+++ b/src/net/ea/beinghandler.cpp
@@ -167,7 +167,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
if (speed == 0) { speed = 150; }
dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setJob(job);
+ dstBeing->setSubtype(job);
hairStyle = msg.readInt16();
weapon = msg.readInt16();
headBottom = msg.readInt16();
@@ -550,7 +550,7 @@ void BeingHandler::handleMessage(Net::MessageIn &msg)
}
dstBeing->setWalkSpeed(Vector(speed, speed, 0));
- dstBeing->setJob(job);
+ dstBeing->setSubtype(job);
hairStyle = msg.readInt16();
weapon = msg.readInt16();
shield = msg.readInt16();
diff --git a/src/net/ea/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp
index 64e1d42..8706727 100644
--- a/src/net/ea/charserverhandler.cpp
+++ b/src/net/ea/charserverhandler.cpp
@@ -220,7 +220,7 @@ LocalPlayer *CharServerHandler::readPlayerData(Net::MessageIn &msg, int *slot)
tempPlayer->setMP(msg.readInt16());
tempPlayer->setMaxMP(msg.readInt16());
msg.readInt16(); // speed
- msg.readInt16(); // class
+ tempPlayer->setSubtype(msg.readInt16()); // class (used for race)
int hairStyle = msg.readInt16();
Uint16 weapon = msg.readInt16();
tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true);
diff --git a/src/npc.cpp b/src/npc.cpp
index 29a6c61..cdfe519 100644
--- a/src/npc.cpp
+++ b/src/npc.cpp
@@ -37,11 +37,32 @@
#include "resources/npcdb.h"
-NPC::NPC(int id, int job, Map *map):
- Player(id, job, map, true)
+NPC::NPC(int id, int subtype, Map *map):
+ Player(id, subtype, map, true)
{
- NPCInfo info = NPCDB::get(job);
+ setSubtype(subtype);
+ setShowName(true);
+}
+
+void NPC::setName(const std::string &name)
+{
+ const std::string displayName = name.substr(0, name.find('#', 0));
+
+ Being::setName(displayName);
+
+ mNameColor = &userPalette->getColor(UserPalette::NPC);
+
+ mDispName->setColor(mNameColor);
+}
+
+void NPC::setSubtype(Uint16 subtype)
+{
+ Being::setSubtype(subtype);
+
+ NPCInfo info = NPCDB::get(subtype);
+
+ mSprites.clear();
// Setup NPC sprites
for (std::list<NPCsprite*>::const_iterator i = info.sprites.begin();
i != info.sprites.end();
@@ -65,19 +86,6 @@ NPC::NPC(int id, int job, Map *map):
this->controlParticle(p);
}
}
-
- setShowName(true);
-}
-
-void NPC::setName(const std::string &name)
-{
- const std::string displayName = name.substr(0, name.find('#', 0));
-
- Being::setName(displayName);
-
- mNameColor = &userPalette->getColor(UserPalette::NPC);
-
- mDispName->setColor(mNameColor);
}
void NPC::talk()
diff --git a/src/npc.h b/src/npc.h
index c7db58f..0abd239 100644
--- a/src/npc.h
+++ b/src/npc.h
@@ -30,12 +30,14 @@ class Text;
class NPC : public Player
{
public:
- NPC(int id, int job, Map *map);
+ NPC(int id, int subtype, Map *map);
void setName(const std::string &name);
virtual Type getType() const { return Being::NPC; }
+ virtual void setSubtype(Uint16 subtype);
+
void talk();
void setSprite(unsigned int slot, int id,
diff --git a/src/player.cpp b/src/player.cpp
index ad8c1db..9113b4a 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -43,8 +43,8 @@
#include "utils/stringutils.h"
-Player::Player(int id, int job, Map *map, bool isNPC):
- Being(id, job, map),
+Player::Player(int id, int subtype, Map *map, bool isNPC):
+ Being(id, subtype, map),
mGender(GENDER_UNSPECIFIED),
mParty(NULL),
mIsGM(false)
@@ -58,11 +58,7 @@ Player::Player(int id, int job, Map *map, bool isNPC):
mSpriteColors.push_back("");
}
- /* Human base sprite. When implementing different races remove this
- * line and set the base sprite when setting the race of the player
- * character.
- */
- setSprite(Net::getCharHandler()->baseSprite(), -100);
+ setSubtype(subtype);
}
mShowName = config.getValue("visiblenames", 1);
config.addListener("visiblenames", this);
@@ -137,6 +133,17 @@ void Player::logic()
Being::logic();
}
+void Player::setSubtype(Uint16 subtype)
+{
+ Being::setSubtype(subtype);
+
+ int id = -100 - subtype;
+ if (ItemDB::exists(id)) // Prevent showing errors when sprite doesn't exist
+ setSprite(Net::getCharHandler()->baseSprite(), id);
+ else
+ setSprite(Net::getCharHandler()->baseSprite(), -100);
+}
+
void Player::setGender(Gender gender)
{
if (gender != mGender)
diff --git a/src/player.h b/src/player.h
index 670f6d8..e75870a 100644
--- a/src/player.h
+++ b/src/player.h
@@ -47,7 +47,7 @@ class Player : public Being
/**
* Constructor.
*/
- Player(int id, int job, Map *map, bool isNPC = false);
+ Player(int id, int subtype, Map *map, bool isNPC = false);
~Player();
@@ -55,6 +55,8 @@ class Player : public Being
virtual Type getType() const { return PLAYER; }
+ virtual void setSubtype(Uint16 subtype);
+
/**
* Sets the gender of this being.
*/
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index d60e38d..4638f00 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -78,6 +78,8 @@ static ItemType itemTypeFromString(const std::string &name, int id = 0)
else if (name=="equip-necklace") return ITEM_EQUIPMENT_NECKLACE;
else if (name=="equip-feet") return ITEM_EQUIPMENT_FEET;
else if (name=="equip-ammo") return ITEM_EQUIPMENT_AMMO;
+ else if (name=="racesprite") return ITEM_SPRITE_RACE;
+ else if (name=="hairsprite") return ITEM_SPRITE_HAIR;
else return ITEM_UNUSABLE;
}
@@ -255,6 +257,15 @@ void ItemDB::unload()
mLoaded = false;
}
+bool ItemDB::exists(int id)
+{
+ assert(mLoaded);
+
+ ItemInfos::const_iterator i = mItemInfos.find(id);
+
+ return i != mItemInfos.end();
+}
+
const ItemInfo &ItemDB::get(int id)
{
assert(mLoaded);
diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h
index 63c016b..be02307 100644
--- a/src/resources/itemdb.h
+++ b/src/resources/itemdb.h
@@ -43,6 +43,8 @@ namespace ItemDB
*/
void unload();
+ bool exists(int id);
+
const ItemInfo &get(int id);
const ItemInfo &get(const std::string &name);
diff --git a/src/resources/iteminfo.h b/src/resources/iteminfo.h
index e14d62b..a7c0ddc 100644
--- a/src/resources/iteminfo.h
+++ b/src/resources/iteminfo.h
@@ -72,19 +72,21 @@ enum EquipmentSlot
enum ItemType
{
ITEM_UNUSABLE = 0,
- ITEM_USABLE, // 1
- ITEM_EQUIPMENT_ONE_HAND_WEAPON, // 2
- ITEM_EQUIPMENT_TWO_HANDS_WEAPON,// 3
- ITEM_EQUIPMENT_TORSO,// 4
- ITEM_EQUIPMENT_ARMS,// 5
- ITEM_EQUIPMENT_HEAD,// 6
- ITEM_EQUIPMENT_LEGS,// 7
- ITEM_EQUIPMENT_SHIELD,// 8
- ITEM_EQUIPMENT_RING,// 9
- ITEM_EQUIPMENT_NECKLACE,// 10
- ITEM_EQUIPMENT_FEET,// 11
- ITEM_EQUIPMENT_AMMO,// 12
- ITEM_EQUIPMENT_CHARM// 13
+ ITEM_USABLE,
+ ITEM_EQUIPMENT_ONE_HAND_WEAPON,
+ ITEM_EQUIPMENT_TWO_HANDS_WEAPON,
+ ITEM_EQUIPMENT_TORSO,
+ ITEM_EQUIPMENT_ARMS, // 5
+ ITEM_EQUIPMENT_HEAD,
+ ITEM_EQUIPMENT_LEGS,
+ ITEM_EQUIPMENT_SHIELD,
+ ITEM_EQUIPMENT_RING,
+ ITEM_EQUIPMENT_NECKLACE, // 10
+ ITEM_EQUIPMENT_FEET,
+ ITEM_EQUIPMENT_AMMO,
+ ITEM_EQUIPMENT_CHARM,
+ ITEM_SPRITE_RACE,
+ ITEM_SPRITE_HAIR // 15
};
/**
--
1.7.0.5
|