diff options
Diffstat (limited to 'src/mmo')
-rw-r--r-- | src/mmo/clif.t.hpp | 717 | ||||
-rw-r--r-- | src/mmo/config_parse.hpp | 2 | ||||
-rw-r--r-- | src/mmo/core.cpp | 161 | ||||
-rw-r--r-- | src/mmo/core.hpp | 49 | ||||
-rw-r--r-- | src/mmo/cxxstdio_enums.hpp | 77 | ||||
-rw-r--r-- | src/mmo/extract.cpp | 280 | ||||
-rw-r--r-- | src/mmo/extract.hpp | 240 | ||||
-rw-r--r-- | src/mmo/extract_enums.cpp | 59 | ||||
-rw-r--r-- | src/mmo/extract_enums.hpp | 6 | ||||
-rw-r--r-- | src/mmo/extract_test.cpp | 448 | ||||
-rw-r--r-- | src/mmo/fwd.hpp | 32 | ||||
-rw-r--r-- | src/mmo/human_time_diff.cpp | 68 | ||||
-rw-r--r-- | src/mmo/human_time_diff.hpp | 45 | ||||
-rw-r--r-- | src/mmo/ids.cpp | 42 | ||||
-rw-r--r-- | src/mmo/ids.hpp | 17 | ||||
-rw-r--r-- | src/mmo/login.t.hpp (renamed from src/mmo/md5more.hpp) | 34 | ||||
-rw-r--r-- | src/mmo/md5more.cpp | 159 | ||||
-rw-r--r-- | src/mmo/mmo.hpp | 71 | ||||
-rw-r--r-- | src/mmo/skill.t.hpp | 136 | ||||
-rw-r--r-- | src/mmo/strs.hpp | 33 | ||||
-rw-r--r-- | src/mmo/utils.cpp | 123 | ||||
-rw-r--r-- | src/mmo/utils.hpp | 167 | ||||
-rw-r--r-- | src/mmo/version.cpp | 2 | ||||
-rw-r--r-- | src/mmo/version.hpp | 2 |
24 files changed, 1170 insertions, 1800 deletions
diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp new file mode 100644 index 0000000..0a51523 --- /dev/null +++ b/src/mmo/clif.t.hpp @@ -0,0 +1,717 @@ +#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 <b.r.longbons@gmail.com> +// +// 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 <http://www.gnu.org/licenses/>. + +#include "fwd.hpp" + +#include <cstdint> + +#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 <dirent.h> +// 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<int, DIR, DIR::COUNT> 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<uint8_t>(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 + 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, + +#if 0 + PARTNER = 57, + CART = 58, + FAME = 59, + UNBREAKABLE = 60, +#endif + + DEAF = 70, + + // sent to client + GM = 500, + + // sent to client + ATTACKRANGE = 1000, +#if 0 + ATKELE = 1001, +#endif +#if 0 + DEFELE = 1002, +#endif +#if 0 + CASTRATE = 1003, +#endif + MAXHPRATE = 1004, +#if 0 + MAXSPRATE = 1005, +#endif +#if 0 + SPRATE = 1006, +#endif + +#if 0 + ADDEFF = 1012, +#endif +#if 0 + RESEFF = 1013, +#endif + BASE_ATK = 1014, + ASPD_RATE = 1015, + HP_RECOV_RATE = 1016, +#if 0 + SP_RECOV_RATE = 1017, +#endif +#if 0 + SPEED_RATE = 1018, +#endif + CRITICAL_DEF = 1019, +#if 0 + NEAR_ATK_DEF = 1020, +#endif +#if 0 + LONG_ATK_DEF = 1021, +#endif +#if 0 + DOUBLE_RATE = 1022, +#endif + DOUBLE_ADD_RATE = 1023, +#if 0 + MATK = 1024, +#endif +#if 0 + MATK_RATE = 1025, +#endif +#if 0 + IGNORE_DEF_ELE = 1026, +#endif +#if 0 + IGNORE_DEF_RACE = 1027, +#endif +#if 0 + ATK_RATE = 1028, +#endif + SPEED_ADDRATE = 1029, +#if 0 + ASPD_ADDRATE = 1030, +#endif +#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 + +#if 0 + PERFECT_HIT_RATE = 1038, +#endif +#if 0 + PERFECT_HIT_ADD_RATE = 1039, +#endif +#if 0 + CRITICAL_RATE = 1040, +#endif +#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 +#if 0 + ADD_SPEED = 1050, +#endif +#if 0 + HIT_RATE = 1051, +#endif +#if 0 + FLEE_RATE = 1052, +#endif +#if 0 + FLEE2_RATE = 1053, +#endif + DEF_RATE = 1054, + DEF2_RATE = 1055, +#if 0 + MDEF_RATE = 1056, +#endif +#if 0 + MDEF2_RATE = 1057, +#endif +#if 0 + SPLASH_RANGE = 1058, +#endif +#if 0 + SPLASH_ADD_RANGE = 1059, +#endif + + HP_DRAIN_RATE = 1061, +#if 0 + SP_DRAIN_RATE = 1062, +#endif +#if 0 + SHORT_WEAPON_DAMAGE_RETURN = 1063, +#endif +#if 0 + LONG_WEAPON_DAMAGE_RETURN = 1064, +#endif + +#if 0 + ADDEFF2 = 1067, +#endif + BREAK_WEAPON_RATE = 1068, + BREAK_ARMOR_RATE = 1069, + ADD_STEAL_RATE = 1070, + MAGIC_DAMAGE_RETURN = 1071, +#if 0 + RANDOM_ATTACK_INCREASE = 1072, +#endif +}; + +constexpr +SP attr_to_sp(ATTR attr) +{ + return static_cast<SP>(static_cast<uint16_t>(attr) + static_cast<uint16_t>(SP::STR)); +} + +constexpr +ATTR sp_to_attr(SP sp) +{ + return static_cast<ATTR>(static_cast<uint16_t>(sp) - static_cast<uint16_t>(SP::STR)); +} + +constexpr +SP attr_to_usp(ATTR attr) +{ + return static_cast<SP>(static_cast<uint16_t>(attr) + static_cast<uint16_t>(SP::USTR)); +} + +constexpr +ATTR usp_to_attr(SP sp) +{ + return static_cast<ATTR>(static_cast<uint16_t>(sp) - static_cast<uint16_t>(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<uint8_t>(native.dir); + + uint8_t *p = reinterpret_cast<uint8_t *>(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<const uint8_t *>(&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<DIR>(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<uint8_t *>(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<const uint8_t *>(&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<ValueIterator<IOff0>> 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<ValueIterator<SOff0>> 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<uint16_t>(i + 2)}; } + static IteratorPair<ValueIterator<IOff2>> 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<uint16_t>(i + 1)}; } + static IteratorPair<ValueIterator<SOff1>> 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 diff --git a/src/mmo/config_parse.hpp b/src/mmo/config_parse.hpp index 50a115e..db097e9 100644 --- a/src/mmo/config_parse.hpp +++ b/src/mmo/config_parse.hpp @@ -20,8 +20,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - namespace tmwa { diff --git a/src/mmo/core.cpp b/src/mmo/core.cpp deleted file mode 100644 index ff12f17..0000000 --- a/src/mmo/core.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "core.hpp" -// core.cpp - The main loop. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include <sys/wait.h> - -#include <alloca.h> - -#include <csignal> -#include <cstdlib> - -#include <tmwa/shared.hpp> - -#include "../strings/zstring.hpp" -#include "../strings/literal.hpp" - -#include "../io/cxxstdio.hpp" - -#include "../net/socket.hpp" -#include "../net/timer.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -// Added by Gabuzomeu -// -// This is an implementation of signal() using sigaction() for portability. -// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced -// Programming in the UNIX Environment_. -// -typedef void(*sigfunc)(int); -static -sigfunc compat_signal(int signo, sigfunc func) -{ - struct sigaction sact, oact; - - sact.sa_handler = func; - sigfillset(&sact.sa_mask); - sigdelset(&sact.sa_mask, SIGSEGV); - sigdelset(&sact.sa_mask, SIGBUS); - sigdelset(&sact.sa_mask, SIGTRAP); - sigdelset(&sact.sa_mask, SIGILL); - sigdelset(&sact.sa_mask, SIGFPE); - sact.sa_flags = 0; - - if (sigaction(signo, &sact, &oact) < 0) - { - DIAG_PUSH(); - DIAG_I(old_style_cast); - return SIG_ERR; - DIAG_POP(); - } - - return oact.sa_handler; -} - -volatile -bool runflag = true; - -static -void chld_proc(int) -{ - wait(nullptr); -} -static -void sig_proc(int) -{ - for (int i = 1; i < 31; ++i) - { - DIAG_PUSH(); - DIAG_I(old_style_cast); - compat_signal(i, SIG_IGN); - DIAG_POP(); - } - runflag = false; -} - -/* - Note about fatal signals: - - Under certain circumstances, - the following signals MUST not be ignored: - SIGFPE, SIGSEGV, SIGILL - Unless you use SA_SIGINFO and *carefully* check the origin, - that means they must be SIG_DFL. - */ -} // namespace tmwa - -int tmwa_main(int argc, char **argv) -{ - using namespace tmwa; - - check_paths(); - - // ZString args[argc]; is (deliberately!) not supported by clang yet - ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString))); - for (int i = 0; i < argc; ++i) - args[i] = ZString(strings::really_construct_from_a_pointer, argv[i], nullptr); - do_init(Slice<ZString>(args, argc)); - - if (!runflag) - { - PRINTF("Fatal error during startup; exiting\n"_fmt); - return 1; - } - // set up exit handlers *after* the initialization has happened. - // This is because term_func is likely to depend on successful init. - - DIAG_PUSH(); - DIAG_I(old_style_cast); - compat_signal(SIGPIPE, SIG_IGN); - DIAG_POP(); - compat_signal(SIGTERM, sig_proc); - compat_signal(SIGINT, sig_proc); - compat_signal(SIGCHLD, chld_proc); - - // Signal to create coredumps by system when necessary (crash) - DIAG_PUSH(); - DIAG_I(old_style_cast); - DIAG_I(zero_as_null_pointer_constant); - compat_signal(SIGSEGV, SIG_DFL); - compat_signal(SIGBUS, SIG_DFL); - compat_signal(SIGTRAP, SIG_DFL); - compat_signal(SIGILL, SIG_DFL); - compat_signal(SIGFPE, SIG_DFL); - DIAG_POP(); - - atexit(term_func); - - while (runflag) - { - // TODO - if timers take a long time to run, this - // may wait too long in sendrecv - tick_t now = milli_clock::now(); - interval_t next = do_timer(now); - do_sendrecv(next); - do_parsepacket(); - } - - return 0; -} diff --git a/src/mmo/core.hpp b/src/mmo/core.hpp deleted file mode 100644 index 259dd90..0000000 --- a/src/mmo/core.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -// core.hpp - The main loop. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include "fwd.hpp" - -#include "../range/slice.hpp" - -#include "../strings/fwd.hpp" - - -namespace tmwa -{ -/// core.c contains a server-independent main() function -/// and then runs a do_sendrecv loop - -/// When this is cleared, the server exits gracefully. -extern volatile bool runflag; - -/// This is an external function defined by each server -/// This function must register stuff for the parse loop -extern int do_init(Slice<ZString>); - -/// Cleanup function called whenever a signal kills us -/// or when if we manage to exit() gracefully. -extern void term_func(void); -} // namespace tmwa - -/// grumble grumble stupid intertwined includes mumble mumble -__attribute__((warn_unused_result)) -extern int tmwa_main(int argc, char **argv); diff --git a/src/mmo/cxxstdio_enums.hpp b/src/mmo/cxxstdio_enums.hpp new file mode 100644 index 0000000..6f428e8 --- /dev/null +++ b/src/mmo/cxxstdio_enums.hpp @@ -0,0 +1,77 @@ +#pragma once +// cxxstdio_enums.hpp - Opt-in integer formatting support for enums. +// +// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> +// +// 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 <http://www.gnu.org/licenses/>. + +#include "fwd.hpp" + +#include <cstdint> + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +namespace e +{ +enum class BF : uint16_t; +enum class EPOS : uint16_t; +enum class MapCell : uint8_t; +enum class Opt0 : uint16_t; + +inline +auto decay_for_printf(BF v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(EPOS v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(MapCell v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(Opt0 v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +} + +namespace magic +{ +enum class SPELLARG : uint8_t; + +inline +auto decay_for_printf(SPELLARG v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +} + +enum class BL : uint8_t; +enum class ByteCode : uint8_t; +enum class ItemLook : uint16_t; +enum class MS : uint8_t; +enum class SP : uint16_t; +enum class SkillID : uint16_t; +enum class StatusChange : uint16_t; + +inline +auto decay_for_printf(BL v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(ByteCode v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(ItemLook v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(MS v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(SP v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(SkillID v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +inline +auto decay_for_printf(StatusChange v) -> typename remove_enum<decltype(v)>::type { return typename remove_enum<decltype(v)>::type(v); } +} // namespace tmwa diff --git a/src/mmo/extract.cpp b/src/mmo/extract.cpp deleted file mode 100644 index 9123237..0000000 --- a/src/mmo/extract.cpp +++ /dev/null @@ -1,280 +0,0 @@ -#include "extract.hpp" -// extract.cpp - a simple, hierarchical, tokenizer -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include <algorithm> - -#include "../strings/astring.hpp" -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "extract_enums.hpp" -#include "mmo.hpp" - -#include "../poison.hpp" - - -// TODO move this whole file to io/ or something. -// It needs to be lower in the include hierarchy so it can be implemented -// for library types. Also it should pass an io::LineSpan around. -namespace tmwa -{ -bool extract(XString str, XString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, RString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, AString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, GlobalReg *var) -{ - return extract(str, - record<','>(&var->str, &var->value)); -} - -bool extract(XString str, Item *it) -{ - XString ignored; - XString corruption_hack_amount; - bool rv = extract(str, - record<',', 11>( - &ignored, - &it->nameid, - &corruption_hack_amount, - &it->equip, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored)); - if (rv) - { - if (corruption_hack_amount == "-1"_s) - it->amount = 0; - else - rv = extract(corruption_hack_amount, &it->amount); - } - return rv; -} - -bool extract(XString str, MapName *m) -{ - XString::iterator it = std::find(str.begin(), str.end(), '.'); - str = str.xislice_h(it); - VString<15> tmp; - bool rv = extract(str, &tmp); - *m = tmp; - return rv; -} - -bool extract(XString str, CharName *out) -{ - VString<23> tmp; - if (extract(str, &tmp)) - { - *out = CharName(tmp); - return true; - } - return false; -} - -bool extract(XString str, std::chrono::nanoseconds *ns) -{ - std::chrono::nanoseconds::rep rep; - if (extract(str, &rep)) - { - *ns = std::chrono::nanoseconds(rep); - return true; - } - if (str.endswith("ns"_s)) - { - if (extract(str.xrslice_h("ns"_s.size()), &rep)) - { - *ns = std::chrono::nanoseconds(rep); - return true; - } - return false; - } - std::chrono::microseconds bigger; - if (extract(str, &bigger)) - { - *ns = bigger; - return *ns == bigger; - } - return false; -} -bool extract(XString str, std::chrono::microseconds *us) -{ - std::chrono::microseconds::rep rep; - if (extract(str, &rep)) - { - *us = std::chrono::microseconds(rep); - return true; - } - if (str.endswith("us"_s)) - { - if (extract(str.xrslice_h("us"_s.size()), &rep)) - { - *us = std::chrono::microseconds(rep); - return true; - } - return false; - } - std::chrono::milliseconds bigger; - if (extract(str, &bigger)) - { - *us = bigger; - return *us == bigger; - } - return false; -} -bool extract(XString str, std::chrono::milliseconds *ms) -{ - std::chrono::milliseconds::rep rep; - if (extract(str, &rep)) - { - *ms = std::chrono::milliseconds(rep); - return true; - } - if (str.endswith("ms"_s)) - { - if (extract(str.xrslice_h("ms"_s.size()), &rep)) - { - *ms = std::chrono::milliseconds(rep); - return true; - } - return false; - } - std::chrono::seconds bigger; - if (extract(str, &bigger)) - { - *ms = bigger; - return *ms == bigger; - } - return false; -} -bool extract(XString str, std::chrono::seconds *s) -{ - std::chrono::seconds::rep rep; - if (extract(str, &rep)) - { - *s = std::chrono::seconds(rep); - return true; - } - if (str.endswith("s"_s)) - { - if (extract(str.xrslice_h("s"_s.size()), &rep)) - { - *s = std::chrono::seconds(rep); - return true; - } - return false; - } - std::chrono::minutes bigger; - if (extract(str, &bigger)) - { - *s = bigger; - return *s == bigger; - } - return false; -} -bool extract(XString str, std::chrono::minutes *min) -{ - std::chrono::minutes::rep rep; - if (extract(str, &rep)) - { - *min = std::chrono::minutes(rep); - return true; - } - if (str.endswith("min"_s)) - { - if (extract(str.xrslice_h("min"_s.size()), &rep)) - { - *min = std::chrono::minutes(rep); - return true; - } - return false; - } - std::chrono::hours bigger; - if (extract(str, &bigger)) - { - *min = bigger; - return *min == bigger; - } - return false; -} -bool extract(XString str, std::chrono::hours *h) -{ - std::chrono::hours::rep rep; - if (extract(str, &rep)) - { - *h = std::chrono::hours(rep); - return true; - } - if (str.endswith("h"_s)) - { - if (extract(str.xrslice_h("h"_s.size()), &rep)) - { - *h = std::chrono::hours(rep); - return true; - } - return false; - } - std::chrono::duration<int, std::ratio<60*60*24>> bigger; - if (extract(str, &bigger)) - { - *h = bigger; - return *h == bigger; - } - return false; -} -bool extract(XString str, std::chrono::duration<int, std::ratio<60*60*24>> *d) -{ - std::chrono::duration<int, std::ratio<60*60*24>>::rep rep; - if (extract(str, &rep)) - { - *d = std::chrono::duration<int, std::ratio<60*60*24>>(rep); - return true; - } - if (str.endswith("d"_s)) - { - if (extract(str.xrslice_h("d"_s.size()), &rep)) - { - *d = std::chrono::duration<int, std::ratio<60*60*24>>(rep); - return true; - } - return false; - } - return false; -} -} // namespace tmwa diff --git a/src/mmo/extract.hpp b/src/mmo/extract.hpp deleted file mode 100644 index 152d1b7..0000000 --- a/src/mmo/extract.hpp +++ /dev/null @@ -1,240 +0,0 @@ -#pragma once -// extract.hpp - a simple, hierarchical, tokenizer -// -// Copyright © 2012-2013 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include "fwd.hpp" - -#include <cerrno> -#include <cstdlib> - -#include <algorithm> -#include <chrono> -#include <vector> - -#include "../ints/wrap.hpp" - -#include "../strings/xstring.hpp" - -#include "../generic/enum.hpp" - -#include "utils.hpp" - - -namespace tmwa -{ -template<class T> -bool do_extract(XString str, T t); - -template<class T, typename=typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && !std::is_same<T, bool>::value>::type> -bool extract(XString str, T *iv) -{ - if (!str || str.size() > 20) - return false; - if (!((str.front() == '-' && std::is_signed<T>::value) - || ('0' <= str.front() && str.front() <= '9'))) - return false; - // needs a NUL, but can't always be given one. TODO VString? - char buf[20 + 1]; - std::copy(str.begin(), str.end(), buf); - buf[str.size()] = '\0'; - - char *end; - errno = 0; - if (std::is_signed<T>::value) - { - long long v = strtoll(buf, &end, 10); - if (errno || *end) - return false; - *iv = v; - return *iv == v; - } - else - { - unsigned long long v = strtoull(buf, &end, 10); - if (errno || *end) - return false; - *iv = v; - return *iv == v; - } -} - -inline -bool extract(XString str, TimeT *tv) -{ - return extract(str, &tv->value); -} - -template<class T, typename=typename std::enable_if<std::is_enum<T>::value>::type> -bool extract_as_int(XString str, T *iv) -{ - typedef typename underlying_type<T>::type U; - U v; - // defer to integer version - if (!extract(str, &v)) - return false; - // TODO check bounds using enum min/max as in SSCANF - *iv = static_cast<T>(v); - return true; -} - -bool extract(XString str, XString *rv); -bool extract(XString str, RString *rv); -bool extract(XString str, AString *rv); - -template<uint8_t N> -bool extract(XString str, VString<N> *out) -{ - if (str.size() > N) - return false; - *out = str; - return true; -} - -inline -bool extract(XString str, LString exact) -{ - return str == exact; -} - -template<class T> -class LStripper -{ -public: - T impl; -}; - -template<class T> -LStripper<T> lstripping(T v) -{ - return {v}; -} - -template<class T> -bool extract(XString str, LStripper<T> out) -{ - return extract(str.lstrip(), out.impl); -} - -// basically just a std::tuple -// but it provides its data members publically -template<char split, int n, class... T> -class Record; -template<char split, int n> -class Record<split, n> -{ -}; -template<char split, int n, class F, class... R> -class Record<split, n, F, R...> -{ -public: - F frist; - Record<split, n - 1, R...> rest; -public: - Record(F f, R... r) - : frist(f), rest(r...) - {} -}; -template<char split, class... T> -Record<split, sizeof...(T), T...> record(T... t) -{ - return Record<split, sizeof...(T), T...>(t...); -} -template<char split, int n, class... T> -Record<split, n, T...> record(T... t) -{ - static_assert(0 < n && n < sizeof...(T), "don't be silly"); - return Record<split, n, T...>(t...); -} - -template<char split, int n> -bool extract(XString str, Record<split, n>) -{ - return !str; -} - -template<char split, int n, class F, class... R> -bool extract(XString str, Record<split, n, F, R...> rec) -{ - XString::iterator s = std::find(str.begin(), str.end(), split); - XString::iterator s2 = s; - if (s2 != str.end()) - ++s2; - XString head = str.xislice_h(s); - XString tail = str.xislice_t(s2); - if (s == str.end()) - return (extract(head, rec.frist) && n <= 1) - || (!head && n <= 0); - - return (extract(head, rec.frist) || n <= 0) - && extract(tail, rec.rest); -} - -template<char split, class T> -struct VRecord -{ - std::vector<T> *arr; -}; - -template<char split, class T> -VRecord<split, T> vrec(std::vector<T> *arr) -{ - return {arr}; -} - -template<char split, class T> -bool extract(XString str, VRecord<split, T> rec) -{ - if (!str) - return true; - XString::iterator s = std::find(str.begin(), str.end(), split); - rec.arr->emplace_back(); - if (s == str.end()) - return extract(str, &rec.arr->back()); - return extract(str.xislice_h(s), &rec.arr->back()) - && extract(str.xislice_t(s + 1), rec); -} - -bool extract(XString str, GlobalReg *var); - -bool extract(XString str, Item *it); - -bool extract(XString str, MapName *m); - -bool extract(XString str, CharName *out); - -template<class T> -bool do_extract(XString str, T t) -{ - return extract(str, t); -} - -template<class R> -bool extract(XString str, Wrapped<R> *w) -{ - return extract(str, &w->_value); -} - -bool extract(XString str, std::chrono::nanoseconds *ns); -bool extract(XString str, std::chrono::microseconds *us); -bool extract(XString str, std::chrono::milliseconds *ms); -bool extract(XString str, std::chrono::seconds *s); -bool extract(XString str, std::chrono::minutes *min); -bool extract(XString str, std::chrono::hours *h); -bool extract(XString str, std::chrono::duration<int, std::ratio<60*60*24>> *d); -} // namespace tmwa diff --git a/src/mmo/extract_enums.cpp b/src/mmo/extract_enums.cpp new file mode 100644 index 0000000..ecf6940 --- /dev/null +++ b/src/mmo/extract_enums.cpp @@ -0,0 +1,59 @@ +#include "extract_enums.hpp" +// extract_enums.cpp - Opt-in integer extraction support for enums. +// +// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> +// +// 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 <http://www.gnu.org/licenses/>. + +#include "../poison.hpp" + + +namespace tmwa +{ +bool extract(XString str, DIR *d) +{ + unsigned di; + if (extract(str, &di) && di < 8) + { + *d = static_cast<DIR>(di); + return true; + } + const struct + { + LString str; + DIR d; + } dirs[] = + { + {"S"_s, DIR::S}, + {"SW"_s, DIR::SW}, + {"W"_s, DIR::W}, + {"NW"_s, DIR::NW}, + {"N"_s, DIR::N}, + {"NE"_s, DIR::NE}, + {"E"_s, DIR::E}, + {"SE"_s, DIR::SE}, + }; + for (auto& pair : dirs) + { + if (str == pair.str) + { + *d = pair.d; + return true; + } + } + return false; +} +} // namespace tmwa diff --git a/src/mmo/extract_enums.hpp b/src/mmo/extract_enums.hpp index 60ad493..96e5df7 100644 --- a/src/mmo/extract_enums.hpp +++ b/src/mmo/extract_enums.hpp @@ -22,7 +22,9 @@ #include <cstdint> -#include "extract.hpp" +#include "../io/extract.hpp" + +#include "clif.t.hpp" namespace tmwa @@ -66,4 +68,6 @@ inline bool extract(XString str, SkillID *iv) { return extract_as_int(str, iv); } inline bool extract(XString str, StatusChange *iv) { return extract_as_int(str, iv); } + +bool extract(XString, DIR *); } // namespace tmwa diff --git a/src/mmo/extract_test.cpp b/src/mmo/extract_test.cpp deleted file mode 100644 index 9c203ac..0000000 --- a/src/mmo/extract_test.cpp +++ /dev/null @@ -1,448 +0,0 @@ -#include "extract.hpp" -// extract_test.cpp - Testsuite for a simple, hierarchical, tokenizer -// -// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include <gtest/gtest.h> - -#include "../strings/xstring.hpp" - -#include "mmo.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -TEST(extract, record_int) -{ - int x, y, z; - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(" "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(""_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - - EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract("1"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(" "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(""_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - - EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 3"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(3, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 2"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(2, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_TRUE(extract("1"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(" "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - EXPECT_FALSE(extract(""_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; -} - -TEST(extract, record_str) -{ - XString x, y, z; - x = y = z = ""_s; - EXPECT_FALSE(extract("1 2 3 4 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1 2 3 4"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 3 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 3"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1 2"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1 "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract(" "_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(""_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract(""_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(""_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - - EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 3"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1"_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract(" "_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(""_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract(""_s, record<' ', 2>(&x, &y, &z))); - EXPECT_EQ(""_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - - EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 3"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ("3"_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 2"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ("2"_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1 "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract("1"_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ("1"_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract(" "_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(""_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; - EXPECT_TRUE(extract(""_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(""_s, x); - EXPECT_EQ(""_s, y); - EXPECT_EQ(""_s, z); - x = y = z = ""_s; -} - -TEST(extract, mapname) -{ - MapName map; - EXPECT_TRUE(extract("abc"_s, &map)); - EXPECT_EQ(map, "abc"_s); - EXPECT_TRUE(extract("abc.gat"_s, &map)); - EXPECT_EQ(map, "abc"_s); - EXPECT_TRUE(extract("abcdefghijklmno"_s, &map)); - EXPECT_EQ(map, "abcdefghijklmno"_s); - EXPECT_TRUE(extract("abcdefghijklmno.gat"_s, &map)); - EXPECT_EQ(map, "abcdefghijklmno"_s); -} - -TEST(extract, chrono) -{ - std::chrono::nanoseconds ns; - std::chrono::microseconds us; - std::chrono::milliseconds ms; - std::chrono::seconds s; - std::chrono::minutes min; - std::chrono::hours h; - std::chrono::duration<int, std::ratio<60*60*24>> d; - - EXPECT_TRUE(extract("1"_s, &ns)); - EXPECT_EQ(ns, 1_ns); - EXPECT_TRUE(extract("3ns"_s, &ns)); - EXPECT_EQ(ns, 3_ns); - EXPECT_TRUE(extract("4us"_s, &ns)); - EXPECT_EQ(ns, 4_us); - EXPECT_TRUE(extract("5ms"_s, &ns)); - EXPECT_EQ(ns, 5_ms); - EXPECT_TRUE(extract("6s"_s, &ns)); - EXPECT_EQ(ns, 6_s); - EXPECT_TRUE(extract("7min"_s, &ns)); - EXPECT_EQ(ns, 7_min); - EXPECT_TRUE(extract("8h"_s, &ns)); - EXPECT_EQ(ns, 8_h); - EXPECT_TRUE(extract("9d"_s, &ns)); - EXPECT_EQ(ns, 9_d); - - EXPECT_TRUE(extract("1"_s, &us)); - EXPECT_EQ(us, 1_us); - EXPECT_TRUE(extract("4us"_s, &us)); - EXPECT_EQ(us, 4_us); - EXPECT_TRUE(extract("5ms"_s, &us)); - EXPECT_EQ(us, 5_ms); - EXPECT_TRUE(extract("6s"_s, &us)); - EXPECT_EQ(us, 6_s); - EXPECT_TRUE(extract("7min"_s, &us)); - EXPECT_EQ(us, 7_min); - EXPECT_TRUE(extract("8h"_s, &us)); - EXPECT_EQ(us, 8_h); - EXPECT_TRUE(extract("9d"_s, &us)); - EXPECT_EQ(us, 9_d); - - EXPECT_TRUE(extract("1"_s, &ms)); - EXPECT_EQ(ms, 1_ms); - EXPECT_TRUE(extract("5ms"_s, &ms)); - EXPECT_EQ(ms, 5_ms); - EXPECT_TRUE(extract("6s"_s, &ms)); - EXPECT_EQ(ms, 6_s); - EXPECT_TRUE(extract("7min"_s, &ms)); - EXPECT_EQ(ms, 7_min); - EXPECT_TRUE(extract("8h"_s, &ms)); - EXPECT_EQ(ms, 8_h); - EXPECT_TRUE(extract("9d"_s, &ms)); - EXPECT_EQ(ms, 9_d); - - EXPECT_TRUE(extract("1"_s, &s)); - EXPECT_EQ(s, 1_s); - EXPECT_TRUE(extract("6s"_s, &s)); - EXPECT_EQ(s, 6_s); - EXPECT_TRUE(extract("7min"_s, &s)); - EXPECT_EQ(s, 7_min); - EXPECT_TRUE(extract("8h"_s, &s)); - EXPECT_EQ(s, 8_h); - EXPECT_TRUE(extract("9d"_s, &s)); - EXPECT_EQ(s, 9_d); - - EXPECT_TRUE(extract("1"_s, &min)); - EXPECT_EQ(min, 1_min); - EXPECT_TRUE(extract("7min"_s, &min)); - EXPECT_EQ(min, 7_min); - EXPECT_TRUE(extract("8h"_s, &min)); - EXPECT_EQ(min, 8_h); - EXPECT_TRUE(extract("9d"_s, &min)); - EXPECT_EQ(min, 9_d); - - EXPECT_TRUE(extract("1"_s, &h)); - EXPECT_EQ(h, 1_h); - EXPECT_TRUE(extract("8h"_s, &h)); - EXPECT_EQ(h, 8_h); - EXPECT_TRUE(extract("9d"_s, &h)); - EXPECT_EQ(h, 9_d); - - EXPECT_TRUE(extract("1"_s, &d)); - EXPECT_EQ(d, 1_d); - EXPECT_TRUE(extract("9d"_s, &d)); - EXPECT_EQ(d, 9_d); -} -} // namespace tmwa diff --git a/src/mmo/fwd.hpp b/src/mmo/fwd.hpp index 6612aab..f51767d 100644 --- a/src/mmo/fwd.hpp +++ b/src/mmo/fwd.hpp @@ -20,13 +20,20 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +// mmo/fwd.hpp is rank 6 + namespace tmwa { // meh, add more when I feel like it class MapName; class CharName; -class CharPair; class HumanTimeDiff; @@ -48,22 +55,9 @@ class VarName; class MapName; class CharName; -class Item; -#if 0 -class Point; -class SkillValue; -#endif -class GlobalReg; -#if 0 -class CharKey; -class CharData; -class CharPair; -#endif -class Storage; -#if 0 -class GM_Account; -class PartyMember; -#endif -class PartyMost; -class PartyPair; +struct MobName; +struct NpcName; +struct ScriptLabel; +struct ItemName; +struct NpcEvent; } // namespace tmwa diff --git a/src/mmo/human_time_diff.cpp b/src/mmo/human_time_diff.cpp new file mode 100644 index 0000000..e434773 --- /dev/null +++ b/src/mmo/human_time_diff.cpp @@ -0,0 +1,68 @@ +#include "human_time_diff.hpp" +// human_time_diff.cpp - broken deltas +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// 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 <http://www.gnu.org/licenses/>. + +#include "../io/extract.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +bool extract(XString str, HumanTimeDiff *iv) +{ + // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) + // there are NO spaces here + // parse by counting the number starts + auto is_num = [](char c) + { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; + if (!str || !is_num(str.front())) + return false; + *iv = HumanTimeDiff{}; + while (str) + { + auto it = std::find_if_not(str.begin(), str.end(), is_num); + auto it2 = std::find_if(it, str.end(), is_num); + XString number = str.xislice_h(it); + XString suffix = str.xislice(it, it2); + str = str.xislice_t(it2); + + short *ptr = nullptr; + if (suffix == "y"_s || suffix == "a"_s) + ptr = &iv->year; + else if (suffix == "m"_s) + ptr = &iv->month; + else if (suffix == "j"_s || suffix == "d"_s) + ptr = &iv->day; + else if (suffix == "h"_s) + ptr = &iv->hour; + else if (suffix == "mn"_s) + ptr = &iv->minute; + else if (suffix == "s"_s) + ptr = &iv->second; + else + return false; + if (number.startswith('+') && !number.startswith("+-"_s)) + number = number.xslice_t(1); + if (*ptr || !extract(number, ptr)) + return false; + } + return true; +} +} // namespace tmwa diff --git a/src/mmo/human_time_diff.hpp b/src/mmo/human_time_diff.hpp index b5c19fb..40352d0 100644 --- a/src/mmo/human_time_diff.hpp +++ b/src/mmo/human_time_diff.hpp @@ -24,8 +24,6 @@ #include "../strings/xstring.hpp" -#include "extract.hpp" - namespace tmwa { @@ -44,46 +42,5 @@ struct HumanTimeDiff return !bool(*this); } }; - -inline -bool extract(XString str, HumanTimeDiff *iv) -{ - // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) - // there are NO spaces here - // parse by counting the number starts - auto is_num = [](char c) - { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; - if (!str || !is_num(str.front())) - return false; - *iv = HumanTimeDiff{}; - while (str) - { - auto it = std::find_if_not(str.begin(), str.end(), is_num); - auto it2 = std::find_if(it, str.end(), is_num); - XString number = str.xislice_h(it); - XString suffix = str.xislice(it, it2); - str = str.xislice_t(it2); - - short *ptr = nullptr; - if (suffix == "y"_s || suffix == "a"_s) - ptr = &iv->year; - else if (suffix == "m"_s) - ptr = &iv->month; - else if (suffix == "j"_s || suffix == "d"_s) - ptr = &iv->day; - else if (suffix == "h"_s) - ptr = &iv->hour; - else if (suffix == "mn"_s) - ptr = &iv->minute; - else if (suffix == "s"_s) - ptr = &iv->second; - else - return false; - if (number.startswith('+') && !number.startswith("+-"_s)) - number = number.xslice_t(1); - if (*ptr || !extract(number, ptr)) - return false; - } - return true; -} +bool extract(XString str, HumanTimeDiff *iv); } // namespace tmwa diff --git a/src/mmo/ids.cpp b/src/mmo/ids.cpp new file mode 100644 index 0000000..9c013ba --- /dev/null +++ b/src/mmo/ids.cpp @@ -0,0 +1,42 @@ +#include "ids.hpp" +// ids.cpp - special integer classes for various object IDs +// +// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com> +// +// 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 <http://www.gnu.org/licenses/>. + +#include "../io/extract.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +bool extract(XString str, Species *w) +{ + // lots of data files use this + if (str == "-1"_s) + { + *w = NEGATIVE_SPECIES; + return true; + } + return extract(str, &w->_value); +} +bool extract(XString str, GmLevel *lvl) +{ + return extract(str, &lvl->bits); +} +} // namespace tmwa diff --git a/src/mmo/ids.hpp b/src/mmo/ids.hpp index 4e2b97c..389f9e9 100644 --- a/src/mmo/ids.hpp +++ b/src/mmo/ids.hpp @@ -23,8 +23,6 @@ #include "../ints/little.hpp" #include "../ints/wrap.hpp" -#include "extract.hpp" - namespace tmwa { @@ -32,17 +30,7 @@ class Species : public Wrapped<uint16_t> { public: explicit operator bool() cons constexpr Species NEGATIVE_SPECIES = Species(); -inline -bool extract(XString str, Species *w) -{ - // lots of data files use this - if (str == "-1"_s) - { - *w = NEGATIVE_SPECIES; - return true; - } - return extract(str, &w->_value); -} +bool extract(XString str, Species *w); class AccountId : public Wrapped<uint32_t> { public: constexpr AccountId() : Wrapped<uint32_t>() {} protected: constexpr explicit AccountId(uint32_t a) : Wrapped<uint32_t>(a) {} }; @@ -53,11 +41,12 @@ class ItemNameId : public Wrapped<uint16_t> { public: constexpr ItemNameId() : W class BlockId : public Wrapped<uint32_t> { public: constexpr BlockId() : Wrapped<uint32_t>() {} protected: constexpr explicit BlockId(uint32_t a) : Wrapped<uint32_t>(a) {} }; +bool extract(XString str, GmLevel *lvl); class GmLevel { uint32_t bits; - friend bool extract(XString str, GmLevel *lvl) { return extract(str, &lvl->bits); } + friend bool extract(XString str, GmLevel *lvl); constexpr explicit GmLevel(uint32_t b) : bits(b) {} constexpr explicit diff --git a/src/mmo/md5more.hpp b/src/mmo/login.t.hpp index 7d50713..f2c775a 100644 --- a/src/mmo/md5more.hpp +++ b/src/mmo/login.t.hpp @@ -1,5 +1,5 @@ #pragma once -// md5more.hpp - Non-basic MD5 functions. +// login.t.hpp - externally useful types from login // // Copyright © ????-2004 Athena Dev Teams // Copyright © 2004-2011 The Mana World Development Team @@ -22,27 +22,23 @@ #include "fwd.hpp" -#include "../generic/md5.hpp" +#include <cstdint> -#include "../io/fwd.hpp" - -#include "../net/fwd.hpp" +#include "../generic/enum.hpp" namespace tmwa { -MD5_state MD5_from_FILE(io::ReadFile& in); - -// whoever wrote this fails basic understanding of -AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt); - -/// return some random characters -// Currently, returns a 5-char string -SaltString make_salt(void); - -/// check plaintext password against saved saltcrypt -bool pass_ok(AccountPass password, AccountCrypt crypted); - -/// This returns an IP4Address because it is configurable whether it gets called at all -IP4Address MD5_ip(IP4Address ip); +namespace e +{ +enum class VERSION_2 : uint8_t +{ + /// client supports updatehost + UPDATEHOST = 0x01, + /// send servers in forward order + SERVERORDER = 0x02, +}; +ENUM_BITWISE_OPERATORS(VERSION_2) +} +using e::VERSION_2; } // namespace tmwa diff --git a/src/mmo/md5more.cpp b/src/mmo/md5more.cpp deleted file mode 100644 index 4e5d2da..0000000 --- a/src/mmo/md5more.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "md5more.hpp" -// md5more.cpp - Non-basic MD5 functions. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include <algorithm> - -#include "../compat/rawmem.hpp" - -#include "../generic/random.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/read.hpp" - -#include "../net/ip.hpp" - -#include "../mmo/mmo.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -#define X block.data - -// TODO - refactor MD5 into a stream, and merge the implementations -// I once implemented an ostream that does it ... -MD5_state MD5_from_FILE(io::ReadFile& in) -{ - uint64_t total_len = 0; - - uint8_t buf[0x40]; - uint8_t block_len = 0; - - MD5_state state; - MD5_init(&state); - - MD5_block block; - - while (true) - { - size_t rv = in.get(sign_cast<char *>(buf + block_len), 0x40 - block_len); - if (!rv) - break; - total_len += 8 * rv; // in bits - block_len += rv; - if (block_len != 0x40) - continue; - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - block_len = 0; - } - // no more input, just pad and append the length - buf[block_len] = 0x80; - really_memset0(buf + block_len + 1, 0x40 - block_len - 1); - if (block_len < 0x38) - { - for (int i = 0; i < 8; i++) - buf[0x38 + i] = total_len >> i * 8; - } - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - if (0x38 <= block_len) - { - really_memset0(buf, 0x38); - for (int i = 0; i < 8; i++) - buf[0x38 + i] = total_len >> i * 8; - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - } - return state; -} - - -// Hash a password with a salt. -// Whoever wrote this FAILS programming -AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt) -{ - char cbuf[64] {}; - - // hash the key then the salt - // buf ends up as a 64-char NUL-terminated string - md5_string tbuf, tbuf2; - MD5_to_str(MD5_from_string(key), tbuf); - MD5_to_str(MD5_from_string(salt), tbuf2); - const auto it = std::copy(tbuf.begin(), tbuf.end(), std::begin(cbuf)); - auto it2 = std::copy(tbuf2.begin(), tbuf2.end(), it); - assert(it2 == std::end(cbuf)); - - md5_string tbuf3; - MD5_to_str(MD5_from_string(XString(std::begin(cbuf), it2, nullptr)), tbuf3); - - VString<31> obuf; - - // This truncates the string, but we have to keep it like that for compatibility - SNPRINTF(obuf, 32, "!%s$%s"_fmt, salt, tbuf3); - return stringish<AccountCrypt>(obuf); -} - -SaltString make_salt(void) -{ - char salt[5]; - for (int i = 0; i < 5; i++) - // 126 would probably actually be okay - salt[i] = random_::in(48, 125); - return stringish<SaltString>(XString(salt + 0, salt + 5, nullptr)); -} - -bool pass_ok(AccountPass password, AccountCrypt crypted) -{ - // crypted is like !salt$hash - auto begin = crypted.begin() + 1; - auto end = std::find(begin, crypted.end(), '$'); - SaltString salt = stringish<SaltString>(crypted.xislice(begin, end)); - - return crypted == MD5_saltcrypt(password, salt); -} - -// [M|h]ashes up an IP address and a secret key -// to return a hopefully unique masked IP. -IP4Address MD5_ip(IP4Address ip) -{ - static SaltString secret = make_salt(); - - // MD5sum a secret + the IP address - VString<31> ipbuf; - SNPRINTF(ipbuf, 32, "%s %s"_fmt, ip, secret); - md5_binary obuf; - MD5_to_bin(MD5_from_string(ipbuf), obuf); - - // Fold the md5sum to 32 bits, pack the bytes to an in_addr - return IP4Address({ - static_cast<uint8_t>(obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]), - static_cast<uint8_t>(obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]), - static_cast<uint8_t>(obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]), - static_cast<uint8_t>(obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]), - }); -} -} // namespace tmwa diff --git a/src/mmo/mmo.hpp b/src/mmo/mmo.hpp deleted file mode 100644 index b5bcac8..0000000 --- a/src/mmo/mmo.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -// mmo.hpp - Huge mess of structures. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include "fwd.hpp" - -#include "../compat/borrow.hpp" -#include "../compat/memory.hpp" - -#include "../proto2/net-CharData.hpp" -#include "../proto2/net-CharKey.hpp" -#include "../proto2/net-PartyMost.hpp" -#include "../proto2/net-SkillValue.hpp" - - -namespace tmwa -{ -inline -bool operator == (const SkillValue& l, const SkillValue& r) -{ - return l.lv == r.lv && l.flags == r.flags; -} -inline -bool operator != (const SkillValue& l, const SkillValue& r) -{ - return !(l == r); -} - -struct CharPair -{ - CharKey key; - std::unique_ptr<CharData> data; - - CharPair() - : key{}, data(make_unique<CharData>()) - {} -}; - -struct GM_Account -{ - AccountId account_id; - GmLevel level; -}; - -struct PartyPair -{ - PartyId party_id; - Borrowed<PartyMost> party_most; - - PartyMost& operator *() const { return *party_most; } - Borrowed<PartyMost> operator->() const { return party_most; } -}; -} // namespace tmwa diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp new file mode 100644 index 0000000..d0e3926 --- /dev/null +++ b/src/mmo/skill.t.hpp @@ -0,0 +1,136 @@ +#pragma once +// skill.t.hpp - Old-style skills. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> +// +// 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 <http://www.gnu.org/licenses/>. + +#include "fwd.hpp" + +#include <cstdint> + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +// TODO remove most of these as their corresponding SkillIDs get deleted. +enum class StatusChange : uint16_t +{ + // indices into (map_session_data).status_change + SC_SENDMAX = 256, + + // sometimes means "none", sometimes not + NEGATIVE1 = 0xffff, + + // these ones are used by clif_status_change, + // e.g. by the magic system + ZERO = 0, + ATTACK_ICON_GENERIC = 2000, + ATTACK_ICON_SHEARING = 2001, + CART = 0x0c, + CLIF_OPTION_SC_INVISIBILITY = 0x1000, + CLIF_OPTION_SC_SCRIBE = 0x1001, + + // the rest are the normal effects + SC_SLOWPOISON = 14, // item script + + SC_WEIGHT50 = 35, // ? sort of used + SC_WEIGHT90 = 36, // definitely used + SC_SPEEDPOTION0 = 37, // item script + + SC_HEALING = 70, // item script + + SC_POISON = 132, // bad; actually used + + SC_ATKPOT = 185, // item script + SC_MATKPOT = 186, // unused, but kept for parallel + +// Added for Fate's spells + SC_HIDE = 194, // Hide from `detect' magic (PCs only) + SC_SHEARED = 194, // Has been sheared (mobs only) + SC_HALT_REGENERATE = 195, // Suspend regeneration + SC_FLYING_BACKPACK = 196, // Flying backpack + SC_MBARRIER = 197, // Magical barrier, magic resistance (val1 : power (%)) + SC_HASTE = 198, // `Haste' spell (val1 : power) + SC_PHYS_SHIELD = 199, // `Protect' spell, reduce damage (val1: power) + MAX_STATUSCHANGE = 200, +}; + +enum class SkillID : uint16_t +{ + // TODO: Remove these! + NEGATIVE = 0xffff, + ZERO = 0x0000, + ONE = 0x0001, + + // Basic skills. + // These should probably be made unconditional. + NV_EMOTE = 1, // + NV_TRADE = 2, // + NV_PARTY = 3, // + + AC_OWL = 45, // Mallard's Eye + + NPC_SELFDESTRUCTION = 175, // + + NPC_POISON = 178, // + + NPC_SUMMONSLAVE = 198, // + NPC_EMOTION = 199, // + + TMW_SKILLPOOL = 339, // skill pool size + + // magic skills + TMW_MAGIC = 340, // + TMW_MAGIC_LIFE = 341, // + TMW_MAGIC_WAR = 342, // + TMW_MAGIC_TRANSMUTE = 343, // + TMW_MAGIC_NATURE = 344, // + TMW_MAGIC_ETHER = 345, // + TMW_MAGIC_DARK = 346, // + TMW_MAGIC_LIGHT = 347, // + + // focusable skills + TMW_BRAWLING = 350, // + TMW_LUCKY_COUNTER = 351, // + TMW_SPEED = 352, // + TMW_RESIST_POISON = 353, // + TMW_ASTRAL_SOUL = 354, // + TMW_RAGING = 355, // + + // Note: this value is also hard-coded in common/mmo.hpp + MAX_SKILL_DB = 474, // not 450 +}; + +namespace e +{ +enum class SkillFlags : uint16_t +{ + ZERO = 0x00, + // is a pool skill + POOL_FLAG = 0x01, + // is an active pool skill + POOL_ACTIVE = 0x02, + // pool skill has been activated (used for clif) + POOL_ACTIVATED = 0x04, +}; +ENUM_BITWISE_OPERATORS(SkillFlags) +} +using e::SkillFlags; +} // namespace tmwa diff --git a/src/mmo/strs.hpp b/src/mmo/strs.hpp index fea0c98..6a132c2 100644 --- a/src/mmo/strs.hpp +++ b/src/mmo/strs.hpp @@ -123,4 +123,37 @@ CharName stringish<CharName>(VString<23> iv) { return CharName(iv); } + +struct MobName : VString<23> {}; +struct NpcName : VString<23> {}; +struct ScriptLabel : VString<23> {}; +struct ItemName : VString<23> {}; + +// formerly VString<49>, as name::label +struct NpcEvent +{ + NpcName npc; + ScriptLabel label; + + explicit operator bool() + { + return npc || label; + } + bool operator !() + { + return !bool(*this); + } + + friend bool operator == (const NpcEvent& l, const NpcEvent& r) + { + return l.npc == r.npc && l.label == r.label; + } + + friend bool operator < (const NpcEvent& l, const NpcEvent& r) + { + return l.npc < r.npc || (l.npc == r.npc && l.label < r.label); + } + + friend VString<49> convert_for_printf(NpcEvent ev); +}; } // namespace tmwa diff --git a/src/mmo/utils.cpp b/src/mmo/utils.cpp deleted file mode 100644 index f8aff2e..0000000 --- a/src/mmo/utils.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "utils.hpp" -// utils.cpp - Useful stuff that hasn't been categorized. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include <sys/time.h> - -#include <algorithm> - -#include "../strings/zstring.hpp" -#include "../strings/xstring.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/write.hpp" - -#include "extract.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -//--------------------------------------------------- -// E-mail check: return 0 (not correct) or 1 (valid). -//--------------------------------------------------- -bool e_mail_check(XString email) -{ - // athena limits - if (email.size() < 3 || email.size() > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - XString::iterator at = std::find(email.begin(), email.end(), '@'); - if (at == email.end()) - return 0; - XString username = email.xislice_h(at); - XString hostname = email.xislice_t(at + 1); - if (!username || !hostname) - return 0; - if (hostname.contains('@')) - return 0; - if (hostname.front() == '.' || hostname.back() == '.') - return 0; - if (hostname.contains_seq(".."_s)) - return 0; - if (email.contains_any(" ;"_s)) - return 0; - return email.is_print(); -} - -//------------------------------------------------- -// Return numerical value of a switch configuration -// on/off, english, français, deutsch, español -//------------------------------------------------- -int config_switch(ZString str) -{ - if (str == "true"_s || str == "on"_s || str == "yes"_s - || str == "oui"_s || str == "ja"_s - || str == "si"_s) - return 1; - if (str == "false"_s || str == "off"_s || str == "no"_s - || str == "non"_s || str == "nein"_s) - return 0; - - int rv; - if (extract(str, &rv)) - return rv; - FPRINTF(stderr, "Fatal: bad option value %s"_fmt, str); - abort(); -} - -static_assert(sizeof(timestamp_seconds_buffer) == 20, "seconds buffer"); -static_assert(sizeof(timestamp_milliseconds_buffer) == 24, "millis buffer"); - -void stamp_time(timestamp_seconds_buffer& out, const TimeT *t) -{ - struct tm when = t ? *t : TimeT::now(); - char buf[20]; - strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); - out = stringish<timestamp_seconds_buffer>(VString<19>(strings::really_construct_from_a_pointer, buf)); -} -void stamp_time(timestamp_milliseconds_buffer& out) -{ - struct timeval tv; - gettimeofday(&tv, nullptr); - struct tm when = TimeT(tv.tv_sec); - char buf[24]; - strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when); - sprintf(buf + 19, ".%03d", static_cast<int>(tv.tv_usec / 1000)); - out = stringish<timestamp_milliseconds_buffer>(VString<23>(strings::really_construct_from_a_pointer, buf)); -} - -void log_with_timestamp(io::WriteFile& out, XString line) -{ - if (!line) - { - out.put('\n'); - return; - } - timestamp_milliseconds_buffer tmpstr; - stamp_time(tmpstr); - out.really_put(tmpstr.data(), tmpstr.size()); - out.really_put(": ", 2); - out.put_line(line); -} -} // namespace tmwa diff --git a/src/mmo/utils.hpp b/src/mmo/utils.hpp deleted file mode 100644 index fc3ea74..0000000 --- a/src/mmo/utils.hpp +++ /dev/null @@ -1,167 +0,0 @@ -#pragma once -// utils.hpp - Useful stuff that hasn't been categorized. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> -// -// 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 <http://www.gnu.org/licenses/>. - -#include "fwd.hpp" - -#include <cstring> -#include <ctime> - -#include <type_traits> - -#include "../ints/little.hpp" - -#include "../strings/fwd.hpp" -#include "../strings/vstring.hpp" - -#include "../generic/operators.hpp" - -#include "../io/fwd.hpp" - - -namespace tmwa -{ -template<class T> -struct is_trivially_copyable -: std::integral_constant<bool, - // come back when GCC actually implements the public traits properly - __has_trivial_copy(T) - && __has_trivial_assign(T) - && __has_trivial_destructor(T)> -{}; - -bool e_mail_check(XString email); -int config_switch (ZString str); - -template<class T> -void really_memzero_this(T *v) -{ - static_assert(is_trivially_copyable<T>::value, "only for mostly-pod types"); - static_assert(std::is_class<T>::value || std::is_union<T>::value, "Only for user-defined structures (for now)"); - memset(v, '\0', sizeof(*v)); -} -template<class T, size_t n> -void really_memzero_this(T (&)[n]) = delete; - -// Exists in place of time_t, to give it a predictable printf-format. -// (on x86 and amd64, time_t == long, but not on x32) -static_assert(sizeof(long long) >= sizeof(time_t), "long long >= time_t"); -struct TimeT : Comparable -{ - long long value; - - // conversion - TimeT(time_t t=0) : value(t) {} - TimeT(struct tm t) : value(timegm(&t)) {} - operator time_t() const { return value; } - operator struct tm() const { time_t v = value; return *gmtime(&v); } - - explicit operator bool() const { return value; } - bool operator !() const { return !value; } - - // prevent surprises - template<class T> - TimeT(T) = delete; - template<class T> - operator T() const = delete; - - static - TimeT now() - { - // poisoned, but this is still in header-land - return time(nullptr); - } - - bool error() const - { - return value == -1; - } - bool okay() const - { - return !error(); - } -}; - -inline -long long convert_for_printf(TimeT t) -{ - return t.value; -} - -// 2038 problem -inline __attribute__((warn_unused_result)) -bool native_to_network(Little32 *net, TimeT nat) -{ - time_t tmp = nat; - return native_to_network(net, static_cast<uint32_t>(tmp)); -} - -inline __attribute__((warn_unused_result)) -bool network_to_native(TimeT *nat, Little32 net) -{ - uint32_t tmp; - bool rv = network_to_native(&tmp, net); - *nat = static_cast<time_t>(tmp); - return rv; -} - -inline __attribute__((warn_unused_result)) -bool native_to_network(Little64 *net, TimeT nat) -{ - time_t tmp = nat; - return native_to_network(net, static_cast<uint64_t>(tmp)); -} - -inline __attribute__((warn_unused_result)) -bool network_to_native(TimeT *nat, Little64 net) -{ - uint64_t tmp; - bool rv = network_to_native(&tmp, net); - *nat = static_cast<time_t>(tmp); - return rv; -} - - -struct timestamp_seconds_buffer : VString<19> {}; -struct timestamp_milliseconds_buffer : VString<23> {}; -void stamp_time(timestamp_seconds_buffer&, const TimeT *t=nullptr); -void stamp_time(timestamp_milliseconds_buffer&); - -void log_with_timestamp(io::WriteFile& out, XString line); - -// TODO VString? -#define TIMESTAMP_DUMMY "YYYY-MM-DD HH:MM:SS" -static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), - "timestamp size"); -#define WITH_TIMESTAMP(str) str TIMESTAMP_DUMMY -// str: prefix: YYYY-MM-DD HH:MM:SS -// sizeof: 01234567890123456789012345678 -// str + sizeof: ^ -// -1: ^ -// there's probably a better way to do this now -#define REPLACE_TIMESTAMP(str, t) \ - stamp_time( \ - reinterpret_cast<timestamp_seconds_buffer *>( \ - str + sizeof(str) \ - )[-1], \ - &t \ - ) -} // namespace tmwa diff --git a/src/mmo/version.cpp b/src/mmo/version.cpp index 7c63614..56e21dc 100644 --- a/src/mmo/version.cpp +++ b/src/mmo/version.cpp @@ -24,7 +24,7 @@ #include "../strings/xstring.hpp" -#include "extract.hpp" +#include "../io/extract.hpp" #include "../poison.hpp" diff --git a/src/mmo/version.hpp b/src/mmo/version.hpp index 6afcd58..1eed223 100644 --- a/src/mmo/version.hpp +++ b/src/mmo/version.hpp @@ -24,8 +24,6 @@ #include <cstdint> -#include "../strings/fwd.hpp" - namespace tmwa { |