summaryrefslogtreecommitdiff
path: root/src/game-server/command.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game-server/command.cpp')
-rw-r--r--src/game-server/command.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/src/game-server/command.cpp b/src/game-server/command.cpp
new file mode 100644
index 00000000..2920c30a
--- /dev/null
+++ b/src/game-server/command.cpp
@@ -0,0 +1,223 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World 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 2 of the License, or
+ * any later version.
+ *
+ * The Mana World 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 The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * $Id$
+ */
+
+#include <cstddef>
+
+#include "defines.h"
+#include "game-server/character.hpp"
+#include "game-server/inventory.hpp"
+#include "game-server/item.hpp"
+#include "game-server/itemmanager.hpp"
+#include "game-server/mapmanager.hpp"
+#include "game-server/state.hpp"
+
+template< typename T1, typename T2, typename T3 >
+static void proxy(void (*f)(), intptr_t args[4])
+{
+ ((void (*)(T1, T2, T3))f)((T1)args[0], (T2)args[1], (T3)args[2]);
+}
+
+template< typename T1, typename T2, typename T3, typename T4 >
+static void proxy(void (*f)(), intptr_t args[4])
+{
+ ((void (*)(T1, T2, T3, T4))f)((T1)args[0], (T2)args[1], (T3)args[2], (T4)args[3]);
+}
+
+/**
+ * An argument type that a command can use.
+ */
+
+template< typename T > struct Argument;
+
+template<> struct Argument< int >
+{ static char const type = 'n'; };
+template<> struct Argument< Character * >
+{ static char const type = 'c'; };
+template<> struct Argument< MapComposite * >
+{ static char const type = 'm'; };
+template<> struct Argument< ItemClass * >
+{ static char const type = 'i'; };
+
+/**
+ * A command that a user can run remotely with sufficient rights.
+ */
+struct Command
+{
+ char const *name;
+ char type[4];
+ void (*handler)(void (*f)(), intptr_t[4]);
+ void (*target)();
+ unsigned char level;
+};
+
+/**
+ * Creates a command with a 3-parameter handler.
+ */
+template< typename T1, typename T2, typename T3 >
+static Command handle(char const *name, int level, void (*f)(T1, T2, T3))
+{
+ Command c;
+ c.name = name;
+ c.level = level;
+ c.handler = &proxy< T1, T2, T3 >;
+ c.target = (void (*)())f;
+ c.type[0] = Argument<T1>::type;
+ c.type[1] = Argument<T2>::type;
+ c.type[2] = Argument<T3>::type;
+ c.type[3] = 0;
+ return c;
+}
+
+/**
+ * Creates a command with a 4-parameter handler.
+ */
+template< typename T1, typename T2, typename T3, typename T4 >
+static Command handle(char const *name, int level, void (*f)(T1, T2, T3, T4))
+{
+ Command c;
+ c.name = name;
+ c.level = level;
+ c.handler = &proxy< T1, T2, T3, T4 >;
+ c.target = (void (*)())f;
+ c.type[0] = Argument<T1>::type;
+ c.type[1] = Argument<T2>::type;
+ c.type[2] = Argument<T3>::type;
+ c.type[3] = Argument<T4>::type;
+ return c;
+}
+
+static void warp(Character *q, MapComposite *m, int x, int y)
+{
+ DelayedEvent e = { EVENT_WARP, x, y, m };
+ GameState::enqueueEvent(q, e);
+}
+
+static void item(Character *q, ItemClass *it, int nb)
+{
+ Inventory(q).insert(it->getDatabaseID(), nb);
+}
+
+/**
+ * List of remote commands.
+ */
+static Command const commands[] =
+{
+ handle("warp", AL_GM, warp),
+ handle("item", AL_GM, item),
+};
+
+/**
+ * Parses a command and executes its associated handler.
+ */
+void runCommand(Character *ch, std::string const &text)
+{
+ Command const *c = NULL;
+ std::string::size_type npos = std::string::npos;
+ std::string::size_type pos = text.find(' ');
+ std::string s(text, 1, pos == npos ? npos : pos - 1); // Skip slash.
+
+ for (int i = 0; i < (int)(sizeof(commands) / sizeof(commands[0])); ++i)
+ {
+ if (s == commands[i].name)
+ {
+ c = &commands[i];
+ break;
+ }
+ }
+
+ if (!c || c->level < ch->getAccountLevel())
+ {
+ // No such command or no sufficient rights.
+ return;
+ }
+
+ intptr_t args[4];
+
+ for (int i = 0; i < 4 && c->type[i]; ++i)
+ {
+ if (pos == npos || pos + 1 >= text.length())
+ {
+ // Not enough parameters.
+ return;
+ }
+
+ std::string::size_type pos2 = text.find(' ', pos + 1);
+ std::string arg(text, pos + 1, pos2 == npos ? npos : pos2 - pos - 1);
+ if (arg.empty())
+ {
+ // Empty parameter.
+ return;
+ }
+
+ switch (c->type[i])
+ {
+ case 'c':
+ if (arg == "#")
+ {
+ // Character itself.
+ args[i] = (intptr_t)ch;
+ }
+ else
+ {
+ // TODO: explicitly named character.
+ return;
+ }
+ break;
+
+ case 'i':
+ if (ItemClass *ic = ItemManager::getItem(atoi(arg.c_str())))
+ {
+ args[i] = (intptr_t)ic;
+ }
+ else
+ {
+ // No such item.
+ return;
+ }
+ break;
+
+ case 'm':
+ if (arg == "#")
+ {
+ // Map the character is on.
+ args[i] = (intptr_t)ch->getMap();
+ }
+ else if (MapComposite *m = MapManager::getMap(atoi(arg.c_str())))
+ {
+ args[i] = (intptr_t)m;
+ }
+ else
+ {
+ // No such map.
+ return;
+ }
+ break;
+
+ case 'n':
+ args[i] = atoi(arg.c_str());
+ break;
+ }
+ pos = pos2;
+ }
+ c->handler(c->target, args);
+}