diff options
Diffstat (limited to 'src/net/tmwa')
40 files changed, 245 insertions, 273 deletions
diff --git a/src/net/tmwa/specialhandler.cpp b/src/net/tmwa/abilityhandler.cpp index 2e22b00a..ab891b40 100644 --- a/src/net/tmwa/specialhandler.cpp +++ b/src/net/tmwa/abilityhandler.cpp @@ -19,7 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "net/tmwa/specialhandler.h" +#include "net/tmwa/abilityhandler.h" #include "event.h" #include "log.h" @@ -64,11 +64,11 @@ /** should always be zero if failed */ #define SKILL_FAILED 0x00 -extern Net::SpecialHandler *specialHandler; +extern Net::AbilityHandler *abilityHandler; namespace TmwAthena { -SpecialHandler::SpecialHandler() +AbilityHandler::AbilityHandler() { static const Uint16 _messages[] = { SMSG_PLAYER_SKILLS, @@ -77,23 +77,20 @@ SpecialHandler::SpecialHandler() 0 }; handledMessages = _messages; - specialHandler = this; + abilityHandler = this; } -void SpecialHandler::handleMessage(MessageIn &msg) +void AbilityHandler::handleMessage(MessageIn &msg) { - int skillCount; - int skillId; - switch (msg.getId()) { - case SMSG_PLAYER_SKILLS: + case SMSG_PLAYER_SKILLS: { msg.readInt16(); // length - skillCount = (msg.getLength() - 4) / 37; + const int skillCount = (msg.getLength() - 4) / 37; for (int k = 0; k < skillCount; k++) { - skillId = msg.readInt16(); + int skillId = msg.readInt16(); msg.readInt16(); // target type msg.skip(2); // unused int level = msg.readInt16(); @@ -107,10 +104,11 @@ void SpecialHandler::handleMessage(MessageIn &msg) skillDialog->setModifiable(skillId, up); } break; + } case SMSG_PLAYER_SKILL_UP: { - skillId = msg.readInt16(); + int skillId = msg.readInt16(); int level = msg.readInt16(); msg.readInt16(); // sp msg.readInt16(); // range @@ -124,20 +122,20 @@ void SpecialHandler::handleMessage(MessageIn &msg) case SMSG_SKILL_FAILED: // Action failed (ex. sit because you have not reached the // right level) - skillId = msg.readInt16(); - short bskill = msg.readInt16(); - msg.readInt16(); // unknown - char success = msg.readInt8(); - char reason = msg.readInt8(); - if (success != SKILL_FAILED && bskill == BSKILL_EMOTE) + int skillId = msg.readInt16(); + auto btype = msg.readInt16(); + msg.readInt16(); // zero1 + msg.readInt8(); // zero2 + auto type = msg.readInt8(); + if (btype == BSKILL_EMOTE) { - logger->log("Action: %d/%d", bskill, success); + logger->log("Action: %d", btype); } std::string msg; - if (success == SKILL_FAILED && skillId == SKILL_BASIC) + if (skillId == SKILL_BASIC) { - switch (bskill) + switch (btype) { case BSKILL_TRADE: msg = _("Trade failed!"); @@ -161,7 +159,7 @@ void SpecialHandler::handleMessage(MessageIn &msg) msg += " "; - switch (reason) + switch (type) { case RFAIL_SKILLDEP: msg += _("You have not yet reached a high enough lvl!"); @@ -219,19 +217,19 @@ void SpecialHandler::handleMessage(MessageIn &msg) } } -void SpecialHandler::use(int id) +void AbilityHandler::use(int id) { } -void SpecialHandler::use(int id, int level, int beingId) +void AbilityHandler::useOn(int id, int beingId) { } -void SpecialHandler::use(int id, int level, int x, int y) +void AbilityHandler::useAt(int id, int x, int y) { } -void SpecialHandler::use(int id, const std::string &map) +void AbilityHandler::useInDirection(int id, int direction) { } diff --git a/src/net/tmwa/specialhandler.h b/src/net/tmwa/abilityhandler.h index 09b6ce8d..171f7d41 100644 --- a/src/net/tmwa/specialhandler.h +++ b/src/net/tmwa/abilityhandler.h @@ -19,32 +19,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_SKILLHANDLER_H -#define NET_TA_SKILLHANDLER_H +#pragma once #include "net/net.h" -#include "net/specialhandler.h" +#include "net/abilityhandler.h" #include "net/tmwa/messagehandler.h" namespace TmwAthena { -class SpecialHandler final : public MessageHandler, public Net::SpecialHandler +class AbilityHandler final : public MessageHandler, public Net::AbilityHandler { public: - SpecialHandler(); + AbilityHandler(); void handleMessage(MessageIn &msg) override; void use(int id) override; - void use(int id, int level, int beingId) override; + void useOn(int id, int beingId) override; - void use(int id, int level, int x, int y) override; + void useAt(int id, int x, int y) override; - void use(int id, const std::string &map) override; + void useInDirection(int id, int direction) override; }; } // namespace TmwAthena - -#endif // NET_TA_SKILLHANDLER_H diff --git a/src/net/tmwa/adminhandler.cpp b/src/net/tmwa/adminhandler.cpp index c60050bd..4c4ecdad 100644 --- a/src/net/tmwa/adminhandler.cpp +++ b/src/net/tmwa/adminhandler.cpp @@ -68,10 +68,7 @@ void AdminHandler::handleMessage(MessageIn &msg) id = msg.readInt32(); int ip = msg.readInt32(); if (Being *player = actorSpriteManager->findBeing(id)) - { player->setIp(ip); - player->updateName(); - } break; } } diff --git a/src/net/tmwa/adminhandler.h b/src/net/tmwa/adminhandler.h index 17d547a8..6a233823 100644 --- a/src/net/tmwa/adminhandler.h +++ b/src/net/tmwa/adminhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_ADMINHANDLER_H -#define NET_TA_ADMINHANDLER_H +#pragma once #include "net/adminhandler.h" #include "net/net.h" @@ -44,5 +43,3 @@ class AdminHandler final : public MessageHandler, public Net::AdminHandler }; } // namespace TmwAthena - -#endif // NET_TA_ADMINHANDLER_H diff --git a/src/net/tmwa/beinghandler.cpp b/src/net/tmwa/beinghandler.cpp index e2c4f158..c5979e9f 100644 --- a/src/net/tmwa/beinghandler.cpp +++ b/src/net/tmwa/beinghandler.cpp @@ -40,6 +40,7 @@ #include "resources/emotedb.h" #include "resources/hairdb.h" +#include "resources/statuseffectdb.h" #include <cmath> @@ -78,29 +79,51 @@ BeingHandler::BeingHandler(bool enableSync): handledMessages = _messages; } -static Being *createBeing(int id, short job) +static ActorSprite::Type typeFromJob(short job) { - ActorSprite::Type type = ActorSprite::UNKNOWN; if (job <= 25 || (job >= 4001 && job <= 4049)) - type = ActorSprite::PLAYER; - else if (job >= 46 && job <= 1000) - type = ActorSprite::NPC; - else if (job > 1000 && job <= 2000) - type = ActorSprite::MONSTER; - else if (job == 45) + return ActorSprite::PLAYER; + if (job >= 46 && job <= 1000) + return ActorSprite::NPC; + if (job > 1000 && job <= 2000) + return ActorSprite::MONSTER; + if (job == 45) + return ActorSprite::PORTAL; + + return ActorSprite::UNKNOWN; +} + +static Being *createBeing(int id, short job) +{ + const auto type = typeFromJob(job); + if (type == ActorSprite::PORTAL) return nullptr; // Skip portals Being *being = actorSpriteManager->createBeing(id, type, job); if (type == ActorSprite::PLAYER || type == ActorSprite::NPC) { - MessageOut outMsg(0x0094); - outMsg.writeInt32(id);//readLong(2)); + MessageOut outMsg(CMSG_NAME_REQUEST); + outMsg.writeInt32(id); } return being; } +static void updateBeingType(Being *being, short job) +{ + const auto type = typeFromJob(job); + const bool typeChanged = being->getType() != type; + + being->setType(type, job); + + if (typeChanged && type == ActorSprite::PLAYER) + { + MessageOut outMsg(CMSG_NAME_REQUEST); + outMsg.writeInt32(being->getId()); + } +} + static void handleMoveMessage(Map *map, Being *dstBeing, Uint16 srcX, Uint16 srcY, Uint16 dstX, Uint16 dstY) @@ -146,6 +169,42 @@ static void handlePosMessage(Map *map, Being *dstBeing, Uint16 x, Uint16 y, } } +static void applyStatusEffectsByOption1(Being *being, + const StatusEffectDB::OptionsMap &map, + uint16_t option) +{ + for (auto &[opt, id] : map) + being->setStatusEffect(id, option == opt); +} + +static void applyStatusEffectsByOption(Being *being, + const StatusEffectDB::OptionsMap &map, + uint16_t option) +{ + for (auto &[opt, id] : map) + { + const bool enabled = (option & opt) != 0; + being->setStatusEffect(id, enabled); + } +} + +/** + * Maps flags or indexes to their corresponding status effect index and + * updates the state of the given being. This is tmwAthena-specific. + */ +static void applyStatusEffects(Being *being, + uint16_t opt0, + uint16_t opt1, + uint16_t opt2, + std::optional<uint16_t> opt3 = {}) +{ + applyStatusEffectsByOption(being, StatusEffectDB::opt0ToIdMap(), opt0); + applyStatusEffectsByOption1(being, StatusEffectDB::opt1ToIdMap(), opt1); + applyStatusEffectsByOption(being, StatusEffectDB::opt2ToIdMap(), opt2); + if (opt3) + applyStatusEffectsByOption(being, StatusEffectDB::opt3ToIdMap(), *opt3); +} + void BeingHandler::handleMessage(MessageIn &msg) { if (!actorSpriteManager) @@ -159,8 +218,10 @@ void BeingHandler::handleMessage(MessageIn &msg) Uint16 weapon, shield; Uint16 gmstatus; int param1; - int stunMode; - Uint32 statusEffects; + uint16_t opt0; + uint16_t opt1; + uint16_t opt2; + uint16_t opt3; int type, guild; Uint16 status; Being *srcBeing, *dstBeing; @@ -176,9 +237,9 @@ void BeingHandler::handleMessage(MessageIn &msg) // Information about a being in range id = msg.readInt32(); speed = (float)msg.readInt16(); - stunMode = msg.readInt16(); // opt1 - statusEffects = msg.readInt16(); // opt2 - statusEffects |= ((Uint32)msg.readInt16()) << 16; // option + opt1 = msg.readInt16(); + opt2 = msg.readInt16(); + opt0 = msg.readInt16(); job = msg.readInt16(); // class dstBeing = actorSpriteManager->findBeing(id); @@ -209,7 +270,7 @@ void BeingHandler::handleMessage(MessageIn &msg) speed = 150.0f; // In ticks per tile * 10 dstBeing->setMoveSpeed(Vector(speed / 10, speed / 10)); - dstBeing->setSubtype(job); + updateBeingType(dstBeing, job); hairStyle = msg.readInt16(); weapon = msg.readInt16(); headBottom = msg.readInt16(); @@ -236,14 +297,14 @@ void BeingHandler::handleMessage(MessageIn &msg) } msg.readInt16(); // guild emblem msg.readInt16(); // manner - dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + opt3 = msg.readInt16(); msg.readInt8(); // karma gender = msg.readInt8(); 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)); @@ -274,9 +335,7 @@ void BeingHandler::handleMessage(MessageIn &msg) msg.readInt8(); // unknown msg.readInt8(); // unknown / sit - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + applyStatusEffects(dstBeing, opt0, opt1, opt2, opt3); break; case SMSG_BEING_SPAWN: @@ -417,6 +476,9 @@ void BeingHandler::handleMessage(MessageIn &msg) switch (type) { + case LOOK::BASE: + updateBeingType(dstBeing, id); + break; case LOOK::HAIR: { // const int look = id / 256; @@ -505,10 +567,9 @@ void BeingHandler::handleMessage(MessageIn &msg) // An update about a player, potentially including movement. id = msg.readInt32(); speed = msg.readInt16(); - stunMode = msg.readInt16(); // opt1; Aethyra use this as cape - statusEffects = msg.readInt16(); // opt2; Aethyra use this as misc1 - statusEffects |= ((Uint32) msg.readInt16()) - << 16; // status.options; Aethyra uses this as misc2 + opt1 = msg.readInt16(); + opt2 = msg.readInt16(); + opt0 = msg.readInt16(); job = msg.readInt16(); dstBeing = actorSpriteManager->findBeing(id); @@ -531,7 +592,7 @@ void BeingHandler::handleMessage(MessageIn &msg) else dstBeing->setMoveSpeed(Net::getPlayerHandler()->getDefaultMoveSpeed()); - dstBeing->setSubtype(job); + updateBeingType(dstBeing, job); hairStyle = msg.readInt16(); weapon = msg.readInt16(); shield = msg.readInt16(); @@ -545,15 +606,16 @@ void BeingHandler::handleMessage(MessageIn &msg) headTop = msg.readInt16(); headMid = msg.readInt16(); hairColor = msg.readInt16(); - shoes = msg.readInt16(); - gloves = msg.readInt16(); + msg.readInt16(); // clothes_color + msg.readInt8(); // head_dir + msg.readInt8(); // unused2 msg.readInt32(); // guild msg.readInt16(); // emblem msg.readInt16(); // manner - dstBeing->setStatusEffectBlock(32, msg.readInt16()); // opt3 + opt3 = msg.readInt16(); 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); @@ -601,15 +663,13 @@ void BeingHandler::handleMessage(MessageIn &msg) } else if (msg.getId() == SMSG_PLAYER_MOVE) { - msg.readInt8(); // unknown + msg.readInt8(); // five } msg.readInt8(); // Lv - msg.readInt8(); // unknown + msg.readInt8(); // unused - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + applyStatusEffects(dstBeing, opt0, opt1, opt2, opt3); break; case SMSG_PLAYER_STOP: @@ -654,14 +714,12 @@ void BeingHandler::handleMessage(MessageIn &msg) if (!dstBeing) break; - stunMode = msg.readInt16(); - statusEffects = msg.readInt16(); - statusEffects |= ((Uint32) msg.readInt16()) << 16; - msg.readInt8(); // Unused? + opt1 = msg.readInt16(); + opt2 = msg.readInt16(); + opt0 = msg.readInt16(); + msg.readInt8(); // zero - dstBeing->setStunMode(stunMode); - dstBeing->setStatusEffectBlock(0, (statusEffects >> 16) & 0xffff); - dstBeing->setStatusEffectBlock(16, statusEffects & 0xffff); + applyStatusEffects(dstBeing, opt0, opt1, opt2); break; case SMSG_BEING_STATUS_CHANGE: diff --git a/src/net/tmwa/beinghandler.h b/src/net/tmwa/beinghandler.h index f1c8887f..fd8f08f5 100644 --- a/src/net/tmwa/beinghandler.h +++ b/src/net/tmwa/beinghandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_BEINGHANDLER_H -#define NET_TA_BEINGHANDLER_H +#pragma once #include "net/tmwa/messagehandler.h" @@ -39,5 +38,3 @@ class BeingHandler final : public MessageHandler }; } // namespace TmwAthena - -#endif // NET_TA_BEINGHANDLER_H diff --git a/src/net/tmwa/buysellhandler.cpp b/src/net/tmwa/buysellhandler.cpp index 1fdf1ffe..d7acd674 100644 --- a/src/net/tmwa/buysellhandler.cpp +++ b/src/net/tmwa/buysellhandler.cpp @@ -99,7 +99,7 @@ void BuySellHandler::handleMessage(MessageIn &msg) Item *item = PlayerInfo::getInventory()->getItem(index); - if (item && !(item->isEquipped())) + if (item && !item->isEquipped()) dialog->addItem(item, value); } } diff --git a/src/net/tmwa/buysellhandler.h b/src/net/tmwa/buysellhandler.h index 8f7a324f..cad9f943 100644 --- a/src/net/tmwa/buysellhandler.h +++ b/src/net/tmwa/buysellhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_BUYSELLHANDLER_H -#define NET_TA_BUYSELLHANDLER_H +#pragma once #include "net/tmwa/messagehandler.h" @@ -41,5 +40,3 @@ class BuySellHandler final : public MessageHandler }; } // namespace TmwAthena - -#endif // NET_TA_BUYSELLHANDLER_H diff --git a/src/net/tmwa/charserverhandler.cpp b/src/net/tmwa/charserverhandler.cpp index 636b58ce..0ecbb135 100644 --- a/src/net/tmwa/charserverhandler.cpp +++ b/src/net/tmwa/charserverhandler.cpp @@ -28,7 +28,6 @@ #include "gui/charcreatedialog.h" #include "gui/okdialog.h" -#include "net/logindata.h" #include "net/net.h" #include "net/tmwa/gamehandler.h" @@ -210,21 +209,20 @@ void CharServerHandler::readPlayerData(MessageIn &msg, Net::Character *character const Token &token = static_cast<LoginHandler*>(Net::getLoginHandler())->getToken(); - auto *tempPlayer = new LocalPlayer(msg.readInt32(), 0); - tempPlayer->setGender(token.sex); + const int id = msg.readInt32(); character->data.mAttributes[EXP] = msg.readInt32(); character->data.mAttributes[MONEY] = msg.readInt32(); character->data.mStats[JOB].exp = msg.readInt32(); - int temp = msg.readInt32(); + const int temp = msg.readInt32(); character->data.mStats[JOB].base = temp; character->data.mStats[JOB].mod = temp; - tempPlayer->setSprite(SPRITE_SHOE, msg.readInt16()); - tempPlayer->setSprite(SPRITE_GLOVES, msg.readInt16()); - tempPlayer->setSprite(SPRITE_CAPE, msg.readInt16()); - tempPlayer->setSprite(SPRITE_MISC1, msg.readInt16()); + const int shoe = msg.readInt16(); + const int gloves = msg.readInt16(); + const int cape = msg.readInt16(); + const int misc1 = msg.readInt16(); msg.readInt32(); // option msg.readInt32(); // karma @@ -240,8 +238,15 @@ void CharServerHandler::readPlayerData(MessageIn &msg, Net::Character *character const uint16_t race = msg.readInt16(); // class (used for race) int hairStyle = msg.readInt8(); msg.readInt8(); // look - tempPlayer->setSubtype(race); - Uint16 weapon = msg.readInt16(); + const uint16_t weapon = msg.readInt16(); + + auto *tempPlayer = new LocalPlayer(id, race); + tempPlayer->setGender(token.sex); + + tempPlayer->setSprite(SPRITE_SHOE, shoe); + tempPlayer->setSprite(SPRITE_GLOVES, gloves); + tempPlayer->setSprite(SPRITE_CAPE, cape); + tempPlayer->setSprite(SPRITE_MISC1, misc1); tempPlayer->setSprite(SPRITE_WEAPON, weapon, "", true); character->data.mAttributes[LEVEL] = msg.readInt16(); @@ -263,7 +268,7 @@ void CharServerHandler::readPlayerData(MessageIn &msg, Net::Character *character character->slot = msg.readInt8(); // character slot const uint8_t sex = msg.readInt8(); - tempPlayer->setGender(sex ? Gender::MALE : Gender::FEMALE); + tempPlayer->setGender(sex ? Gender::Male : Gender::Female); } void CharServerHandler::setCharSelectDialog(CharSelectDialog *window) @@ -395,7 +400,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 9633c8d9..b0d3e970 100644 --- a/src/net/tmwa/charserverhandler.h +++ b/src/net/tmwa/charserverhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_CHARSERVERHANDLER_H -#define NET_TA_CHARSERVERHANDLER_H +#pragma once #include "net/charhandler.h" @@ -75,9 +74,7 @@ class CharServerHandler final : public MessageHandler, public Net::CharHandler void connect(); private: - void readPlayerData(MessageIn &msg, Net::Character *character); + static void readPlayerData(MessageIn &msg, Net::Character *character); }; } // namespace TmwAthena - -#endif // NET_TA_CHARSERVERHANDLER_H diff --git a/src/net/tmwa/chathandler.cpp b/src/net/tmwa/chathandler.cpp index 4f998922..cce5a41d 100644 --- a/src/net/tmwa/chathandler.cpp +++ b/src/net/tmwa/chathandler.cpp @@ -193,7 +193,10 @@ void ChatHandler::handleMessage(MessageIn &msg) trim(chatMsg); std::string reducedMessage = chatMsg; - chatMsg = removeColors(sender_name) + " : " + reducedMessage; + chatMsg = sender_name; + removeColors(chatMsg); + chatMsg += " : "; + chatMsg += reducedMessage; Event event(Event::Being); event.setString("message", chatMsg); @@ -271,7 +274,7 @@ void ChatHandler::handleMessage(MessageIn &msg) msg.readInt8(); // gm level msg.readInt8(); // gender - Avatar *avatar = new Avatar(nick); + auto *avatar = new Avatar(nick); avatar->setOnline(true); players.push_back(avatar); } diff --git a/src/net/tmwa/chathandler.h b/src/net/tmwa/chathandler.h index d545b221..b16b3dc4 100644 --- a/src/net/tmwa/chathandler.h +++ b/src/net/tmwa/chathandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_CHATHANDLER_H -#define NET_TA_CHATHANDLER_H +#pragma once #include "net/chathandler.h" #include "net/net.h" @@ -73,5 +72,3 @@ class ChatHandler final : public MessageHandler, public Net::ChatHandler }; } // namespace TmwAthena - -#endif // NET_TA_CHATHANDLER_H diff --git a/src/net/tmwa/gamehandler.cpp b/src/net/tmwa/gamehandler.cpp index abc9c73c..0a3bb9d9 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/gamehandler.h b/src/net/tmwa/gamehandler.h index ecd8df2d..2f876b82 100644 --- a/src/net/tmwa/gamehandler.h +++ b/src/net/tmwa/gamehandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_MAPHANDLER_H -#define NET_TA_MAPHANDLER_H +#pragma once #include "eventlistener.h" @@ -74,5 +73,3 @@ class GameHandler final : public MessageHandler, public Net::GameHandler, }; } // namespace TmwAthena - -#endif // NET_TA_MAPHANDLER_H diff --git a/src/net/tmwa/generalhandler.cpp b/src/net/tmwa/generalhandler.cpp index e1b1a9ea..d6eb3b34 100644 --- a/src/net/tmwa/generalhandler.cpp +++ b/src/net/tmwa/generalhandler.cpp @@ -25,7 +25,6 @@ #include "configuration.h" #include "log.h" -#include "gui/inventorywindow.h" #include "gui/skilldialog.h" #include "gui/socialwindow.h" #include "gui/statuswindow.h" @@ -49,7 +48,7 @@ #include "net/tmwa/playerhandler.h" #include "net/tmwa/protocol.h" #include "net/tmwa/tradehandler.h" -#include "net/tmwa/specialhandler.h" +#include "net/tmwa/abilityhandler.h" #include "net/tmwa/gui/guildtab.h" #include "net/tmwa/gui/partytab.h" @@ -60,8 +59,6 @@ #include <list> -extern Net::GeneralHandler *generalHandler; - namespace TmwAthena { ServerInfo charServer; @@ -84,7 +81,7 @@ GeneralHandler::GeneralHandler(): mNpcHandler(new NpcHandler), mPartyHandler(new PartyHandler), mPlayerHandler(new PlayerHandler), - mSpecialHandler(new SpecialHandler), + mAbilityHandler(new AbilityHandler), mTradeHandler(new TradeHandler) { static const Uint16 _messages[] = { @@ -92,7 +89,6 @@ GeneralHandler::GeneralHandler(): 0 }; handledMessages = _messages; - generalHandler = this; std::list<ItemStat> stats; stats.emplace_back("str", _("Strength %+d")); @@ -155,6 +151,7 @@ void GeneralHandler::handleMessage(MessageIn &msg) void GeneralHandler::load() { + // This sets mNetwork to the created Network instance (new Network)->registerHandler(this); mNetwork->registerHandler(mAdminHandler.get()); @@ -169,7 +166,7 @@ void GeneralHandler::load() mNetwork->registerHandler(mLoginHandler.get()); mNetwork->registerHandler(mNpcHandler.get()); mNetwork->registerHandler(mPlayerHandler.get()); - mNetwork->registerHandler(mSpecialHandler.get()); + mNetwork->registerHandler(mAbilityHandler.get()); mNetwork->registerHandler(mTradeHandler.get()); mNetwork->registerHandler(mPartyHandler.get()); } @@ -209,11 +206,6 @@ void GeneralHandler::flushNetwork() } } -void GeneralHandler::clearHandlers() -{ - mNetwork->clearHandlers(); -} - void GeneralHandler::event(Event::Channel channel, const Event &event) { @@ -221,7 +213,6 @@ void GeneralHandler::event(Event::Channel channel, { if (event.getType() == Event::GuiWindowsLoaded) { - inventoryWindow->setSplitAllowed(false); skillDialog->loadSkills(); statusWindow->addAttribute(STRENGTH, _("Strength"), true, ""); diff --git a/src/net/tmwa/generalhandler.h b/src/net/tmwa/generalhandler.h index f105da96..1da81ba8 100644 --- a/src/net/tmwa/generalhandler.h +++ b/src/net/tmwa/generalhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TMWA_GENERALHANDLER_H -#define NET_TMWA_GENERALHANDLER_H +#pragma once #include "eventlistener.h" @@ -49,8 +48,6 @@ class GeneralHandler final : public MessageHandler, public Net::GeneralHandler, void flushNetwork() override; - void clearHandlers() override; - void event(Event::Channel channel, const Event &event) override; protected: @@ -67,10 +64,8 @@ class GeneralHandler final : public MessageHandler, public Net::GeneralHandler, MessageHandlerPtr mNpcHandler; MessageHandlerPtr mPartyHandler; MessageHandlerPtr mPlayerHandler; - MessageHandlerPtr mSpecialHandler; + MessageHandlerPtr mAbilityHandler; MessageHandlerPtr mTradeHandler; }; } // namespace TmwAthena - -#endif // NET_TMWA_GENERALHANDLER_H diff --git a/src/net/tmwa/gui/guildtab.h b/src/net/tmwa/gui/guildtab.h index 3f864748..c51e63d0 100644 --- a/src/net/tmwa/gui/guildtab.h +++ b/src/net/tmwa/gui/guildtab.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef TA_GUILDTAB_H -#define TA_GUILDTAB_H +#pragma once #include "gui/widgets/chattab.h" @@ -49,5 +48,3 @@ class GuildTab : public ChatTab extern GuildTab *guildTab; } // namespace TmwAthena - -#endif // TA_GUILDTAB_H diff --git a/src/net/tmwa/gui/partytab.cpp b/src/net/tmwa/gui/partytab.cpp index 418e0843..ee29757a 100644 --- a/src/net/tmwa/gui/partytab.cpp +++ b/src/net/tmwa/gui/partytab.cpp @@ -32,14 +32,13 @@ #include "resources/theme.h" #include "utils/gettext.h" -#include "utils/stringutils.h" namespace TmwAthena { PartyTab::PartyTab() : ChatTab(_("Party")) { - setTabColor(&Theme::getThemeColor(Theme::PARTY_CHAT_TAB)); + setTabColor(&Theme::getThemeColor(Theme::PARTY_TAB)); } void PartyTab::handleInput(const std::string &msg) diff --git a/src/net/tmwa/gui/partytab.h b/src/net/tmwa/gui/partytab.h index a6c52f58..39a1f978 100644 --- a/src/net/tmwa/gui/partytab.h +++ b/src/net/tmwa/gui/partytab.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef TA_PARTYTAB_H -#define TA_PARTYTAB_H +#pragma once #include "gui/widgets/chattab.h" @@ -49,5 +48,3 @@ class PartyTab : public ChatTab extern PartyTab *partyTab; } // namespace TmwAthena - -#endif // TA_PARTYTAB_H diff --git a/src/net/tmwa/guildhandler.cpp b/src/net/tmwa/guildhandler.cpp index 1877f0f1..e8ee4848 100644 --- a/src/net/tmwa/guildhandler.cpp +++ b/src/net/tmwa/guildhandler.cpp @@ -40,11 +40,6 @@ Guild *taGuild; GuildHandler::GuildHandler() { - static const Uint16 _messages[] = { - 0 - }; - handledMessages = _messages; - guildHandler = this; } diff --git a/src/net/tmwa/guildhandler.h b/src/net/tmwa/guildhandler.h index 9bbe9b4a..6faca0cc 100644 --- a/src/net/tmwa/guildhandler.h +++ b/src/net/tmwa/guildhandler.h @@ -18,8 +18,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_GUILDHANDLER_H -#define NET_TA_GUILDHANDLER_H +#pragma once #include "net/guildhandler.h" @@ -67,5 +66,3 @@ class GuildHandler final : public Net::GuildHandler, public MessageHandler }; } - -#endif // NET_TA_GUILDHANDLER_H diff --git a/src/net/tmwa/inventoryhandler.cpp b/src/net/tmwa/inventoryhandler.cpp index 496ce621..0d8e3005 100644 --- a/src/net/tmwa/inventoryhandler.cpp +++ b/src/net/tmwa/inventoryhandler.cpp @@ -521,11 +521,6 @@ void InventoryHandler::event(Event::Channel channel, } } -bool InventoryHandler::canSplit(const Item *item) -{ - return false; -} - size_t InventoryHandler::getSize(int type) const { switch (type) diff --git a/src/net/tmwa/inventoryhandler.h b/src/net/tmwa/inventoryhandler.h index 51a0fe51..f5ef4492 100644 --- a/src/net/tmwa/inventoryhandler.h +++ b/src/net/tmwa/inventoryhandler.h @@ -19,11 +19,11 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_INVENTORYHANDLER_H -#define NET_TA_INVENTORYHANDLER_H +#pragma once #include "eventlistener.h" #include "inventory.h" +#include "item.h" #include "log.h" #include "playerinfo.h" @@ -38,7 +38,7 @@ #include "utils/gettext.h" -#include <list> +#include <vector> namespace TmwAthena { @@ -166,8 +166,6 @@ class InventoryHandler final : public MessageHandler, public Net::InventoryHandl void event(Event::Channel channel, const Event &event) override; - bool canSplit(const Item *item) override; - size_t getSize(int type) const override; // Note the slot type id is equal to the slot Index for tA. @@ -195,5 +193,3 @@ class InventoryHandler final : public MessageHandler, public Net::InventoryHandl }; } // namespace TmwAthena - -#endif // NET_TA_INVENTORYHANDLER_H diff --git a/src/net/tmwa/itemhandler.h b/src/net/tmwa/itemhandler.h index 0c6175d8..5e42e0d8 100644 --- a/src/net/tmwa/itemhandler.h +++ b/src/net/tmwa/itemhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_ITEMHANDLER_H -#define NET_TA_ITEMHANDLER_H +#pragma once #include "net/tmwa/messagehandler.h" @@ -35,5 +34,3 @@ class ItemHandler final : public MessageHandler }; } // namespace TmwAthena - -#endif // NET_TA_ITEMHANDLER_H diff --git a/src/net/tmwa/loginhandler.cpp b/src/net/tmwa/loginhandler.cpp index 24bc9ab2..a7162ee6 100644 --- a/src/net/tmwa/loginhandler.cpp +++ b/src/net/tmwa/loginhandler.cpp @@ -103,17 +103,15 @@ void LoginHandler::handleMessage(MessageIn &msg) } break; - case SMSG_UPDATE_HOST: - int len; - - len = msg.readInt16() - 4; + case SMSG_UPDATE_HOST: { + int len = msg.readInt16() - 4; mUpdateHost = msg.readString(len); loginData.updateHost = mUpdateHost; logger->log("Received update host \"%s\" from login server.", mUpdateHost.c_str()); break; - + } case SMSG_LOGIN_DATA: // Skip the length word msg.skip(2); @@ -126,7 +124,7 @@ void LoginHandler::handleMessage(MessageIn &msg) mToken.account_ID = msg.readInt32(); mToken.session_ID2 = msg.readInt32(); msg.skip(30); // unused - mToken.sex = msg.readInt8() ? Gender::MALE : Gender::FEMALE; + mToken.sex = msg.readInt8() ? Gender::Male : Gender::Female; for (int i = 0; i < worldCount; i++) { @@ -306,7 +304,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/loginhandler.h b/src/net/tmwa/loginhandler.h index 25dd414d..f6b8a530 100644 --- a/src/net/tmwa/loginhandler.h +++ b/src/net/tmwa/loginhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TMWA_LOGINHANDLER_H -#define NET_TMWA_LOGINHANDLER_H +#pragma once #include "net/loginhandler.h" @@ -94,5 +93,3 @@ class LoginHandler final : public MessageHandler, public Net::LoginHandler }; } // namespace TmwAthena - -#endif // NET_TA_LOGINHANDLER_H diff --git a/src/net/tmwa/messagehandler.h b/src/net/tmwa/messagehandler.h index 0d278c15..8e3c6a19 100644 --- a/src/net/tmwa/messagehandler.h +++ b/src/net/tmwa/messagehandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_MESSAGEHANDLER_H -#define NET_TA_MESSAGEHANDLER_H +#pragma once #include "net/messagehandler.h" @@ -52,5 +51,3 @@ class MessageHandler : public Net::MessageHandler using MessageHandlerPtr = const std::unique_ptr<MessageHandler>; } - -#endif // NET_TA_MESSAGEHANDLER_H diff --git a/src/net/tmwa/messagein.cpp b/src/net/tmwa/messagein.cpp index 7c142619..c0db0fca 100644 --- a/src/net/tmwa/messagein.cpp +++ b/src/net/tmwa/messagein.cpp @@ -21,6 +21,9 @@ #include "net/tmwa/messagein.h" +#include "being.h" +#include "net/tmwa/protocol.h" + #include <SDL_endian.h> #define MAKEWORD(low,high) \ @@ -88,38 +91,20 @@ void MessageIn::readCoordinates(uint16_t &x, uint16_t &y, uint8_t &direction) direction = data[2] & 0x000f; // Translate from tmwAthena format - switch (direction) + switch (static_cast<DIR>(direction)) { - case 0: - direction = 1; - break; - case 1: - direction = 3; - break; - case 2: - direction = 2; - break; - case 3: - direction = 6; - break; - case 4: - direction = 4; - break; - case 5: - direction = 12; - break; - case 6: - direction = 8; - break; - case 7: - direction = 9; - break; - case 8: - direction = 8; - break; + case DIR::S: direction = Being::DOWN; break; + case DIR::SW: direction = Being::DOWN | Being::LEFT; break; + case DIR::W: direction = Being::LEFT; break; + case DIR::NW: direction = Being::UP | Being::LEFT; break; + case DIR::N: direction = Being::UP; break; + case DIR::NE: direction = Being::UP | Being::RIGHT; break; + case DIR::E: direction = Being::RIGHT; break; + case DIR::SE: direction = Being::DOWN | Being::RIGHT; break; default: // OOPSIE! Impossible or unknown direction = 0; + break; } } mPos += 3; @@ -162,7 +147,7 @@ std::string MessageIn::readString(int length) if (length < 0 || mPos + length > mLength) { mPos = mLength + 1; - return ""; + return std::string(); } // Read the string diff --git a/src/net/tmwa/messagein.h b/src/net/tmwa/messagein.h index 2f66ca28..b2fb6716 100644 --- a/src/net/tmwa/messagein.h +++ b/src/net/tmwa/messagein.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_MESSAGEIN_H -#define NET_TA_MESSAGEIN_H +#pragma once #include <cstdint> #include <string> @@ -109,5 +108,3 @@ class MessageIn }; } // TmwAthena - -#endif // NET_TA_MESSAGEIN_H diff --git a/src/net/tmwa/messageout.cpp b/src/net/tmwa/messageout.cpp index 12c9419a..a886fb4d 100644 --- a/src/net/tmwa/messageout.cpp +++ b/src/net/tmwa/messageout.cpp @@ -31,6 +31,9 @@ namespace TmwAthena { MessageOut::MessageOut(uint16_t id) { +#ifdef DEBUG + logger->log("Sending %s (0x%x)", Network::mInstance->messageName(id), id); +#endif writeInt16(id); } diff --git a/src/net/tmwa/messageout.h b/src/net/tmwa/messageout.h index b60644de..ba2d3c75 100644 --- a/src/net/tmwa/messageout.h +++ b/src/net/tmwa/messageout.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_MESSAGEOUT_H -#define NET_TA_MESSAGEOUT_H +#pragma once #include <cstdint> #include <string> @@ -73,5 +72,3 @@ class MessageOut }; } // namespace TmwAthena - -#endif // NET_TA_MESSAGEOUT_H diff --git a/src/net/tmwa/network.cpp b/src/net/tmwa/network.cpp index 5a2dd0d0..b448dc4f 100644 --- a/src/net/tmwa/network.cpp +++ b/src/net/tmwa/network.cpp @@ -45,9 +45,9 @@ struct PacketInfo }; // indicator for a variable-length packet -const uint16_t VAR = 1; +constexpr uint16_t VAR = 1; -static const PacketInfo packet_infos[] = { +static constexpr PacketInfo packet_infos[] = { // login server messages { SMSG_UPDATE_HOST, VAR, "SMSG_UPDATE_HOST" }, { CMSG_LOGIN_REGISTER, 55, "CMSG_LOGIN_REGISTER" }, @@ -331,20 +331,16 @@ void Network::disconnect() void Network::registerHandler(MessageHandler *handler) { - for (const Uint16 *i = handler->handledMessages; *i; ++i) - { + for (const uint16_t *i = handler->handledMessages; *i; ++i) mMessageHandlers[*i] = handler; - } handler->setNetwork(this); } void Network::unregisterHandler(MessageHandler *handler) { - for (const Uint16 *i = handler->handledMessages; *i; ++i) - { + for (const uint16_t *i = handler->handledMessages; *i; ++i) mMessageHandlers.erase(*i); - } handler->setNetwork(nullptr); } @@ -352,12 +348,20 @@ void Network::unregisterHandler(MessageHandler *handler) void Network::clearHandlers() { for (auto& [_, messageHandler] : mMessageHandlers) - { messageHandler->setNetwork(nullptr); - } + mMessageHandlers.clear(); } +const char *Network::messageName(uint16_t id) const +{ + auto packetInfoIt = mPacketInfo.find(id); + if (packetInfoIt != mPacketInfo.end()) + return packetInfoIt->second->name; + + return "Unknown"; +} + void Network::dispatchMessages() { MutexLocker lock(&mMutex); diff --git a/src/net/tmwa/network.h b/src/net/tmwa/network.h index fa0237dd..b27d1eda 100644 --- a/src/net/tmwa/network.h +++ b/src/net/tmwa/network.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_NETWORK_H -#define NET_TA_NETWORK_H +#pragma once #include "utils/mutex.h" @@ -67,6 +66,8 @@ class Network void clearHandlers(); + const char *messageName(uint16_t id) const; + int getState() const { return mState; } const std::string &getError() const { return mError; } @@ -125,5 +126,3 @@ class Network }; } // namespace TmwAthena - -#endif // NET_TA_NETWORK_H diff --git a/src/net/tmwa/npchandler.h b/src/net/tmwa/npchandler.h index b55a8155..df23531f 100644 --- a/src/net/tmwa/npchandler.h +++ b/src/net/tmwa/npchandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_NPCHANDLER_H -#define NET_TA_NPCHANDLER_H +#pragma once #include "net/npchandler.h" @@ -65,5 +64,3 @@ class NpcHandler final : public MessageHandler, public Net::NpcHandler }; } // namespace TmwAthena - -#endif // NET_TA_NPCHANDLER_H diff --git a/src/net/tmwa/partyhandler.h b/src/net/tmwa/partyhandler.h index 14c6d9f3..3f99de20 100644 --- a/src/net/tmwa/partyhandler.h +++ b/src/net/tmwa/partyhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_PARTYHANDLER_H -#define NET_TA_PARTYHANDLER_H +#pragma once #include "net/net.h" #include "net/partyhandler.h" @@ -71,5 +70,3 @@ class PartyHandler final : public MessageHandler, public Net::PartyHandler }; } // namespace TmwAthena - -#endif // NET_TA_PARTYHANDLER_H diff --git a/src/net/tmwa/playerhandler.h b/src/net/tmwa/playerhandler.h index 1a90532e..f1a67e94 100644 --- a/src/net/tmwa/playerhandler.h +++ b/src/net/tmwa/playerhandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_PLAYERHANDLER_H -#define NET_TA_PLAYERHANDLER_H +#pragma once #include "net/net.h" #include "net/playerhandler.h" @@ -67,5 +66,3 @@ class PlayerHandler final : public MessageHandler, public Net::PlayerHandler }; } // namespace TmwAthena - -#endif // NET_TA_PLAYERHANDLER_H diff --git a/src/net/tmwa/protocol.h b/src/net/tmwa/protocol.h index 609b18a5..532ac90e 100644 --- a/src/net/tmwa/protocol.h +++ b/src/net/tmwa/protocol.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef TA_PROTOCOL_H -#define TA_PROTOCOL_H +#pragma once #include <cstdint> @@ -80,6 +79,20 @@ enum class LOOK : uint8_t MISC2 = 13, }; +enum class DIR : uint8_t +{ + S = 0, + SW = 1, + W = 2, + NW = 3, + N = 4, + NE = 5, + E = 6, + SE = 7, + + COUNT, +}; + enum NpcCommand { NPC_REQUEST_LANG = 0, @@ -283,5 +296,3 @@ enum { }; } - -#endif diff --git a/src/net/tmwa/token.h b/src/net/tmwa/token.h index c0a2b3c8..b563bf65 100644 --- a/src/net/tmwa/token.h +++ b/src/net/tmwa/token.h @@ -21,8 +21,7 @@ #include "being.h" -#ifndef NET_TA_TOKEN_H -#define NET_TA_TOKEN_H +#pragma once struct Token { @@ -36,8 +35,6 @@ struct Token account_ID = 0; session_ID1 = 0; session_ID2 = 0; - sex = Gender::UNSPECIFIED; + sex = Gender::Unspecified; } }; - -#endif // NET_TA_TOKEN_H diff --git a/src/net/tmwa/tradehandler.cpp b/src/net/tmwa/tradehandler.cpp index 60732eef..c129cfd4 100644 --- a/src/net/tmwa/tradehandler.cpp +++ b/src/net/tmwa/tradehandler.cpp @@ -131,7 +131,7 @@ void TradeHandler::handleMessage(MessageIn &msg) "doesn't exist.")); break; case 2: // Invite request check failed... - serverNotice(_("Trade cancelled due to an unknown " + serverNotice(_("Trade canceled due to an unknown " "reason.")); break; case 3: // Trade accepted @@ -140,11 +140,11 @@ void TradeHandler::handleMessage(MessageIn &msg) tradePartnerName.c_str())); tradeWindow->setVisible(true); break; - case 4: // Trade cancelled + case 4: // Trade canceled if (player_relations.hasPermission(tradePartnerName, PlayerPermissions::SPEECH_LOG)) { - serverNotice(strprintf(_("Trade with %s cancelled."), + serverNotice(strprintf(_("Trade with %s canceled."), tradePartnerName.c_str())); } // otherwise ignore silently diff --git a/src/net/tmwa/tradehandler.h b/src/net/tmwa/tradehandler.h index fa7ec034..1a2cfcef 100644 --- a/src/net/tmwa/tradehandler.h +++ b/src/net/tmwa/tradehandler.h @@ -19,8 +19,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef NET_TA_TRADEHANDLER_H -#define NET_TA_TRADEHANDLER_H +#pragma once #include "net/net.h" #include "net/tradehandler.h" @@ -57,5 +56,3 @@ class TradeHandler final : public MessageHandler, public Net::TradeHandler }; } // namespace TmwAthena - -#endif // NET_TA_TRADEHANDLER_H |