GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/progs/manaplus/actions/chat.cpp Lines: 1 315 0.3 %
Date: 2017-11-29 Branches: 2 398 0.5 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2017  The ManaPlus Developers
4
 *
5
 *  This file is part of The ManaPlus Client.
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, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "actions/chat.h"
22
23
#include "configuration.h"
24
25
#include "actions/actiondef.h"
26
27
#include "const/gui/chat.h"
28
29
#include "being/localplayer.h"
30
31
#include "gui/sdlinput.h"
32
33
#include "gui/windows/chatwindow.h"
34
35
#include "listeners/inputactionreplaylistener.h"
36
37
#include "net/charserverhandler.h"
38
#include "net/chathandler.h"
39
#include "net/guildhandler.h"
40
#include "net/net.h"
41
#include "net/partyhandler.h"
42
43
#ifdef TMWA_SUPPORT
44
#include "net/tmwa/guildmanager.h"
45
#endif  // TMWA_SUPPORT
46
47
#include "resources/iteminfo.h"
48
49
#include "resources/db/itemdb.h"
50
51
#include "utils/booleanoptions.h"
52
#include "utils/chatutils.h"
53
#include "utils/parameters.h"
54
55
#include "utils/translation/podict.h"
56
57
#include "debug.h"
58
59
const int DEFAULT_CHAT_WINDOW_SCROLL = 7;
60
61
namespace Actions
62
{
63
64
static void outString(ChatTab *const tab,
65
                      const std::string &str,
66
                      const std::string &def)
67
{
68
    if (tab == nullptr)
69
    {
70
        if (chatHandler != nullptr)
71
            chatHandler->talk(def, GENERAL_CHANNEL);
72
        return;
73
    }
74
75
    switch (tab->getType())
76
    {
77
        case ChatTabType::PARTY:
78
        {
79
            if (partyHandler != nullptr)
80
                partyHandler->chat(str);
81
            break;
82
        }
83
        case ChatTabType::GUILD:
84
        {
85
            if ((guildHandler == nullptr) || (localPlayer == nullptr))
86
                return;
87
            const Guild *const guild = localPlayer->getGuild();
88
            if (guild != nullptr)
89
            {
90
#ifdef TMWA_SUPPORT
91
                if (guild->getServerGuild())
92
                {
93
                    if (Net::getNetworkType() == ServerType::TMWATHENA)
94
                        return;
95
                    guildHandler->chat(str);
96
                }
97
                else if (guildManager != nullptr)
98
                {
99
                    guildManager->chat(str);
100
                }
101
#else  // TMWA_SUPPORT
102
103
                if (guild->getServerGuild())
104
                    guildHandler->chat(str);
105
#endif  // TMWA_SUPPORT
106
            }
107
            break;
108
        }
109
        case ChatTabType::CHANNEL:
110
        case ChatTabType::GM:
111
        case ChatTabType::TRADE:
112
            tab->chatInput(str);
113
            break;
114
        default:
115
        case ChatTabType::UNKNOWN:
116
        case ChatTabType::INPUT:
117
        case ChatTabType::WHISPER:
118
        case ChatTabType::DEBUG:
119
        case ChatTabType::BATTLE:
120
        case ChatTabType::LANG:
121
            if (chatHandler != nullptr)
122
                chatHandler->talk(str, GENERAL_CHANNEL);
123
            break;
124
    }
125
}
126
127
impHandler0(toggleChat)
128
{
129
    return chatWindow != nullptr ? chatWindow->requestChatFocus() : false;
130
}
131
132
impHandler0(prevChatTab)
133
{
134
    if (chatWindow != nullptr)
135
    {
136
        chatWindow->prevTab();
137
        return true;
138
    }
139
    return false;
140
}
141
142
impHandler0(nextChatTab)
143
{
144
    if (chatWindow != nullptr)
145
    {
146
        chatWindow->nextTab();
147
        return true;
148
    }
149
    return false;
150
}
151
152
impHandler0(closeChatTab)
153
{
154
    if (chatWindow != nullptr)
155
    {
156
        chatWindow->closeTab();
157
        return true;
158
    }
159
    return false;
160
}
161
162
impHandler0(closeAllChatTabs)
163
{
164
    if (chatWindow != nullptr)
165
    {
166
        chatWindow->removeAllWhispers();
167
        chatWindow->saveState();
168
        return true;
169
    }
170
    return false;
171
}
172
173
impHandler0(ignoreAllWhispers)
174
{
175
    if (chatWindow != nullptr)
176
    {
177
        chatWindow->ignoreAllWhispers();
178
        chatWindow->saveState();
179
        return true;
180
    }
181
    return false;
182
}
183
184
impHandler0(scrollChatUp)
185
{
186
    if ((chatWindow != nullptr) && chatWindow->isWindowVisible())
187
    {
188
        chatWindow->scroll(-DEFAULT_CHAT_WINDOW_SCROLL);
189
        return true;
190
    }
191
    return false;
192
}
193
194
impHandler0(scrollChatDown)
195
{
196
    if ((chatWindow != nullptr) && chatWindow->isWindowVisible())
197
    {
198
        chatWindow->scroll(DEFAULT_CHAT_WINDOW_SCROLL);
199
        return true;
200
    }
201
    return false;
202
}
203
204
static bool splitWhisper(const std::string &args,
205
                         std::string &recvnick,
206
                         std::string &message)
207
{
208
    if (args.substr(0, 1) == "\"")
209
    {
210
        const size_t pos = args.find('"', 1);
211
        if (pos != std::string::npos)
212
        {
213
            recvnick = args.substr(1, pos - 1);
214
            if (pos + 2 < args.length())
215
                message = args.substr(pos + 2, args.length());
216
        }
217
    }
218
    else
219
    {
220
        const size_t pos = args.find(' ');
221
        if (pos != std::string::npos)
222
        {
223
            recvnick = args.substr(0, pos);
224
            if (pos + 1 < args.length())
225
                message = args.substr(pos + 1, args.length());
226
        }
227
        else
228
        {
229
            recvnick = std::string(args);
230
            message.clear();
231
        }
232
    }
233
234
    trim(message);
235
236
    if (message.length() > 0)
237
    {
238
        std::string playerName = localPlayer->getName();
239
        std::string tempNick = recvnick;
240
241
        toLower(playerName);
242
        toLower(tempNick);
243
244
        if (tempNick == playerName || args.empty())
245
            return false;
246
247
        return true;
248
    }
249
    return false;
250
}
251
252
impHandler(msg)
253
{
254
    std::string recvnick;
255
    std::string message;
256
257
    if (splitWhisper(event.args, recvnick, message))
258
    {
259
        if (chatWindow == nullptr)
260
            return false;
261
        ChatTab *const tab = chatWindow->addChatTab(recvnick, false, true);
262
        if (tab != nullptr)
263
        {
264
            chatWindow->saveState();
265
            tab->chatInput(message);
266
        }
267
    }
268
    else
269
    {
270
        if (event.tab != nullptr)
271
        {
272
            event.tab->chatLog(
273
                // TRANSLATORS: whisper send
274
                _("Cannot send empty whisper or channel message!"),
275
                ChatMsgType::BY_SERVER);
276
        }
277
    }
278
    return true;
279
}
280
281
impHandler(msgText)
282
{
283
    if (chatWindow == nullptr)
284
        return false;
285
286
    if (config.getBoolValue("whispertab"))
287
    {
288
        chatWindow->localChatInput("/q " + event.args);
289
    }
290
    else
291
    {
292
        chatWindow->addInputText(std::string("/w \"").append(
293
            event.args).append("\" "));
294
    }
295
    return true;
296
}
297
298
impHandler(msg2)
299
{
300
    std::string recvnick;
301
    std::string message;
302
303
    if (chatHandler != nullptr &&
304
        splitWhisper(event.args, recvnick, message))
305
    {
306
        chatHandler->privateMessage(recvnick, message);
307
    }
308
    return true;
309
}
310
311
impHandler(query)
312
{
313
    const std::string &args = event.args;
314
    if (chatWindow != nullptr)
315
    {
316
        if (chatWindow->addChatTab(args, true, true) != nullptr)
317
        {
318
            chatWindow->saveState();
319
            return true;
320
        }
321
    }
322
323
    if (event.tab != nullptr)
324
    {
325
        // TRANSLATORS: new whisper or channel query
326
        event.tab->chatLog(strprintf(_("Cannot create a whisper tab "
327
            "\"%s\"! It probably already exists."),
328
            args.c_str()), ChatMsgType::BY_SERVER);
329
    }
330
    return true;
331
}
332
333
impHandler0(clearChatTab)
334
{
335
    if (chatWindow != nullptr)
336
    {
337
        chatWindow->clearTab();
338
        return true;
339
    }
340
    return false;
341
}
342
343
impHandler(createParty)
344
{
345
    if (partyHandler == nullptr)
346
        return false;
347
348
    if (event.args.empty())
349
    {
350
        // TRANSLATORS: dialog header
351
        inputActionReplayListener.openDialog(_("Create party"),
352
            "",
353
            InputAction::CREATE_PARTY);
354
    }
355
    else
356
    {
357
        partyHandler->create(event.args);
358
    }
359
    return true;
360
}
361
362
impHandler(createGuild)
363
{
364
    if ((guildHandler == nullptr) ||
365
        Net::getNetworkType() == ServerType::TMWATHENA)
366
    {
367
        return false;
368
    }
369
370
    if (event.args.empty())
371
    {
372
        // TRANSLATORS: dialog header
373
        inputActionReplayListener.openDialog(_("Create guild"),
374
            "",
375
            InputAction::CREATE_GUILD);
376
    }
377
    else
378
    {
379
        guildHandler->create(event.args);
380
    }
381
    return true;
382
}
383
384
impHandler(party)
385
{
386
    if (!event.args.empty())
387
    {
388
        if (partyHandler != nullptr)
389
            partyHandler->invite(event.args);
390
    }
391
    else
392
    {
393
        if (event.tab != nullptr)
394
        {
395
            // TRANSLATORS: party invite message
396
            event.tab->chatLog(_("Please specify a name."),
397
                ChatMsgType::BY_SERVER);
398
        }
399
    }
400
    return true;
401
}
402
403
impHandler(guild)
404
{
405
    if ((guildHandler == nullptr) || (localPlayer == nullptr))
406
        return false;
407
408
    const std::string args = event.args;
409
    if (!args.empty())
410
    {
411
        const Guild *const guild = localPlayer->getGuild();
412
        if (guild != nullptr)
413
        {
414
#ifdef TMWA_SUPPORT
415
            if (guild->getServerGuild())
416
                guildHandler->invite(args);
417
            else if (guildManager != nullptr)
418
                GuildManager::invite(args);
419
#else  // TMWA_SUPPORT
420
421
            guildHandler->invite(args);
422
#endif  // TMWA_SUPPORT
423
        }
424
    }
425
    else
426
    {
427
        if (event.tab != nullptr)
428
        {
429
            // TRANSLATORS: guild invite message
430
            event.tab->chatLog(_("Please specify a name."),
431
                ChatMsgType::BY_SERVER);
432
        }
433
        else if (localChatTab != nullptr)
434
        {
435
            // TRANSLATORS: guild invite message
436
            localChatTab->chatLog(_("Please specify a name."),
437
                ChatMsgType::BY_SERVER);
438
        }
439
    }
440
    return true;
441
}
442
443
impHandler(me)
444
{
445
    outString(event.tab, textToMe(event.args), event.args);
446
    return true;
447
}
448
449
impHandler(toggle)
450
{
451
    if (event.args.empty())
452
    {
453
        if ((chatWindow != nullptr) && (event.tab != nullptr))
454
        {
455
            event.tab->chatLog(chatWindow->getReturnTogglesChat() ?
456
                // TRANSLATORS: message from toggle chat command
457
                _("Return toggles chat.") : _("Message closes chat."),
458
                ChatMsgType::BY_SERVER);
459
        }
460
        return true;
461
    }
462
463
    switch (parseBoolean(event.args))
464
    {
465
        case 1:
466
            if (event.tab != nullptr)
467
            {
468
                // TRANSLATORS: message from toggle chat command
469
                event.tab->chatLog(_("Return now toggles chat."),
470
                    ChatMsgType::BY_SERVER);
471
            }
472
            if (chatWindow != nullptr)
473
                chatWindow->setReturnTogglesChat(true);
474
            return true;
475
        case 0:
476
            if (event.tab != nullptr)
477
            {
478
                // TRANSLATORS: message from toggle chat command
479
                event.tab->chatLog(_("Message now closes chat."),
480
                    ChatMsgType::BY_SERVER);
481
            }
482
            if (chatWindow != nullptr)
483
                chatWindow->setReturnTogglesChat(false);
484
            return true;
485
        case -1:
486
            if (event.tab != nullptr)
487
            {
488
                event.tab->chatLog(strprintf(BOOLEAN_OPTIONS, "toggle"),
489
                    ChatMsgType::BY_SERVER);
490
            }
491
            return true;
492
        default:
493
            return true;
494
    }
495
}
496
497
impHandler(kickParty)
498
{
499
    if (!event.args.empty())
500
    {
501
        if (partyHandler != nullptr)
502
            partyHandler->kick(event.args);
503
    }
504
    else
505
    {
506
        if (event.tab != nullptr)
507
        {
508
            // TRANSLATORS: party kick message
509
            event.tab->chatLog(_("Please specify a name."),
510
                ChatMsgType::BY_SERVER);
511
        }
512
    }
513
    return true;
514
}
515
516
impHandler(kickGuild)
517
{
518
    if (!event.args.empty())
519
    {
520
        if (localPlayer != nullptr)
521
        {
522
            const Guild *const guild = localPlayer->getGuild();
523
            if (guild != nullptr)
524
            {
525
                if (guild->getServerGuild())
526
                {
527
                    if (guildHandler != nullptr)
528
                        guildHandler->kick(guild->getMember(event.args), "");
529
                }
530
#ifdef TMWA_SUPPORT
531
                else if (guildManager != nullptr)
532
                {
533
                    GuildManager::kick(event.args);
534
                }
535
#endif  // TMWA_SUPPORT
536
            }
537
        }
538
    }
539
    else
540
    {
541
        if (event.tab != nullptr)
542
        {
543
            // TRANSLATORS: party kick message
544
            event.tab->chatLog(_("Please specify a name."),
545
                ChatMsgType::BY_SERVER);
546
        }
547
    }
548
    return true;
549
}
550
551
impHandler(addText)
552
{
553
    if (chatWindow != nullptr)
554
        chatWindow->addInputText(event.args);
555
    return true;
556
}
557
558
impHandler0(clearChat)
559
{
560
    if (chatWindow != nullptr)
561
        chatWindow->clearTab();
562
    return true;
563
}
564
565
impHandler0(chatGeneralTab)
566
{
567
    if (chatWindow != nullptr)
568
        chatWindow->selectTabByType(ChatTabType::INPUT);
569
    return true;
570
}
571
572
impHandler0(chatDebugTab)
573
{
574
    if (chatWindow != nullptr)
575
        chatWindow->selectTabByType(ChatTabType::DEBUG);
576
    return true;
577
}
578
579
impHandler0(chatBattleTab)
580
{
581
    if (chatWindow != nullptr)
582
        chatWindow->selectTabByType(ChatTabType::BATTLE);
583
    return true;
584
}
585
586
impHandler0(chatTradeTab)
587
{
588
    if (chatWindow != nullptr)
589
        chatWindow->selectTabByType(ChatTabType::TRADE);
590
    return true;
591
}
592
593
impHandler0(chatLangTab)
594
{
595
    if (chatWindow != nullptr)
596
        chatWindow->selectTabByType(ChatTabType::LANG);
597
    return true;
598
}
599
600
impHandler0(chatGmTab)
601
{
602
    if (chatWindow != nullptr)
603
        chatWindow->selectTabByType(ChatTabType::GM);
604
    return true;
605
}
606
607
impHandler0(chatPartyTab)
608
{
609
    if (chatWindow != nullptr)
610
        chatWindow->selectTabByType(ChatTabType::PARTY);
611
    return true;
612
}
613
614
impHandler0(chatGuildTab)
615
{
616
    if (chatWindow != nullptr)
617
        chatWindow->selectTabByType(ChatTabType::GUILD);
618
    return true;
619
}
620
621
impHandler(hat)
622
{
623
    if ((localPlayer == nullptr) || (charServerHandler == nullptr))
624
        return false;
625
626
    const int sprite = localPlayer->getSpriteID(
627
        charServerHandler->hatSprite());
628
    std::string str;
629
    if (sprite == 0)
630
    {
631
        // TRANSLATORS: equipped hat chat message
632
        str = strprintf(_("no hat equipped."));
633
    }
634
    else
635
    {
636
        const ItemInfo &info = ItemDB::get(sprite);
637
        // TRANSLATORS: equipped hat chat message
638
        str = strprintf(_("equipped hat %s."),
639
            info.getName().c_str());
640
    }
641
    outString(event.tab, str, str);
642
    return true;
643
}
644
645
impHandler(chatClipboard)
646
{
647
    int x = 0;
648
    int y = 0;
649
650
    if ((chatWindow != nullptr) && parse2Int(event.args, x, y))
651
    {
652
        chatWindow->copyToClipboard(x, y);
653
        return true;
654
    }
655
    return false;
656
}
657
658
impHandler(guildNotice)
659
{
660
    if (localPlayer == nullptr)
661
        return false;
662
    const std::string args = event.args;
663
    if (args.empty())
664
    {
665
        // TRANSLATORS: dialog header
666
        inputActionReplayListener.openDialog(_("Guild notice"),
667
            "",
668
            InputAction::GUILD_NOTICE);
669
        return true;
670
    }
671
672
    std::string str2;
673
    if (args.size() > 60)
674
        str2 = args.substr(60);
675
    const Guild *const guild = localPlayer->getGuild();
676
    if (guild != nullptr)
677
    {
678
        guildHandler->changeNotice(guild->getId(),
679
            args.substr(0, 60),
680
            str2);
681
    }
682
    return true;
683
}
684
685
impHandler(translate)
686
{
687
    if (reverseDictionary == nullptr ||
688
        localPlayer == nullptr ||
689
        event.args.empty())
690
    {
691
        return false;
692
    }
693
694
    ChatTab *const tab = event.tab;
695
    if (tab == nullptr)
696
        return false;
697
698
    std::string srcStr = event.args;
699
    std::string enStr;
700
    toLower(srcStr);
701
    if (localPlayer->getLanguageId() > 0)
702
    {
703
        if (reverseDictionary->haveStr(srcStr))
704
            enStr = reverseDictionary->getStr(srcStr);
705
        else if (dictionary->haveStr(srcStr))
706
            enStr = srcStr;
707
    }
708
    else
709
    {
710
        if (dictionary->haveStr(srcStr))
711
            enStr = srcStr;
712
    }
713
714
    if (enStr.empty())
715
    {
716
        tab->chatLog(
717
            // TRANSLATORS: translation error message
718
            strprintf(_("No translation found for string: %s"),
719
            srcStr.c_str()),
720
            ChatMsgType::BY_SERVER);
721
        return true;
722
    }
723
724
    tab->chatInput(enStr);
725
    return true;
726
}
727
728
impHandler(sendGuiKey)
729
{
730
    if (guiInput == nullptr)
731
        return false;
732
733
    const std::string args = event.args;
734
    if (args.empty())
735
        return false;
736
    StringVect pars;
737
    if (!splitParameters(pars, args, " ,", '\"'))
738
        return false;
739
    const int sz = CAST_S32(pars.size());
740
    if (sz < 1)
741
        return false;
742
743
    int keyValue = atoi(pars[0].c_str());
744
    if (keyValue == 0 &&
745
        pars[0].size() == 1)
746
    {
747
        keyValue = CAST_S32(pars[0][0]);
748
    }
749
    if (sz == 2)
750
    {
751
        const InputActionT actionId = inputManager.getActionByConfigField(
752
            pars[1]);
753
        guiInput->simulateKey(keyValue, actionId);
754
    }
755
    else
756
    {
757
        guiInput->simulateKey(keyValue, InputAction::NO_VALUE);
758
    }
759
    return true;
760
}
761
762
impHandler(sendMouseKey)
763
{
764
    if (guiInput == nullptr)
765
        return false;
766
    const std::string args = event.args;
767
    if (args.empty())
768
        return false;
769
    StringVect pars;
770
    if (!splitParameters(pars, args, " ,", '\"'))
771
        return false;
772
    const int sz = CAST_S32(pars.size());
773
    if (sz != 3)
774
        return false;
775
776
    const int x = atoi(pars[0].c_str());
777
    const int y = atoi(pars[1].c_str());
778
    const int key1 = CAST_S32(MouseButton::LEFT);
779
    const int key2 = CAST_S32(MouseButton::MIDDLE);
780
    const int key = atoi(pars[2].c_str());
781
    if (key < key1 || key > key2)
782
        return false;
783
    guiInput->simulateMouseClick(x,
784
        y,
785
        static_cast<MouseButtonT>(key));
786
    return true;
787
}
788
789
impHandler(sendChars)
790
{
791
    if (guiInput == nullptr)
792
        return false;
793
794
    const std::string args = event.args;
795
    if (args.empty())
796
        return false;
797
798
    const size_t sz = args.size();
799
    for (size_t f = 0; f < sz; f ++)
800
    {
801
        guiInput->simulateKey(CAST_S32(args[f]),
802
            InputAction::NO_VALUE);
803
    }
804
805
    return true;
806
}
807
808

6
}  // namespace Actions