1
/*
2
 *  The Mana World
3
 *  Copyright (C) 2008  The Mana World Development Team
4
 *
5
 *  This file is part of The Mana World.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
22
23
#include "commandhandler.h"
24
#include "channelmanager.h"
25
#include "channel.h"
26
#include "game.h"
27
#include "localplayer.h"
28
#include "playerrelations.h"
29
30
#include "gui/widgets/channeltab.h"
31
#include "gui/widgets/chattab.h"
32
#include "gui/chat.h"
33
34
#include "net/adminhandler.h"
35
#include "net/chathandler.h"
36
#include "net/gamehandler.h"
37
#include "net/net.h"
38
#include "net/partyhandler.h"
39
40
#include "utils/gettext.h"
41
#include "utils/stringutils.h"
42
43
CommandHandler::CommandHandler()
44
{}
45
46
void CommandHandler::handleCommand(const std::string &command, ChatTab *tab)
47
{
48
    std::string::size_type pos = command.find(' ');
49
    std::string type(command, 0, pos);
50
    std::string args(command, pos == std::string::npos ? command.size() : pos + 1);
51
52
    if (type == "help") // Do help before tabs so they can't override it
53
    {
54
        handleHelp(args, tab);
55
    }
56
    else if (tab->handleCommand(type, args))
57
    {
58
        // Nothing to do
59
    }
60
    else if (type == "announce")
61
    {
62
        handleAnnounce(args, tab);
63
    }
64
    else if (type == "where")
65
    {
66
        handleWhere(args, tab);
67
    }
68
    else if (type == "who")
69
    {
70
        handleWho(args, tab);
71
    }
72
    else if (type == "msg" || type == "whisper" || type == "w")
73
    {
74
        handleMsg(args, tab);
75
    }
76
    else if (type == "query" || type == "q")
77
    {
78
        handleQuery(args, tab);
79
    }
80
    else if (type == "ignore")
81
    {
82
        handleIgnore(args, tab);
83
    }
84
    else if (type == "unignore")
85
    {
86
        handleUnignore(args, tab);
87
    }
88
    else if (type == "join")
89
    {
90
        handleJoin(args, tab);
91
    }
92
    else if (type == "list")
93
    {
94
        handleListChannels(args, tab);
95
    }
96
    else if (type == "clear")
97
    {
98
        handleClear(args, tab);
99
    }
100
    else if (type == "party")
101
    {
102
        handleParty(args, tab);
103
    }
104
    else if (type == "me")
105
    {
106
        handleMe(args, tab);
107
    }
108
    else if (type == "record")
109
    {
110
        handleRecord(args, tab);
111
    }
112
    else if (type == "toggle")
113
    {
114
        handleToggle(args, tab);
115
    }
116
    else if (type == "present")
117
    {
118
        handlePresent(args, tab);
119
    }
120
    else
121
    {
122
        tab->chatLog(_("Unknown command."));
123
    }
124
}
125
126
char CommandHandler::parseBoolean(const std::string &value)
127
{
128
    std::string opt = value.substr(0, 1);
129
130
    if (opt == "1" ||
131
        opt == "y" || opt == "Y" ||
132
        opt == "t" || opt == "T")
133
        return 1;
134
    else if (opt == "0" ||
135
             opt == "n" || opt == "N" ||
136
             opt == "f" || opt == "F")
137
        return 0;
138
    else
139
        return -1;
140
}
141
142
void CommandHandler::handleAnnounce(const std::string &args, ChatTab *tab)
143
{
144
    Net::getAdminHandler()->announce(args);
145
}
146
147
void CommandHandler::handleHelp(const std::string &args, ChatTab *tab)
148
{
149
    if (args == "")
150
    {
151
        tab->chatLog(_("-- Help --"));
152
        tab->chatLog(_("/help > Display this help"));
153
154
        tab->chatLog(_("/where > Display map name"));
155
        tab->chatLog(_("/who > Display number of online users"));
156
        tab->chatLog(_("/me > Tell something about yourself"));
157
158
        tab->chatLog(_("/clear > Clears this window"));
159
160
        tab->chatLog(_("/msg > Send a private message to a user"));
161
        tab->chatLog(_("/whisper > Alias of msg"));
162
        tab->chatLog(_("/w > Alias of msg"));
163
        tab->chatLog(_("/query > Makes a tab for private messages with another user"));
164
        tab->chatLog(_("/q > Alias of query"));
165
166
        tab->chatLog(_("/ignore > ignore a player"));
167
        tab->chatLog(_("/unignore > stop ignoring a player"));
168
169
        tab->chatLog(_("/list > Display all public channels"));
170
        tab->chatLog(_("/join > Join or create a channel"));
171
172
        tab->chatLog(_("/party > Invite a user to party"));
173
174
        tab->chatLog(_("/record > Start recording the chat to an external file"));
175
        tab->chatLog(_("/toggle > Determine whether <return> toggles the chat log"));
176
        tab->chatLog(_("/present > Get list of players present (sent to chat log, if logging)"));
177
178
        tab->chatLog(_("/announce > Global announcement (GM only)"));
179
180
        tab->showHelp(); // Allow the tab to show it's help
181
182
        tab->chatLog(_("For more information, type /help <command>."));
183
    }
184
    else if (args == "help") // Do this before tabs so they can't change it
185
    {
186
        tab->chatLog(_("Command: /help"));
187
        tab->chatLog(_("This command displays a list of all commands available."));
188
        tab->chatLog(_("Command: /help <command>"));
189
        tab->chatLog(_("This command displays help on <command>."));
190
    }
191
    else if (tab->handleCommand("help", args))
192
    {
193
        // Nothing to do
194
    }
195
    else if (args == "announce")
196
    {
197
        tab->chatLog(_("Command: /announce <msg>"));
198
        tab->chatLog(_("*** only available to a GM ***"));
199
        tab->chatLog(_("This command sends the message <msg> to "
200
                            "all players currently online."));
201
    }
202
    else if (args == "clear")
203
    {
204
        tab->chatLog(_("Command: /clear"));
205
        tab->chatLog(_("This command clears the chat log of previous chat."));
206
    }
207
    else if (args == "ignore")
208
    {
209
        tab->chatLog(_("Command: /ignore <player>"));
210
        tab->chatLog(_("This command ignores the given player regardless of "
211
                       "current relations."));
212
    }
213
    else if (args == "join")
214
    {
215
        tab->chatLog(_("Command: /join <channel>"));
216
        tab->chatLog(_("This command makes you enter <channel>."));
217
        tab->chatLog(_("If <channel> doesn't exist, it's created."));
218
    }
219
    else if (args == "list")
220
    {
221
        tab->chatLog(_("Command: /list"));
222
        tab->chatLog(_("This command shows a list of all channels."));
223
    }
224
    else if (args == "me")
225
    {
226
        tab->chatLog(_("Command: /me <message>"));
227
        tab->chatLog(_("This command tell others you are (doing) <msg>."));
228
    }
229
    else if (args == "msg" || args == "whisper" || args == "w")
230
    {
231
        tab->chatLog(_("Command: /msg <nick> <message>"));
232
        tab->chatLog(_("Command: /whisper <nick> <message>"));
233
        tab->chatLog(_("Command: /w <nick> <message>"));
234
        tab->chatLog(_("This command sends the text <message> to <nick>."));
235
        tab->chatLog(_("If the <nick> has spaces in it, enclose it in "
236
                            "double quotes (\")."));
237
    }
238
    else if (args == "query" || args == "q")
239
    {
240
        tab->chatLog(_("Command: /query <nick>"));
241
        tab->chatLog(_("Command: /q <nick>"));
242
        tab->chatLog(_("This command tries to make a tab for whispers between"
243
                       "you and <nick>."));
244
    }
245
    else if (args == "party")
246
    {
247
        tab->chatLog(_("Command: /party <nick>"));
248
        tab->chatLog(_("This command invites <nick> to party with you."));
249
        tab->chatLog(_("If the <nick> has spaces in it, enclose it in "
250
                            "double quotes (\")."));
251
    }
252
    else if (args == "present")
253
    {
254
        tab->chatLog(_("Command: /present"));
255
        tab->chatLog(_("This command gets a list of players within hearing and "
256
                  "sends it to either the record log if recording, or the chat "
257
                  "log otherwise."));
258
    }
259
    else if (args == "record")
260
    {
261
        tab->chatLog(_("Command: /record <filename>"));
262
        tab->chatLog(_("This command starts recording the chat log to the file "
263
                  "<filename>."));
264
        tab->chatLog(_("Command: /record"));
265
        tab->chatLog(_("This command finishes a recording session."));
266
    }
267
    else if (args == "toggle")
268
    {
269
        tab->chatLog(_("Command: /toggle <state>"));
270
        tab->chatLog(_("This command sets whether the return key should toggle the "
271
                  "chat log, or whether the chat log turns off automatically."));
272
        tab->chatLog(_("<state> can be one of \"1\", \"yes\", \"true\" to "
273
                  "turn the toggle on, or \"0\", \"no\", \"false\" to turn the "
274
                  "toggle off."));
275
        tab->chatLog(_("Command: /toggle"));
276
        tab->chatLog(_("This command displays the return toggle status."));
277
    }
278
    else if (args == "unignore")
279
    {
280
        tab->chatLog(_("Command: /unignore <player>"));
281
        tab->chatLog(_("This command stops ignoring the given player if they "
282
                       "are being ignored"));
283
    }
284
    else if (args == "where")
285
    {
286
        tab->chatLog(_("Command: /where"));
287
        tab->chatLog(_("This command displays the name of the current map."));
288
    }
289
    else if (args == "who")
290
    {
291
        tab->chatLog(_("Command: /who"));
292
        tab->chatLog(_("This command displays the number of players currently "
293
                            "online."));
294
    }
295
    else
296
    {
297
        tab->chatLog(_("Unknown command."));
298
        tab->chatLog(_("Type /help for a list of commands."));
299
    }
300
}
301
302
void CommandHandler::handleWhere(const std::string &args, ChatTab *tab)
303
{
304
    std::ostringstream where;
305
    where << map_path << ", coordinates: " 
306
          << ((player_node->getPixelX() - 16) / 32) << ", "
307
          << ((player_node->getPixelY() - 32) / 32);
308
309
    tab->chatLog(where.str(), BY_SERVER);
310
}
311
312
void CommandHandler::handleWho(const std::string &args, ChatTab *tab)
313
{
314
    Net::getChatHandler()->who();
315
}
316
317
void CommandHandler::handleMsg(const std::string &args, ChatTab *tab)
318
{
319
    std::string recvnick = "";
320
    std::string msg = "";
321
322
    if (args.substr(0, 1) == "\"")
323
    {
324
        const std::string::size_type pos = args.find('"', 1);
325
        if (pos != std::string::npos)
326
        {
327
            recvnick = args.substr(1, pos - 1);
328
            if (pos + 2 < args.length())
329
                msg = args.substr(pos + 2, args.length());
330
        }
331
    }
332
    else
333
    {
334
        const std::string::size_type pos = args.find(" ");
335
        if (pos != std::string::npos)
336
        {
337
            recvnick = args.substr(0, pos);
338
            if (pos + 1 < args.length())
339
                msg = args.substr(pos + 1, args.length());
340
        }
341
        else
342
        {
343
            recvnick = std::string(args);
344
            msg = "";
345
        }
346
    }
347
348
    trim(msg);
349
350
    if (msg.length() > 0)
351
    {
352
        std::string playerName = player_node->getName();
353
        std::string tempNick = recvnick;
354
355
        toLower(playerName);
356
        toLower(tempNick);
357
358
        if (tempNick.compare(playerName) == 0 || args.empty())
359
            return;
360
361
        chatWindow->whisper(recvnick, msg, true);
362
    }
363
    else
364
        tab->chatLog(_("Cannot send empty whispers!"), BY_SERVER);
365
}
366
367
void CommandHandler::handleQuery(const std::string &args, ChatTab *tab)
368
{
369
    if (chatWindow->addWhisperTab(args, true))
370
        return;
371
372
    tab->chatLog(strprintf(_("Cannot create a whisper tab for nick \"%s\"! "
373
            "It either already exists, or is you."), args.c_str()), BY_SERVER);
374
}
375
376
void CommandHandler::handleClear(const std::string &args, ChatTab *tab)
377
{
378
    chatWindow->clearTab();
379
}
380
381
void CommandHandler::handleJoin(const std::string &args, ChatTab *tab)
382
{
383
    std::string::size_type pos = args.find(' ');
384
    std::string name(args, 0, pos);
385
    std::string password(args, pos+1);
386
    tab->chatLog(strprintf(_("Requesting to join channel %s."), name.c_str()));
387
    Net::getChatHandler()->enterChannel(name, password);
388
}
389
390
void CommandHandler::handleListChannels(const std::string &args, ChatTab *tab)
391
{
392
    Net::getChatHandler()->channelList();
393
}
394
395
void CommandHandler::handleParty(const std::string &args, ChatTab *tab)
396
{
397
    if (args != "")
398
        Net::getPartyHandler()->invite(args);
399
    else
400
        tab->chatLog(_("Please specify a name."), BY_SERVER);
401
}
402
403
void CommandHandler::handleMe(const std::string &args, ChatTab *tab)
404
{
405
    Net::getChatHandler()->me(args);
406
}
407
408
void CommandHandler::handleRecord(const std::string &args, ChatTab *tab)
409
{
410
    chatWindow->setRecordingFile(args);
411
}
412
413
void CommandHandler::handleToggle(const std::string &args, ChatTab *tab)
414
{
415
    if (args.empty())
416
    {
417
        tab->chatLog(chatWindow->getReturnTogglesChat() ?
418
                _("Return toggles chat.") : _("Message closes chat."));
419
        return;
420
    }
421
422
    char opt = parseBoolean(args);
423
424
    switch (opt)
425
    {
426
        case 1:
427
            tab->chatLog(_("Return now toggles chat."));
428
            chatWindow->setReturnTogglesChat(true);
429
            return;
430
        case 0:
431
            tab->chatLog(_("Message now closes chat."));
432
            chatWindow->setReturnTogglesChat(false);
433
            return;
434
        case -1:
435
            tab->chatLog(strprintf(BOOLEAN_OPTIONS, "toggle"));
436
    }
437
}
438
439
void CommandHandler::handlePresent(const std::string &args, ChatTab *tab)
440
{
441
    chatWindow->doPresent();
442
}
443
444
void CommandHandler::handleIgnore(const std::string &args, ChatTab *tab)
445
{
446
    if (args.empty())
447
    {
448
        tab->chatLog(_("Please specify a name."), BY_SERVER);
449
        return;
450
    }
451
452
    if (player_relations.getRelation(args) == PlayerRelation::IGNORED)
453
    {
454
        tab->chatLog(_("Player already ignored!"), BY_SERVER);
455
        return;
456
    }
457
    else
458
        player_relations.setRelation(args, PlayerRelation::IGNORED);
459
460
    if (player_relations.getRelation(args) == PlayerRelation::IGNORED)
461
        tab->chatLog(_("Player successfully ignored!"), BY_SERVER);
462
    else
463
        tab->chatLog(_("Player could not be ignored!"), BY_SERVER);
464
}
465
466
void CommandHandler::handleUnignore(const std::string &args, ChatTab *tab)
467
{
468
    if (args.empty())
469
    {
470
        tab->chatLog(_("Please specify a name."), BY_SERVER);
471
        return;
472
    }
473
474
    if (player_relations.getRelation(args) == PlayerRelation::IGNORED)
475
        player_relations.removePlayer(args);
476
    else
477
    {
478
        tab->chatLog(_("Player wasn't ignored!"), BY_SERVER);
479
        return;
480
    }
481
482
    if (player_relations.getRelation(args) != PlayerRelation::IGNORED)
483
        tab->chatLog(_("Player no longer ignored!"), BY_SERVER);
484
    else
485
        tab->chatLog(_("Player could not be unignored!"), BY_SERVER);
486
}