#pragma once // clif.t.hpp - Network interface to the client. // // Copyright © ????-2004 Athena Dev Teams // Copyright © 2004-2011 The Mana World Development Team // Copyright © 2011-2014 Ben Longbons // // This file is part of The Mana World (Athena server) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "fwd.hpp" #include #include "../ints/little.hpp" #include "../compat/iter.hpp" #include "../generic/enum.hpp" #include "consts.hpp" #include "enums.hpp" namespace tmwa { namespace e { // [Fate] status.option properties. These are persistent status changes. // IDs that are not listed are not used in the code (to the best of my knowledge) enum class Opt0 : uint16_t { ZERO = 0x0000, // [Fate] This is the GM `@hide' flag HIDE = 0x0040, // [Fate] Complete invisibility to other clients INVISIBILITY = 0x1000, // ? REAL_ANY_HIDE = HIDE, }; enum class Opt1 : uint16_t { ZERO = 0, _stone1 = 1, _freeze = 2, _stan = 3, _sleep = 4, _stone6 = 6, }; enum class Opt2 : uint16_t { ZERO = 0x0000, _poison = 0x0001, _curse = 0x0002, _silence = 0x0004, BLIND = 0x0010, _speedpotion0 = 0x0020, _signumcrucis = 0x0040, _atkpot = 0x0080, _heal = 0x0100, _slowpoison = 0x0200, }; enum class Opt3 : uint16_t { ZERO = 0x0000, _concentration = 0x0001, _overthrust = 0x0002, _energycoat = 0x0004, _explosionspirits = 0x0008, _steelbody = 0x0010, _berserk = 0x0080, _marionette = 0x0400, _assumptio = 0x0800, }; ENUM_BITWISE_OPERATORS(Opt0) ENUM_BITWISE_OPERATORS(Opt2) ENUM_BITWISE_OPERATORS(Opt3) } using e::Opt0; using e::Opt1; using e::Opt2; using e::Opt3; enum class ItemType : uint8_t { USE = 0, // in eA, healing only _1 = 1, // unused _2 = 2, // in eA, other usable items JUNK = 3, // "useless" items (e.g. quests) WEAPON = 4, // all weapons ARMOR = 5, // all other equipment _6 = 6, // in eA, card _7 = 7, // in eA, pet egg _8 = 8, // in eA, pet equipment _9 = 9, // unused ARROW = 10, // ammo _11 = 11, // in eA, delayed use (special script) }; enum class BeingRemoveWhy : uint8_t { // general disappearance GONE = 0, // only case handled specially in client DEAD = 1, QUIT = 2, WARPED = 3, // handled specially in clif_clearchar - sent as 0 over network DISGUISE = 9, // handled speciall in mob_warp - not actually sent over network NEGATIVE1 = 0xff, }; enum class PickupFail : uint8_t { OKAY = 0, BAD_ITEM = 1, TOO_HEAVY = 2, TOO_FAR = 3, INV_FULL = 4, STACK_FULL = 5, DROP_STEAL = 6, }; // this is used for both input and output // different values are valid in 0x0089 vs 0x008a enum class DamageType : uint8_t { NORMAL = 0x00, TAKEITEM = 0x01, SIT = 0x02, STAND = 0x03, RETURNED = 0x04, CONTINUOUS = 0x07, DOUBLED = 0x08, CRITICAL = 0x0a, FLEE2 = 0x0b, }; 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, COUNT, }; // Note: there is also a typedef by this name in // but we should be fine since we never include it. // (in the long term we should still rename this though) enum class DIR : uint8_t { S = 0, SW = 1, W = 2, NW = 3, N = 4, NE = 5, E = 6, SE = 7, COUNT, }; constexpr earray dirx //= {{ 0, -1, -1, -1, 0, 1, 1, 1, }}, diry //= {{ 1, 1, 0, -1, -1, -1, 0, 1, }}; constexpr bool dir_is_diagonal(DIR d) { return static_cast(d) & 1; } enum class SP : uint16_t { // sent to client SPEED = 0, // when used as "no stat" ZERO = 0, // sent to client BASEEXP = 1, // sent to client JOBEXP = 2, #if 0 KARMA = 3, #endif // sent to client HP = 5, // sent to client MAXHP = 6, // sent to client SP = 7, // sent to client MAXSP = 8, // sent to client STATUSPOINT = 9, // sent to client HEALXP = 10, // sent to client BASELEVEL = 11, // sent to client SKILLPOINT = 12, // sent to client STR = 13, // sent to client AGI = 14, // sent to client VIT = 15, // sent to client INT = 16, // sent to client DEX = 17, // sent to client LUK = 18, CLASS = 19, // sent to client ZENY = 20, SEX = 21, // sent to client NEXTBASEEXP = 22, // sent to client NEXTJOBEXP = 23, // sent to client WEIGHT = 24, // sent to client MAXWEIGHT = 25, // sent to client USTR = 32, // sent to client UAGI = 33, // sent to client UVIT = 34, // sent to client UINT = 35, // sent to client UDEX = 36, // sent to client ULUK = 37, // sent to client ATK1 = 41, // sent to client ATK2 = 42, // sent to client MATK1 = 43, // sent to client MATK2 = 44, // sent to client DEF1 = 45, // sent to client DEF2 = 46, // sent to client MDEF1 = 47, // sent to client MDEF2 = 48, // sent to client HIT = 49, // sent to client FLEE1 = 50, // sent to client FLEE2 = 51, // sent to client CRITICAL = 52, // sent to client ASPD = 53, // sent to client JOBLEVEL = 55, PARTNER = 57, #if 0 CART = 58, FAME = 59, UNBREAKABLE = 60, #endif // stats from equipment // sent to client STR2 = 61, // sent to client AGI2 = 62, // sent to client VIT2 = 63, // sent to client INT2 = 64, // sent to client DEX2 = 65, // sent to client LUK2 = 66, DEAF = 70, // sent to client GM = 500, // sent to client ATTACKRANGE = 1000, ELTLVL = 1001, ELTTYPE = 1002, #if 0 CASTRATE = 1003, #endif MAXHPRATE = 1004, MAXSPRATE = 1005, #if 0 SPRATE = 1006, // mana is subtracted at serverdata this can only become useable if spells are handled by servercode #endif #if 0 ADDEFF = 1012, #endif #if 0 RESEFF = 1013, #endif BASE_ATK = 1014, ASPD_RATE = 1015, HP_RECOV_RATE = 1016, SP_RECOV_RATE = 1017, SPEED_RATE = 1018, CRITICAL_DEF = 1019, #if 0 NEAR_ATK_DEF = 1020, #endif #if 0 LONG_ATK_DEF = 1021, #endif DOUBLE_RATE = 1022, DOUBLE_ADD_RATE = 1023, #if 0 MATK = 1024, #endif MATK_RATE = 1025, #if 0 IGNORE_DEF_ELE = 1026, #endif #if 0 IGNORE_DEF_RACE = 1027, #endif ATK_RATE = 1028, SPEED_ADDRATE = 1029, ASPD_ADDRATE = 1030, #if 0 MAGIC_ATK_DEF = 1031, #endif #if 0 MISC_ATK_DEF = 1032, #endif #if 0 IGNORE_MDEF_ELE = 1033, #endif #if 0 IGNORE_MDEF_RACE = 1034, #endif PERFECT_HIT_RATE = 1038, PERFECT_HIT_ADD_RATE = 1039, CRITICAL_RATE = 1040, #if 0 GET_ZENY_NUM = 1041, #endif #if 0 ADD_GET_ZENY_NUM = 1042, #endif #if 0 ADD_MONSTER_DROP_ITEM = 1047, #endif #if 0 DEF_RATIO_ATK_ELE = 1048, #endif #if 0 DEF_RATIO_ATK_RACE = 1049, #endif ADD_SPEED = 1050, HIT_RATE = 1051, FLEE_RATE = 1052, FLEE2_RATE = 1053, DEF_RATE = 1054, DEF2_RATE = 1055, MDEF_RATE = 1056, MDEF2_RATE = 1057, #if 0 SPLASH_RANGE = 1058, #endif #if 0 SPLASH_ADD_RANGE = 1059, #endif HP_DRAIN_RATE = 1061, SP_DRAIN_RATE = 1062, #if 0 SHORT_WEAPON_DAMAGE_RETURN = 1063, #endif #if 0 LONG_WEAPON_DAMAGE_RETURN = 1064, #endif #if 0 ADDEFF2 = 1067, #endif #if 0 BREAK_WEAPON_RATE = 1068, #endif #if 0 BREAK_ARMOR_RATE = 1069, #endif #if 0 ADD_STEAL_RATE = 1070, #endif #if 0 MAGIC_DAMAGE_RETURN = 1071, #endif #if 0 RANDOM_ATTACK_INCREASE = 1072, #endif POS_X = 1074, POS_Y = 1075, PVP_CHANNEL = 1076, BL_ID = 1077, BL_TYPE = 1078, CHAR_ID = 1079, INVISIBLE = 1080, HIDDEN = 1081, MUTE_GLOBAL = 1082, MUTE_WHISPER = 1083, MUTE_PARTY = 1084, MUTE_GUILD = 1085, AUTOMOD = 1086, }; constexpr SP attr_to_sp(ATTR attr) { return static_cast(static_cast(attr) + static_cast(SP::STR)); } constexpr ATTR sp_to_attr(SP sp) { return static_cast(static_cast(sp) - static_cast(SP::STR)); } constexpr SP attr_to_usp(ATTR attr) { return static_cast(static_cast(attr) + static_cast(SP::USTR)); } constexpr ATTR usp_to_attr(SP sp) { return static_cast(static_cast(sp) - static_cast(SP::USTR)); } constexpr SP sp_to_usp(SP sp) { return attr_to_usp(sp_to_attr(sp)); } constexpr SP usp_to_sp(SP sp) { return attr_to_sp(usp_to_attr(sp)); } // xxxx xxxx xxyy yyyy yyyy dddd struct NetPosition1 { Byte data[3]; }; struct Position1 { uint16_t x, y; DIR dir; }; inline bool native_to_network(NetPosition1 *network, Position1 native) { uint16_t x = native.x; uint16_t y = native.y; uint8_t d = static_cast(native.dir); uint8_t *p = reinterpret_cast(network); p[0] = x >> 2; p[1] = (x << 6) | ((y >> 4) & 0x3f); p[2] = y << 4 | d; return x < 1024 && y < 1024 && d < 16; } inline bool network_to_native(Position1 *native, NetPosition1 network) { const uint8_t *p = reinterpret_cast(&network); native->x = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); native->y = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); uint8_t d = p[2] & 0x0f; native->dir = static_cast(d); return d < 8; } // x0xx xxxx xxy0 yyyy yyyy x1xx xxxx xxy1 yyyy yyyy struct NetPosition2 { Byte data[5]; }; struct Position2 { uint16_t x0, y0; uint16_t x1, y1; }; inline bool native_to_network(NetPosition2 *network, Position2 native) { uint16_t x0 = native.x0; uint16_t y0 = native.y0; uint16_t x1 = native.x1; uint16_t y1 = native.y1; uint8_t *p = reinterpret_cast(network); p[0] = x0 >> 2; p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f); p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f); p[3] = (x1 << 2) | ((y1 >> 8) & 0x03); p[4] = y1; return x0 < 1024 && y0 < 1024 && x1 < 1024 && y1 < 1024; } inline bool network_to_native(Position2 *native, NetPosition2 network) { const uint8_t *p = reinterpret_cast(&network); native->x0 = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); native->y0 = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); native->x1 = (p[2] & (0x3ff >> 6)) << 6 | p[3] >> (8 - 6); native->y1 = (p[3] & (0x3ff >> 8)) << 8 | p[4] >> (8 - 8); return true; } struct IOff2; struct SOff1; struct IOff0 { uint16_t index; bool ok() const { return get0() < MAX_INVENTORY; } uint16_t get0() const { return index; } static IOff0 from(uint16_t i) { return IOff0{i}; } static IteratorPair> iter() { return {IOff0::from(0), IOff0::from(MAX_INVENTORY)}; } friend uint16_t convert_for_printf(IOff0 i0) { return i0.index; } IOff0& operator ++() { ++index; return *this; } friend bool operator == (IOff0 l, IOff0 r) { return l.index == r.index; } friend bool operator != (IOff0 l, IOff0 r) { return !(l == r); } IOff2 shift() const; IOff0() : index(0) {} private: explicit IOff0(uint16_t i) : index(i) {} }; struct SOff0 { uint16_t index; bool ok() const { return get0() < MAX_STORAGE; } uint16_t get0() const { return index; } static SOff0 from(uint16_t i) { return SOff0{i}; } static IteratorPair> iter() { return {SOff0::from(0), SOff0::from(MAX_STORAGE)}; } friend uint16_t convert_for_printf(SOff0 s0) { return s0.index; } SOff0& operator ++() { ++index; return *this; } friend bool operator == (SOff0 l, SOff0 r) { return l.index == r.index; } friend bool operator != (SOff0 l, SOff0 r) { return !(l == r); } SOff1 shift() const; SOff0() : index(0) {} private: explicit SOff0(uint16_t i) : index(i) {} }; struct IOff2 { uint16_t index; bool ok() const { return get2() < MAX_INVENTORY; } uint16_t get2() const { return index - 2; } static IOff2 from(uint16_t i) { return IOff2{static_cast(i + 2)}; } static IteratorPair> iter() { return {IOff2::from(0), IOff2::from(MAX_INVENTORY)}; } IOff2& operator ++() { ++index; return *this; } friend bool operator == (IOff2 l, IOff2 r) { return l.index == r.index; } friend bool operator != (IOff2 l, IOff2 r) { return !(l == r); } IOff0 unshift() const { return IOff0::from(get2()); } IOff2() : index(0) {} private: explicit IOff2(uint16_t i) : index(i) {} }; struct SOff1 { uint16_t index; bool ok() const { return get1() < MAX_STORAGE; } uint16_t get1() const { return index - 1; } static SOff1 from(uint16_t i) { return SOff1{static_cast(i + 1)}; } static IteratorPair> iter() { return {SOff1::from(0), SOff1::from(MAX_STORAGE)}; } SOff1& operator ++() { ++index; return *this; } friend bool operator == (SOff1 l, SOff1 r) { return l.index == r.index; } friend bool operator != (SOff1 l, SOff1 r) { return !(l == r); } SOff0 unshift() const { return SOff0::from(get1()); } SOff1() : index(0) {} private: explicit SOff1(uint16_t i) : index(i) {} }; inline IOff2 IOff0::shift() const { return IOff2::from(get0()); } inline SOff1 SOff0::shift() const { return SOff1::from(get0()); } inline bool native_to_network(Little16 *network, IOff2 native) { return native_to_network(network, native.index); } inline bool network_to_native(IOff2 *native, Little16 network) { return network_to_native(&native->index, network); } inline bool native_to_network(Little16 *network, SOff1 native) { return native_to_network(network, native.index); } inline bool network_to_native(SOff1 *native, Little16 network) { return network_to_native(&native->index, network); } } // namespace tmwa