summaryrefslogtreecommitdiff
path: root/src/mmo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mmo')
-rw-r--r--src/mmo/clif.t.hpp717
-rw-r--r--src/mmo/config_parse.hpp2
-rw-r--r--src/mmo/core.cpp161
-rw-r--r--src/mmo/core.hpp49
-rw-r--r--src/mmo/cxxstdio_enums.hpp77
-rw-r--r--src/mmo/extract.cpp280
-rw-r--r--src/mmo/extract.hpp240
-rw-r--r--src/mmo/extract_enums.cpp59
-rw-r--r--src/mmo/extract_enums.hpp6
-rw-r--r--src/mmo/extract_test.cpp448
-rw-r--r--src/mmo/fwd.hpp32
-rw-r--r--src/mmo/human_time_diff.cpp68
-rw-r--r--src/mmo/human_time_diff.hpp45
-rw-r--r--src/mmo/ids.cpp42
-rw-r--r--src/mmo/ids.hpp17
-rw-r--r--src/mmo/login.t.hpp (renamed from src/mmo/md5more.hpp)34
-rw-r--r--src/mmo/md5more.cpp159
-rw-r--r--src/mmo/mmo.hpp71
-rw-r--r--src/mmo/skill.t.hpp136
-rw-r--r--src/mmo/strs.hpp33
-rw-r--r--src/mmo/utils.cpp123
-rw-r--r--src/mmo/utils.hpp167
-rw-r--r--src/mmo/version.cpp2
-rw-r--r--src/mmo/version.hpp2
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
{