GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/progs/manaplus/actions/chat.cpp Lines: 1 318 0.3 %
Date: 2018-06-18 21:15:20 Branches: 0 397 0.0 %

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