diff options
Diffstat (limited to 'src/game-server/command.cpp')
-rw-r--r-- | src/game-server/command.cpp | 223 |
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); +} |