GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/progs/manaplus/actions/actions.cpp Lines: 1 774 0.1 %
Date: 2020-06-04 Branches: 0 949 0.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2019  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/actions.h"
22
23
#include "actormanager.h"
24
#include "configuration.h"
25
#include "game.h"
26
#ifdef USE_OPENGL
27
#include "graphicsmanager.h"
28
#endif  // USE_OPENGL
29
#include "main.h"
30
#include "spellmanager.h"
31
32
#include "actions/actiondef.h"
33
34
#include "being/localplayer.h"
35
#include "being/playerinfo.h"
36
37
#include "const/spells.h"
38
39
#include "const/resources/skill.h"
40
41
#include "fs/files.h"
42
43
#include "gui/gui.h"
44
#include "gui/popupmanager.h"
45
#include "gui/sdlinput.h"
46
#include "gui/windowmanager.h"
47
48
#include "gui/shortcut/dropshortcut.h"
49
#include "gui/shortcut/emoteshortcut.h"
50
#include "gui/shortcut/itemshortcut.h"
51
52
#include "gui/popups/popupmenu.h"
53
54
#include "gui/windows/buydialog.h"
55
#include "gui/windows/okdialog.h"
56
#include "gui/windows/tradewindow.h"
57
#include "gui/windows/quitdialog.h"
58
#include "gui/windows/buyselldialog.h"
59
#include "gui/windows/chatwindow.h"
60
#include "gui/windows/helpwindow.h"
61
#include "gui/windows/inventorywindow.h"
62
#include "gui/windows/itemamountwindow.h"
63
#include "gui/windows/npcdialog.h"
64
#include "gui/windows/outfitwindow.h"
65
#include "gui/windows/setupwindow.h"
66
#include "gui/windows/shopwindow.h"
67
#include "gui/windows/shortcutwindow.h"
68
#include "gui/windows/skilldialog.h"
69
#include "gui/windows/whoisonline.h"
70
71
#include "gui/widgets/createwidget.h"
72
73
#include "gui/widgets/tabs/chat/chattab.h"
74
75
#include "input/inputactionoperators.h"
76
77
#if defined USE_OPENGL
78
#include "render/normalopenglgraphics.h"
79
#endif  // USE_OPENGL
80
81
#include "net/adminhandler.h"
82
#include "net/beinghandler.h"
83
#include "net/buyingstorehandler.h"
84
#include "net/buysellhandler.h"
85
#include "net/chathandler.h"
86
#include "net/download.h"
87
#include "net/homunculushandler.h"
88
#include "net/gamehandler.h"
89
#include "net/inventoryhandler.h"
90
#include "net/ipc.h"
91
#include "net/mercenaryhandler.h"
92
#include "net/net.h"
93
#include "net/npchandler.h"
94
#include "net/serverfeatures.h"
95
#include "net/uploadcharinfo.h"
96
#include "net/tradehandler.h"
97
#include "net/vendinghandler.h"
98
99
#include "resources/iteminfo.h"
100
#include "resources/memorymanager.h"
101
102
#include "resources/resourcemanager/resourcemanager.h"
103
104
#include "utils/chatutils.h"
105
#include "utils/foreach.h"
106
#include "utils/gettext.h"
107
#include "utils/parameters.h"
108
#include "utils/timer.h"
109
110
#ifdef TMWA_SUPPORT
111
#include "net/playerhandler.h"
112
113
#include "utils/mathutils.h"
114
#endif  // TMWA_SUPPORT
115
116
PRAGMA48(GCC diagnostic push)
117
PRAGMA48(GCC diagnostic ignored "-Wshadow")
118
#ifdef ANDROID
119
#ifndef USE_SDL2
120
#include <SDL_screenkeyboard.h>
121
#endif  // USE_OPENGL
122
#endif  // ANDROID
123
PRAGMA48(GCC diagnostic pop)
124
125
#include <sstream>
126
127
#include "debug.h"
128
129
extern std::string tradePartnerName;
130
extern QuitDialog *quitDialog;
131
extern time_t start_time;
132
extern char **environ;
133
134
namespace Actions
135
{
136
137
static int uploadUpdate(void *ptr,
138
                        const DownloadStatusT status,
139
                        size_t total A_UNUSED,
140
                        const size_t remaining A_UNUSED) A_NONNULL(1);
141
142
static int uploadUpdate(void *ptr,
143
                        const DownloadStatusT status,
144
                        size_t total A_UNUSED,
145
                        const size_t remaining A_UNUSED)
146
{
147
    if (status == DownloadStatus::Idle || status == DownloadStatus::Starting)
148
        return 0;
149
150
    UploadChatInfo *const info = reinterpret_cast<UploadChatInfo*>(ptr);
151
    if (info == nullptr)
152
        return 0;
153
154
    if (status == DownloadStatus::Complete)
155
    {
156
        std::string str = Net::Download::getUploadResponse();
157
        const size_t sz = str.size();
158
        if (sz > 0)
159
        {
160
            if (str[sz - 1] == '\n')
161
                str = str.substr(0, sz - 1);
162
            str.append(info->addStr);
163
            ChatTab *const tab = info->tab;
164
            if (chatWindow != nullptr &&
165
                (tab == nullptr || chatWindow->isTabPresent(tab)))
166
            {
167
                str = strprintf("%s [@@%s |%[email protected]@]",
168
                    info->text.c_str(), str.c_str(), str.c_str());
169
                outStringNormal(tab, str, str);
170
            }
171
            else
172
            {
173
                CREATEWIDGET(OkDialog,
174
                    // TRANSLATORS: file uploaded message
175
                    _("File uploaded"),
176
                    str,
177
                    // TRANSLATORS: ok dialog button
178
                    _("OK"),
179
                    DialogType::OK,
180
                    Modal_true,
181
                    ShowCenter_false,
182
                    nullptr,
183
                    260);
184
            }
185
        }
186
    }
187
//    delete2(info->upload)
188
    info->upload = nullptr;
189
    delete info;
190
    return 0;
191
}
192
193
static void uploadFile(const std::string &str,
194
                       const std::string &fileName,
195
                       const std::string &addStr,
196
                       ChatTab *const tab)
197
{
198
    UploadChatInfo *const info = new UploadChatInfo;
199
    Net::Download *const upload = new Net::Download(info,
200
        "http://ix.io",
201
        &uploadUpdate,
202
        false, true, false);
203
    info->upload = upload;
204
    info->text = str;
205
    info->addStr = addStr;
206
    info->tab = tab;
207
    upload->setFile(fileName, -1);
208
    upload->start();
209
}
210
211
static Being *findBeing(const std::string &name, const bool npc)
212
{
213
    if ((localPlayer == nullptr) || (actorManager == nullptr))
214
        return nullptr;
215
216
    Being *being = nullptr;
217
218
    if (name.empty())
219
    {
220
        being = localPlayer->getTarget();
221
    }
222
    else
223
    {
224
        being = actorManager->findBeingByName(
225
            name, ActorType::Unknown);
226
    }
227
    if ((being == nullptr) && npc)
228
    {
229
        being = actorManager->findNearestLivingBeing(
230
            localPlayer, 1, ActorType::Npc, AllowSort_true);
231
        if (being != nullptr)
232
        {
233
            if (abs(being->getTileX() - localPlayer->getTileX()) > 1
234
                || abs(being->getTileY() - localPlayer->getTileY()) > 1)
235
            {
236
                being = nullptr;
237
            }
238
        }
239
    }
240
    if ((being == nullptr) && npc)
241
    {
242
        being = actorManager->findNearestLivingBeing(
243
            localPlayer, 1, ActorType::Player, AllowSort_true);
244
        if (being != nullptr)
245
        {
246
            if (abs(being->getTileX() - localPlayer->getTileX()) > 1
247
                || abs(being->getTileY() - localPlayer->getTileY()) > 1)
248
            {
249
                being = nullptr;
250
            }
251
        }
252
    }
253
    return being;
254
}
255
256
static Item *getItemByInvIndex(const int index,
257
                               const InventoryTypeT invType)
258
{
259
    const Inventory *inv = nullptr;
260
    switch (invType)
261
    {
262
        case InventoryType::Storage:
263
            inv = PlayerInfo::getStorageInventory();
264
            break;
265
266
        case InventoryType::Inventory:
267
            inv = PlayerInfo::getInventory();
268
            break;
269
        case InventoryType::Trade:
270
        case InventoryType::Npc:
271
        case InventoryType::Cart:
272
        case InventoryType::Vending:
273
        case InventoryType::MailEdit:
274
        case InventoryType::MailView:
275
        case InventoryType::Craft:
276
        case InventoryType::TypeEnd:
277
        default:
278
            break;
279
    }
280
    if (inv != nullptr)
281
        return inv->getItem(index);
282
    return nullptr;
283
}
284
285
static int getAmountFromEvent(const InputEvent &event,
286
                              Item *&item0,
287
                              const InventoryTypeT invType)
288
{
289
    Item *const item = getItemByInvIndex(atoi(event.args.c_str()),
290
        invType);
291
    item0 = item;
292
    if (item == nullptr)
293
        return 0;
294
295
    std::string str = event.args;
296
    removeToken(str, " ");
297
298
    if (str.empty())
299
        return 0;
300
301
    int amount = 0;
302
    if (str[0] == '-')
303
    {
304
        if (str.size() > 1)
305
        {
306
            amount = item->getQuantity() - atoi(str.substr(1).c_str());
307
            if (amount <= 0 || amount > item->getQuantity())
308
                amount = item->getQuantity();
309
        }
310
    }
311
    else if (str == "/")
312
    {
313
        amount = item->getQuantity() / 2;
314
    }
315
    else if (str == "all")
316
    {
317
        amount = item->getQuantity();
318
    }
319
    else
320
    {
321
        amount = atoi(str.c_str());
322
    }
323
    return amount;
324
}
325
326
impHandler(emote)
327
{
328
    const int emotion = 1 + (event.action - InputAction::EMOTE_1);
329
    if (emotion > 0)
330
    {
331
        if (emoteShortcut != nullptr)
332
            emoteShortcut->useEmotePlayer(emotion);
333
        if (Game::instance() != nullptr)
334
            Game::instance()->setValidSpeed();
335
        return true;
336
    }
337
338
    return false;
339
}
340
341
impHandler(outfit)
342
{
343
    if (inputManager.isActionActive(InputAction::WEAR_OUTFIT))
344
    {
345
        const int num = event.action - InputAction::OUTFIT_1;
346
        if ((outfitWindow != nullptr) && num >= 0)
347
        {
348
            outfitWindow->wearOutfit(num,
349
                true,
350
                false);
351
            if (Game::instance() != nullptr)
352
                Game::instance()->setValidSpeed();
353
            return true;
354
        }
355
    }
356
    else if (inputManager.isActionActive(InputAction::COPY_OUTFIT))
357
    {
358
        const int num = event.action - InputAction::OUTFIT_1;
359
        if ((outfitWindow != nullptr) && num >= 0)
360
        {
361
            outfitWindow->copyOutfit(num);
362
            if (Game::instance() != nullptr)
363
                Game::instance()->setValidSpeed();
364
            return true;
365
        }
366
    }
367
368
    return false;
369
}
370
371
impHandler0(mouseClick)
372
{
373
    if ((guiInput == nullptr) || (gui == nullptr))
374
        return false;
375
376
    int mouseX;
377
    int mouseY;
378
    Gui::getMouseState(mouseX, mouseY);
379
    guiInput->simulateMouseClick(mouseX, mouseY, MouseButton::RIGHT);
380
    return true;
381
}
382
383
impHandler0(ok)
384
{
385
    // Close the Browser if opened
386
    if ((helpWindow != nullptr) && helpWindow->isWindowVisible())
387
    {
388
        helpWindow->setVisible(Visible_false);
389
        return true;
390
    }
391
    // Close the config window, cancelling changes if opened
392
    else if ((setupWindow != nullptr) && setupWindow->isWindowVisible())
393
    {
394
        setupWindow->action(ActionEvent(nullptr, "cancel"));
395
        return true;
396
    }
397
    else if (NpcDialog *const dialog = NpcDialog::getActive())
398
    {
399
        dialog->action(ActionEvent(nullptr, "ok"));
400
        return true;
401
    }
402
    else if (popupMenu->isPopupVisible())
403
    {
404
        popupMenu->select();
405
    }
406
    return false;
407
}
408
409
impHandler(shortcut)
410
{
411
    if (itemShortcutWindow != nullptr)
412
    {
413
        const int num = itemShortcutWindow->getTabIndex();
414
        if (num >= 0 && num < CAST_S32(SHORTCUT_TABS))
415
        {
416
            if (itemShortcut[num] != nullptr)
417
            {
418
                itemShortcut[num]->useItem(event.action
419
                    - InputAction::SHORTCUT_1);
420
            }
421
        }
422
        return true;
423
    }
424
    return false;
425
}
426
427
impHandler0(quit)
428
{
429
    if (Game::instance() == nullptr)
430
        return false;
431
    if (PopupManager::isPopupMenuVisible())
432
    {
433
        PopupManager::closePopupMenu();
434
        return true;
435
    }
436
    else if (quitDialog == nullptr)
437
    {
438
        CREATEWIDGETV(quitDialog, QuitDialog,
439
            &quitDialog);
440
        quitDialog->requestMoveToTop();
441
        return true;
442
    }
443
    return false;
444
}
445
446
impHandler0(dropItem0)
447
{
448
    if (dropShortcut != nullptr)
449
    {
450
        dropShortcut->dropFirst();
451
        return true;
452
    }
453
    return false;
454
}
455
456
impHandler0(dropItem)
457
{
458
    if (dropShortcut != nullptr)
459
    {
460
        dropShortcut->dropItems(1);
461
        return true;
462
    }
463
    return false;
464
}
465
466
impHandler(dropItemId)
467
{
468
    const Inventory *const inv = PlayerInfo::getInventory();
469
    if (inv == nullptr)
470
        return false;
471
472
    // +++ ignoring item color for now
473
    Item *const item = inv->findItem(atoi(event.args.c_str()),
474
        ItemColor_one);
475
476
    if ((item != nullptr) && !PlayerInfo::isItemProtected(item->getId()))
477
    {
478
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::ItemDrop,
479
            inventoryWindow,
480
            item,
481
            0,
482
            0);
483
    }
484
    return true;
485
}
486
487
impHandler(dropItemInv)
488
{
489
    Item *const item = getItemByInvIndex(atoi(event.args.c_str()),
490
        InventoryType::Inventory);
491
    if ((item != nullptr) && !PlayerInfo::isItemProtected(item->getId()))
492
    {
493
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::ItemDrop,
494
            inventoryWindow,
495
            item,
496
            0,
497
            0);
498
    }
499
    return true;
500
}
501
502
impHandler(dropItemIdAll)
503
{
504
    const Inventory *const inv = PlayerInfo::getInventory();
505
    if (inv == nullptr)
506
        return false;
507
508
    // +++ ignoring item color for now
509
    Item *const item = inv->findItem(atoi(event.args.c_str()),
510
        ItemColor_one);
511
512
    if ((item != nullptr) && !PlayerInfo::isItemProtected(item->getId()))
513
        PlayerInfo::dropItem(item, item->getQuantity(), Sfx_true);
514
    return true;
515
}
516
517
impHandler(dropItemInvAll)
518
{
519
    Item *const item = getItemByInvIndex(atoi(event.args.c_str()),
520
        InventoryType::Inventory);
521
    if ((item != nullptr) && !PlayerInfo::isItemProtected(item->getId()))
522
        PlayerInfo::dropItem(item, item->getQuantity(), Sfx_true);
523
    return true;
524
}
525
526
#ifdef TMWA_SUPPORT
527
impHandler(heal)
528
{
529
    if (Net::getNetworkType() != ServerType::TMWATHENA)
530
        return false;
531
    if (actorManager != nullptr &&
532
        localPlayer != nullptr)
533
    {
534
        std::string args = event.args;
535
536
        if (!args.empty())
537
        {
538
            const Being *being = nullptr;
539
            if (args[0] == ':')
540
            {
541
                being = actorManager->findBeing(fromInt(atoi(
542
                    args.substr(1).c_str()), BeingId));
543
                if (being != nullptr && being->getType() == ActorType::Monster)
544
                    being = nullptr;
545
            }
546
            else
547
            {
548
                being = actorManager->findBeingByName(args, ActorType::Player);
549
            }
550
            if (being != nullptr)
551
                actorManager->heal(being);
552
        }
553
        else
554
        {
555
            Being *target = localPlayer->getTarget();
556
            if (inputManager.isActionActive(InputAction::STOP_ATTACK))
557
            {
558
                if (target == nullptr ||
559
                    target->getType() != ActorType::Player)
560
                {
561
                    target = actorManager->findNearestLivingBeing(
562
                        localPlayer, 10, ActorType::Player, AllowSort_true);
563
                }
564
            }
565
            else
566
            {
567
                if (target == nullptr)
568
                    target = localPlayer;
569
            }
570
            actorManager->heal(target);
571
        }
572
573
        if (Game::instance() != nullptr)
574
            Game::instance()->setValidSpeed();
575
        return true;
576
    }
577
    return false;
578
}
579
#else  // TMWA_SUPPORT
580
581
impHandler0(heal)
582
{
583
    return false;
584
}
585
#endif  // TMWA_SUPPORT
586
587
impHandler0(healmd)
588
{
589
#ifdef TMWA_SUPPORT
590
    if (Net::getNetworkType() != ServerType::TMWATHENA)
591
        return false;
592
    if (actorManager != nullptr)
593
    {
594
        const int matk = PlayerInfo::getStatEffective(Attributes::PLAYER_MATK);
595
        int maxHealingRadius;
596
597
        // magic levels < 2
598
        if (PlayerInfo::getSkillLevel(340) < 2
599
            || PlayerInfo::getSkillLevel(341) < 2)
600
        {
601
            maxHealingRadius = matk / 100 + 1;
602
        }
603
        else
604
        {
605
            maxHealingRadius = (12 * fastSqrtInt(matk) + matk) / 100 + 1;
606
        }
607
608
        Being *target = actorManager->findMostDamagedPlayer(maxHealingRadius);
609
        if (target != nullptr)
610
            actorManager->heal(target);
611
612
        if (Game::instance() != nullptr)
613
            Game::instance()->setValidSpeed();
614
        return true;
615
    }
616
#endif  // TMWA_SUPPORT
617
618
    return false;
619
}
620
621
impHandler0(itenplz)
622
{
623
#ifdef TMWA_SUPPORT
624
    if (Net::getNetworkType() != ServerType::TMWATHENA)
625
        return false;
626
    if (actorManager != nullptr)
627
    {
628
        if (playerHandler != nullptr &&
629
            playerHandler->canUseMagic() &&
630
            PlayerInfo::getAttribute(Attributes::PLAYER_MP) >= 3)
631
        {
632
            actorManager->itenplz();
633
        }
634
        return true;
635
    }
636
#endif  // TMWA_SUPPORT
637
638
    return false;
639
}
640
641
impHandler0(setHome)
642
{
643
    if (localPlayer != nullptr)
644
    {
645
        localPlayer->setHome();
646
        return true;
647
    }
648
    return false;
649
}
650
651
impHandler0(magicAttack)
652
{
653
#ifdef TMWA_SUPPORT
654
    if (Net::getNetworkType() != ServerType::TMWATHENA)
655
        return false;
656
    if (localPlayer != nullptr)
657
    {
658
        localPlayer->magicAttack();
659
        return true;
660
    }
661
#endif  // TMWA_SUPPORT
662
663
    return false;
664
}
665
666
impHandler0(copyEquippedToOutfit)
667
{
668
    if (outfitWindow != nullptr)
669
    {
670
        outfitWindow->copyFromEquiped();
671
        return true;
672
    }
673
    return false;
674
}
675
676
impHandler(pickup)
677
{
678
    if (localPlayer == nullptr)
679
        return false;
680
681
    const std::string args = event.args;
682
    if (args.empty())
683
    {
684
        localPlayer->pickUpItems(0);
685
    }
686
    else
687
    {
688
        FloorItem *const item = actorManager->findItem(fromInt(
689
            atoi(args.c_str()), BeingId));
690
        if (item != nullptr)
691
            localPlayer->pickUp(item);
692
    }
693
    return true;
694
}
695
696
static void doSit()
697
{
698
    if (inputManager.isActionActive(InputAction::EMOTE))
699
        localPlayer->updateSit();
700
    else
701
        localPlayer->toggleSit();
702
}
703
704
impHandler0(sit)
705
{
706
    if (localPlayer != nullptr)
707
    {
708
        doSit();
709
        return true;
710
    }
711
    return false;
712
}
713
714
impHandler(screenshot)
715
{
716
    Game::createScreenshot(event.args);
717
    return true;
718
}
719
720
impHandler0(ignoreInput)
721
{
722
    return true;
723
}
724
725
impHandler(buy)
726
{
727
    if (serverFeatures == nullptr)
728
        return false;
729
    const std::string args = event.args;
730
    Being *being = findBeing(args, false);
731
    if ((being == nullptr) && Net::getNetworkType() == ServerType::TMWATHENA)
732
    {
733
        if (whoIsOnline != nullptr)
734
        {
735
            const std::set<std::string> &players =
736
                whoIsOnline->getOnlineNicks();
737
            if (players.find(args) != players.end())
738
            {
739
                if (buySellHandler != nullptr)
740
                    buySellHandler->requestSellList(args);
741
                return true;
742
            }
743
        }
744
        return false;
745
    }
746
747
    if (being == nullptr)
748
        being = findBeing(args, true);
749
750
    if (being == nullptr)
751
        return false;
752
753
    if (being->getType() == ActorType::Npc)
754
    {
755
        if (npcHandler != nullptr)
756
            npcHandler->buy(being);
757
        return true;
758
    }
759
    else if (being->getType() == ActorType::Player)
760
    {
761
        if (vendingHandler != nullptr &&
762
            Net::getNetworkType() != ServerType::TMWATHENA)
763
        {
764
            vendingHandler->open(being);
765
        }
766
        else if (buySellHandler != nullptr)
767
        {
768
            buySellHandler->requestSellList(being->getName());
769
        }
770
        return true;
771
    }
772
    return false;
773
}
774
775
impHandler(sell)
776
{
777
    if (serverFeatures == nullptr)
778
        return false;
779
780
    const std::string args = event.args;
781
    Being *being = findBeing(args, false);
782
    if (being == nullptr &&
783
        Net::getNetworkType() == ServerType::TMWATHENA)
784
    {
785
        if (whoIsOnline != nullptr)
786
        {
787
            const std::set<std::string> &players =
788
                whoIsOnline->getOnlineNicks();
789
            if (players.find(args) != players.end())
790
            {
791
                if (buySellHandler != nullptr)
792
                    buySellHandler->requestBuyList(args);
793
                return true;
794
            }
795
        }
796
        return false;
797
    }
798
799
    if (being == nullptr)
800
        being = findBeing(args, true);
801
802
    if (being == nullptr)
803
        return false;
804
805
    if (being->getType() == ActorType::Npc)
806
    {
807
        if (npcHandler != nullptr)
808
            npcHandler->sell(being->getId());
809
        return true;
810
    }
811
    else if (being->getType() == ActorType::Player)
812
    {
813
        if ((buyingStoreHandler != nullptr) &&
814
            Net::getNetworkType() != ServerType::TMWATHENA)
815
        {
816
            buyingStoreHandler->open(being);
817
        }
818
        else if (buySellHandler != nullptr)
819
        {
820
            buySellHandler->requestBuyList(being->getName());
821
        }
822
        return true;
823
    }
824
    return false;
825
}
826
827
impHandler(talk)
828
{
829
    const std::string args = event.args;
830
    Being *being = nullptr;
831
832
    if (!args.empty() && args[0] == ':')
833
    {
834
        being = actorManager->findBeing(fromInt(atoi(
835
            args.substr(1).c_str()), BeingId));
836
    }
837
    else
838
    {
839
        being = findBeing(args, true);
840
    }
841
842
    if (being == nullptr)
843
        return false;
844
845
    if (being->canTalk())
846
    {
847
        being->talkTo();
848
    }
849
    else if (being->getType() == ActorType::Player)
850
    {
851
        CREATEWIDGET(BuySellDialog,
852
            being->getName());
853
    }
854
    return true;
855
}
856
857
impHandler0(stopAttack)
858
{
859
    if (localPlayer != nullptr)
860
    {
861
        localPlayer->stopAttack(false);
862
        // not consume if target attack key pressed
863
        if (inputManager.isActionActive(InputAction::TARGET_ATTACK))
864
            return false;
865
        return true;
866
    }
867
    return false;
868
}
869
870
impHandler0(untarget)
871
{
872
    if (localPlayer != nullptr)
873
    {
874
        localPlayer->untarget();
875
        return true;
876
    }
877
    return false;
878
}
879
880
impHandler(attack)
881
{
882
    if ((localPlayer == nullptr) || (actorManager == nullptr))
883
        return false;
884
885
    Being *target = nullptr;
886
    std::string args = event.args;
887
    if (!args.empty())
888
    {
889
        if (args[0] != ':')
890
        {
891
            target = actorManager->findNearestByName(args,
892
                ActorType::Unknown);
893
        }
894
        else
895
        {
896
            target = actorManager->findBeing(fromInt(atoi(
897
                args.substr(1).c_str()), BeingId));
898
            if (target != nullptr &&
899
                target->getType() != ActorType::Monster)
900
            {
901
                target = nullptr;
902
            }
903
        }
904
    }
905
    if (target == nullptr)
906
        target = localPlayer->getTarget();
907
    else
908
        localPlayer->setTarget(target);
909
    if (target != nullptr)
910
        localPlayer->attack(target, true, false);
911
    return true;
912
}
913
914
impHandler(targetAttack)
915
{
916
    if ((localPlayer != nullptr) && (actorManager != nullptr))
917
    {
918
        Being *target = nullptr;
919
        std::string args = event.args;
920
        const bool newTarget = !inputManager.isActionActive(
921
            InputAction::STOP_ATTACK);
922
923
        if (!args.empty())
924
        {
925
            if (args[0] != ':')
926
            {
927
                target = actorManager->findNearestByName(args,
928
                    ActorType::Unknown);
929
            }
930
            else
931
            {
932
                target = actorManager->findBeing(fromInt(atoi(
933
                    args.substr(1).c_str()), BeingId));
934
                if (target != nullptr &&
935
                    target->getType() != ActorType::Monster)
936
                {
937
                    target = nullptr;
938
                }
939
            }
940
        }
941
942
        if ((target == nullptr) && (settings.targetingType == 0U))
943
            target = localPlayer->getTarget();
944
945
        if (target == nullptr)
946
        {
947
            target = actorManager->findNearestLivingBeing(
948
                localPlayer, 90, ActorType::Monster, AllowSort_true);
949
        }
950
951
        localPlayer->attack2(target, newTarget, false);
952
        return true;
953
    }
954
    return false;
955
}
956
957
impHandler0(attackHuman)
958
{
959
    if ((actorManager == nullptr) || (localPlayer == nullptr))
960
        return false;
961
962
    Being *const target = actorManager->findNearestPvpPlayer();
963
    if (target != nullptr)
964
    {
965
        localPlayer->setTarget(target);
966
        localPlayer->attack2(target, true, false);
967
    }
968
    return true;
969
}
970
971
impHandler0(safeVideoMode)
972
{
973
    WindowManager::setFullScreen(false);
974
975
    return true;
976
}
977
978
impHandler0(stopSit)
979
{
980
    if (localPlayer != nullptr)
981
    {
982
        localPlayer->stopAttack(false);
983
        // not consume if target attack key pressed
984
        if (inputManager.isActionActive(InputAction::TARGET_ATTACK))
985
            return false;
986
        if (localPlayer->getTarget() == nullptr)
987
        {
988
            doSit();
989
            return true;
990
        }
991
        return true;
992
    }
993
    return false;
994
}
995
996
impHandler0(showKeyboard)
997
{
998
#if defined(ANDROID) || defined(__SWITCH__)
999
#ifdef USE_SDL2
1000
    if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE)
1001
        SDL_StopTextInput();
1002
    else
1003
        SDL_StartTextInput();
1004
#else  // USE_SDL2
1005
1006
    SDL_ANDROID_ToggleScreenKeyboardTextInput(nullptr);
1007
#endif  // USE_SDL2
1008
1009
    return true;
1010
#else  // ANDROID
1011
1012
    return false;
1013
#endif  // ANDROID
1014
}
1015
1016
impHandler0(showWindows)
1017
{
1018
    if (popupMenu != nullptr)
1019
    {
1020
        popupMenu->showWindowsPopup();
1021
        return true;
1022
    }
1023
    return false;
1024
}
1025
1026
impHandler0(openTrade)
1027
{
1028
    const Being *const being = localPlayer->getTarget();
1029
    if ((being != nullptr) && being->getType() == ActorType::Player)
1030
    {
1031
        if (tradeHandler != nullptr)
1032
            tradeHandler->request(being);
1033
        tradePartnerName = being->getName();
1034
        if (tradeWindow != nullptr)
1035
            tradeWindow->clear();
1036
        return true;
1037
    }
1038
    return false;
1039
}
1040
1041
impHandler0(ipcToggle)
1042
{
1043
    if (ipc != nullptr)
1044
    {
1045
        IPC::stop();
1046
        if (ipc == nullptr)
1047
        {
1048
            debugChatTab->chatLog("IPC service stopped.",
1049
                ChatMsgType::BY_SERVER,
1050
                IgnoreRecord_false,
1051
                TryRemoveColors_true);
1052
        }
1053
        else
1054
        {
1055
            debugChatTab->chatLog("Unable to stop IPC service.",
1056
                ChatMsgType::BY_SERVER,
1057
                IgnoreRecord_false,
1058
                TryRemoveColors_true);
1059
        }
1060
    }
1061
    else
1062
    {
1063
        IPC::start();
1064
        if (ipc != nullptr)
1065
        {
1066
            debugChatTab->chatLog(
1067
                strprintf("IPC service available on port %d", ipc->getPort()),
1068
                ChatMsgType::BY_SERVER,
1069
                IgnoreRecord_false,
1070
                TryRemoveColors_true);
1071
        }
1072
        else
1073
        {
1074
            debugChatTab->chatLog("Unable to start IPC service",
1075
                ChatMsgType::BY_SERVER,
1076
                IgnoreRecord_false,
1077
                TryRemoveColors_true);
1078
        }
1079
    }
1080
    return true;
1081
}
1082
1083
impHandler(where)
1084
{
1085
    ChatTab *const tab = event.tab != nullptr ? event.tab : debugChatTab;
1086
    if (tab == nullptr)
1087
        return false;
1088
    std::ostringstream where;
1089
    where << Game::instance()->getCurrentMapName() << ", coordinates: "
1090
        << ((localPlayer->getPixelX() - mapTileSize / 2) / mapTileSize)
1091
        << ", " << ((localPlayer->getPixelY() - mapTileSize) / mapTileSize);
1092
    tab->chatLog(where.str(),
1093
        ChatMsgType::BY_SERVER,
1094
        IgnoreRecord_false,
1095
        TryRemoveColors_true);
1096
    return true;
1097
}
1098
1099
impHandler0(who)
1100
{
1101
    if (chatHandler != nullptr)
1102
        chatHandler->who();
1103
    return true;
1104
}
1105
1106
impHandler0(cleanGraphics)
1107
{
1108
    ResourceManager::clearCache();
1109
1110
    if (debugChatTab != nullptr)
1111
    {
1112
        // TRANSLATORS: clear graphics command message
1113
        debugChatTab->chatLog(_("Cache cleared"),
1114
            ChatMsgType::BY_SERVER,
1115
            IgnoreRecord_false,
1116
            TryRemoveColors_true);
1117
    }
1118
    return true;
1119
}
1120
1121
impHandler0(cleanFonts)
1122
{
1123
    if (gui != nullptr)
1124
        gui->clearFonts();
1125
    if (debugChatTab != nullptr)
1126
    {
1127
        // TRANSLATORS: clear fonts cache message
1128
        debugChatTab->chatLog(_("Cache cleared"),
1129
            ChatMsgType::BY_SERVER,
1130
            IgnoreRecord_false,
1131
            TryRemoveColors_true);
1132
    }
1133
    return true;
1134
}
1135
1136
impHandler(trade)
1137
{
1138
    if (actorManager == nullptr)
1139
        return false;
1140
1141
    const Being *being = actorManager->findBeingByName(
1142
        event.args, ActorType::Player);
1143
    if (being == nullptr)
1144
        being = localPlayer->getTarget();
1145
    if (being != nullptr)
1146
    {
1147
        if (tradeHandler != nullptr)
1148
            tradeHandler->request(being);
1149
        tradePartnerName = being->getName();
1150
        if (tradeWindow != nullptr)
1151
            tradeWindow->clear();
1152
    }
1153
    return true;
1154
}
1155
1156
impHandler0(priceLoad)
1157
{
1158
    if (shopWindow != nullptr)
1159
    {
1160
        shopWindow->loadList();
1161
        return true;
1162
    }
1163
    return false;
1164
}
1165
1166
impHandler0(priceSave)
1167
{
1168
    if (shopWindow != nullptr)
1169
    {
1170
        shopWindow->saveList();
1171
        return true;
1172
    }
1173
    return false;
1174
}
1175
1176
impHandler0(cacheInfo)
1177
{
1178
    if ((chatWindow == nullptr) || (debugChatTab == nullptr))
1179
        return false;
1180
1181
/*
1182
    Font *const font = chatWindow->getFont();
1183
    if (!font)
1184
        return;
1185
1186
    const TextChunkList *const cache = font->getCache();
1187
    if (!cache)
1188
        return;
1189
1190
    unsigned int all = 0;
1191
    // TRANSLATORS: chat fonts message
1192
    debugChatTab->chatLog(_("font cache size"),
1193
        ChatMsgType::BY_SERVER,
1194
        IgnoreRecord_false,
1195
        TryRemoveColors_true);
1196
    std::string str;
1197
    for (int f = 0; f < 256; f ++)
1198
    {
1199
        if (!cache[f].size)
1200
        {
1201
            const unsigned int sz = CAST_S32(cache[f].size);
1202
            all += sz;
1203
            str.append(strprintf("%d: %u, ", f, sz));
1204
        }
1205
    }
1206
    debugChatTab->chatLog(str,
1207
        ChatMsgType::BY_SERVER,
1208
        IgnoreRecord_false,
1209
        TryRemoveColors_true);
1210
    // TRANSLATORS: chat fonts message
1211
    debugChatTab->chatLog(strprintf("%s %d", _("Cache size:"), all),
1212
        ChatMsgType::BY_SERVER,
1213
        IgnoreRecord_false,
1214
        TryRemoveColors_true);
1215
#ifdef DEBUG_FONT_COUNTERS
1216
    debugChatTab->chatLog("",
1217
        ChatMsgType::BY_SERVER,
1218
        IgnoreRecord_false,
1219
        TryRemoveColors_true);
1220
    debugChatTab->chatLog(strprintf("%s %d",
1221
        // TRANSLATORS: chat fonts message
1222
        _("Created:"), font->getCreateCounter()),
1223
        ChatMsgType::BY_SERVER,
1224
        IgnoreRecord_false,
1225
        TryRemoveColors_true);
1226
    debugChatTab->chatLog(strprintf("%s %d",
1227
        // TRANSLATORS: chat fonts message
1228
        _("Deleted:"), font->getDeleteCounter()),
1229
        ChatMsgType::BY_SERVER,
1230
        IgnoreRecord_false,
1231
        TryRemoveColors_true);
1232
#endif
1233
*/
1234
    return true;
1235
}
1236
1237
impHandler0(disconnect)
1238
{
1239
    if (gameHandler != nullptr)
1240
        gameHandler->disconnect2();
1241
    return true;
1242
}
1243
1244
impHandler(undress)
1245
{
1246
    if ((actorManager == nullptr) || (localPlayer == nullptr))
1247
        return false;
1248
1249
    const std::string args = event.args;
1250
    StringVect pars;
1251
    if (!splitParameters(pars, args, " ,", '\"'))
1252
        return false;
1253
    Being *target = nullptr;
1254
    const size_t sz = pars.size();
1255
    if (sz == 0)
1256
    {
1257
        target = localPlayer->getTarget();
1258
    }
1259
    else
1260
    {
1261
        if (pars[0][0] == ':')
1262
        {
1263
            target = actorManager->findBeing(fromInt(atoi(
1264
                pars[0].substr(1).c_str()), BeingId));
1265
            if ((target != nullptr) && target->getType() == ActorType::Monster)
1266
                target = nullptr;
1267
        }
1268
        else
1269
        {
1270
            target = actorManager->findNearestByName(args,
1271
                ActorType::Unknown);
1272
        }
1273
    }
1274
1275
    if (sz == 2)
1276
    {
1277
        if (target != nullptr)
1278
        {
1279
            const int itemId = atoi(pars[1].c_str());
1280
            target->undressItemById(itemId);
1281
        }
1282
    }
1283
    else
1284
    {
1285
        if ((target != nullptr) && (beingHandler != nullptr))
1286
            beingHandler->undress(target);
1287
    }
1288
1289
    return true;
1290
}
1291
1292
impHandler0(dirs)
1293
{
1294
    if (debugChatTab == nullptr)
1295
        return false;
1296
1297
    debugChatTab->chatLog("config directory: "
1298
        + settings.configDir,
1299
        ChatMsgType::BY_SERVER,
1300
        IgnoreRecord_false,
1301
        TryRemoveColors_true);
1302
    debugChatTab->chatLog("logs directory: "
1303
        + settings.localDataDir,
1304
        ChatMsgType::BY_SERVER,
1305
        IgnoreRecord_false,
1306
        TryRemoveColors_true);
1307
    debugChatTab->chatLog("screenshots directory: "
1308
        + settings.screenshotDir,
1309
        ChatMsgType::BY_SERVER,
1310
        IgnoreRecord_false,
1311
        TryRemoveColors_true);
1312
    debugChatTab->chatLog("temp directory: "
1313
        + settings.tempDir,
1314
        ChatMsgType::BY_SERVER,
1315
        IgnoreRecord_false,
1316
        TryRemoveColors_true);
1317
    return true;
1318
}
1319
1320
impHandler0(uptime)
1321
{
1322
    if (debugChatTab == nullptr)
1323
        return false;
1324
1325
    if (cur_time < start_time)
1326
    {
1327
        // TRANSLATORS: uptime command
1328
        debugChatTab->chatLog(strprintf(_("Client uptime: %s"), "unknown"),
1329
            ChatMsgType::BY_SERVER,
1330
            IgnoreRecord_false,
1331
            TryRemoveColors_true);
1332
    }
1333
    else
1334
    {
1335
        // TRANSLATORS: uptime command
1336
        debugChatTab->chatLog(strprintf(_("Client uptime: %s"),
1337
            timeDiffToString(CAST_S32(cur_time - start_time)).c_str()),
1338
            ChatMsgType::BY_SERVER,
1339
            IgnoreRecord_false,
1340
            TryRemoveColors_true);
1341
    }
1342
    return true;
1343
}
1344
1345
#ifdef DEBUG_DUMP_LEAKS1
1346
static void showRes(std::string str, ResourceManager::Resources *res)
1347
{
1348
    if (!res)
1349
        return;
1350
1351
    str.append(toString(res->size()));
1352
    if (debugChatTab)
1353
    {
1354
        debugChatTab->chatLog(str,
1355
            ChatMsgType::BY_SERVER,
1356
            IgnoreRecord_false,
1357
            TryRemoveColors_true);
1358
    }
1359
    logger->log(str);
1360
    ResourceManager::ResourceIterator iter = res->begin();
1361
    const ResourceManager::ResourceIterator iter_end = res->end();
1362
    while (iter != iter_end)
1363
    {
1364
        if (iter->second && iter->second->mRefCount)
1365
        {
1366
            char type = ' ';
1367
            char isNew = 'N';
1368
            if (iter->second->getDumped())
1369
                isNew = 'O';
1370
            else
1371
                iter->second->setDumped(true);
1372
1373
            SubImage *const subImage = dynamic_cast<SubImage *>(
1374
                iter->second);
1375
            Image *const image = dynamic_cast<Image *>(iter->second);
1376
            int id = 0;
1377
            if (subImage)
1378
                type = 'S';
1379
            else if (image)
1380
                type = 'I';
1381
            if (image)
1382
                id = image->getGLImage();
1383
            logger->log("Resource %c%c: %s (%d) id=%d", type,
1384
                isNew, iter->second->getIdPath().c_str(),
1385
                iter->second->mRefCount, id);
1386
        }
1387
        ++ iter;
1388
    }
1389
}
1390
1391
impHandler(dump)
1392
{
1393
    if (!debugChatTab)
1394
        return false;
1395
1396
    if (!event.args.empty())
1397
    {
1398
        ResourceManager::Resources *res = ResourceManager::getResources();
1399
        // TRANSLATORS: dump command
1400
        showRes(_("Resource images:"), res);
1401
        res = ResourceManager::getOrphanedResources();
1402
        // TRANSLATORS: dump command
1403
        showRes(_("Orphaned resource images:"), res);
1404
    }
1405
    else
1406
    {
1407
        ResourceManager::Resources *res = ResourceManager::getResources();
1408
        // TRANSLATORS: dump command
1409
        debugChatTab->chatLog(_("Resource images:") + toString(res->size()),
1410
            ChatMsgType::BY_SERVER,
1411
            IgnoreRecord_false,
1412
            TryRemoveColors_true);
1413
        res = ResourceManager::getOrphanedResources();
1414
        // TRANSLATORS: dump command
1415
        debugChatTab->chatLog(_("Orphaned resource images:")
1416
            + toString(res->size()),
1417
            ChatMsgType::BY_SERVER,
1418
            IgnoreRecord_false,
1419
            TryRemoveColors_true);
1420
    }
1421
    return true;
1422
}
1423
1424
#elif defined ENABLE_MEM_DEBUG
1425
impHandler0(dump)
1426
{
1427
    nvwa::check_leaks();
1428
    return true;
1429
}
1430
#else  // DEBUG_DUMP_LEAKS1
1431
1432
impHandler0(dump)
1433
{
1434
    return true;
1435
}
1436
#endif  // DEBUG_DUMP_LEAKS1
1437
1438
impHandler0(serverIgnoreAll)
1439
{
1440
    if (chatHandler != nullptr)
1441
        chatHandler->ignoreAll();
1442
    return true;
1443
}
1444
1445
impHandler0(serverUnIgnoreAll)
1446
{
1447
    if (chatHandler != nullptr)
1448
        chatHandler->unIgnoreAll();
1449
    return true;
1450
}
1451
1452
PRAGMA6(GCC diagnostic push)
1453
PRAGMA6(GCC diagnostic ignored "-Wnull-dereference")
1454
impHandler0(error)
1455
{
1456
    int *const ptr = nullptr;
1457
    *(ptr + 1) = 20;
1458
//    logger->log("test %d", *ptr);
1459
    exit(1);
1460
}
1461
PRAGMA6(GCC diagnostic pop)
1462
1463
impHandler(dumpGraphics)
1464
{
1465
    std::string str = strprintf("%s,%s,%dX%dX%d,", PACKAGE_OS, SMALL_VERSION,
1466
        mainGraphics->getWidth(), mainGraphics->getHeight(),
1467
        mainGraphics->getBpp());
1468
1469
    if (mainGraphics->getFullScreen())
1470
        str.append("F");
1471
    else
1472
        str.append("W");
1473
    if (mainGraphics->getHWAccel())
1474
        str.append("H");
1475
    else
1476
        str.append("S");
1477
1478
    if (mainGraphics->getDoubleBuffer())
1479
        str.append("D");
1480
    else
1481
        str.append("_");
1482
1483
#if defined USE_OPENGL
1484
    str.append(strprintf(",%d", mainGraphics->getOpenGL()));
1485
#else  // defined USE_OPENGL
1486
1487
    str.append(",0");
1488
#endif  // defined USE_OPENGL
1489
1490
    str.append(strprintf(",%f,", static_cast<double>(settings.guiAlpha)))
1491
        .append(config.getBoolValue("adjustPerfomance") ? "1" : "0")
1492
        .append(config.getBoolValue("alphaCache") ? "1" : "0")
1493
        .append(config.getBoolValue("enableMapReduce") ? "1" : "0")
1494
        .append(config.getBoolValue("beingopacity") ? "1" : "0")
1495
        .append(",")
1496
        .append(config.getBoolValue("enableAlphaFix") ? "1" : "0")
1497
        .append(config.getBoolValue("disableAdvBeingCaching") ? "1" : "0")
1498
        .append(config.getBoolValue("disableBeingCaching") ? "1" : "0")
1499
        .append(config.getBoolValue("particleeffects") ? "1" : "0")
1500
        .append(strprintf(",%d-%d", fps, config.getIntValue("fpslimit")));
1501
    outStringNormal(event.tab, str, str);
1502
    return true;
1503
}
1504
1505
impHandler0(dumpEnvironment)
1506
{
1507
    logger->log1("Start environment variables");
1508
    for (char **env = environ; *env != nullptr; ++ env)
1509
        logger->log1(*env);
1510
    logger->log1("End environment variables");
1511
    if (debugChatTab != nullptr)
1512
    {
1513
        // TRANSLATORS: dump environment command
1514
        debugChatTab->chatLog(_("Environment variables dumped"),
1515
            ChatMsgType::BY_SERVER,
1516
            IgnoreRecord_false,
1517
            TryRemoveColors_true);
1518
    }
1519
    return true;
1520
}
1521
1522
impHandler(dumpTests)
1523
{
1524
    const std::string str = config.getStringValue("testInfo");
1525
    outStringNormal(event.tab, str, str);
1526
    return true;
1527
}
1528
1529
impHandler0(dumpOGL)
1530
{
1531
#ifdef USE_OPENGL
1532
#if !defined(ANDROID) && !defined(__native_client__) && !defined(__SWITCH__)
1533
    NormalOpenGLGraphics::dumpSettings();
1534
#endif  // !defined(ANDROID) && !defined(__native_client__) &&
1535
        // !defined(__SWITCH__)
1536
#endif  // USE_OPENGL
1537
1538
    return true;
1539
}
1540
1541
#ifdef USE_OPENGL
1542
impHandler(dumpGL)
1543
{
1544
    std::string str = graphicsManager.getGLVersion();
1545
    outStringNormal(event.tab, str, str);
1546
    return true;
1547
}
1548
#else  // USE_OPENGL
1549
1550
impHandler0(dumpGL)
1551
{
1552
    return true;
1553
}
1554
#endif  // USE_OPENGL
1555
1556
impHandler(dumpMods)
1557
{
1558
    std::string str = "enabled mods: " + serverConfig.getValue("mods", "");
1559
    outStringNormal(event.tab, str, str);
1560
    return true;
1561
}
1562
1563
#if defined USE_OPENGL && defined DEBUG_SDLFONT
1564
impHandler0(testSdlFont)
1565
{
1566
    Font *font = new Font("fonts/dejavusans.ttf", 18, TTF_STYLE_NORMAL);
1567
    timespec time1;
1568
    timespec time2;
1569
    NullOpenGLGraphics *nullGraphics = new NullOpenGLGraphics;
1570
    STD_VECTOR<std::string> data;
1571
    volatile int width = 0;
1572
1573
    for (int f = 0; f < 300; f ++)
1574
        data.push_back("test " + toString(f) + "string");
1575
    nullGraphics->beginDraw();
1576
1577
    clock_gettime(CLOCK_MONOTONIC, &time1);
1578
    Color color(0, 0, 0, 255);
1579
1580
    for (int f = 0; f < 500; f ++)
1581
    {
1582
        FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, data)
1583
        {
1584
            width += font->getWidth(*it);
1585
            font->drawString(nullGraphics, color, color, *it, 10, 10);
1586
        }
1587
        FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, data)
1588
            font->drawString(nullGraphics, color, color, *it, 10, 10);
1589
1590
        font->doClean();
1591
    }
1592
1593
    clock_gettime(CLOCK_MONOTONIC, &time2);
1594
1595
    delete nullGraphics;
1596
    delete font;
1597
1598
    int64_t diff = (static_cast<long long int>(
1599
        time2.tv_sec) * 1000000000LL + static_cast<long long int>(
1600
        time2.tv_nsec)) / 100000 - (static_cast<long long int>(
1601
        time1.tv_sec) * 1000000000LL + static_cast<long long int>(
1602
        time1.tv_nsec)) / 100000;
1603
    if (debugChatTab)
1604
    {
1605
        debugChatTab->chatLog("sdlfont time: " + toString(diff),
1606
            ChatMsgType::BY_SERVER,
1607
            IgnoreRecord_false,
1608
            TryRemoveColors_true);
1609
    }
1610
    return true;
1611
}
1612
#endif  // defined USE_OPENGL && defined DEBUG_SDLFONT
1613
1614
impHandler0(createItems)
1615
{
1616
    BuyDialog *const dialog = CREATEWIDGETR0(BuyDialog);
1617
    const ItemDB::ItemInfos &items = ItemDB::getItemInfos();
1618
    FOR_EACH (ItemDB::ItemInfos::const_iterator, it, items)
1619
    {
1620
        const ItemInfo *const info = (*it).second;
1621
        if (info == nullptr)
1622
            continue;
1623
        const int id = info->getId();
1624
        if (id <= 500)
1625
            continue;
1626
1627
        dialog->addItem(id,
1628
            ItemType::Unknown,
1629
            ItemColor_one,
1630
            100,
1631
            0);
1632
    }
1633
    dialog->sort();
1634
    return true;
1635
}
1636
1637
impHandler(createItem)
1638
{
1639
    int id = 0;
1640
    int amount = 0;
1641
1642
    if (adminHandler == nullptr)
1643
        return false;
1644
1645
    if (parse2Int(event.args, id, amount))
1646
        adminHandler->createItems(id, ItemColor_one, amount);
1647
    else
1648
        adminHandler->createItems(atoi(event.args.c_str()), ItemColor_one, 1);
1649
    return true;
1650
}
1651
1652
impHandler(uploadConfig)
1653
{
1654
    // TRANSLATORS: upload config chat message
1655
    uploadFile(_("Config uploaded to:"),
1656
        config.getFileName(),
1657
        "?xml",
1658
        event.tab);
1659
    return true;
1660
}
1661
1662
impHandler(uploadServerConfig)
1663
{
1664
    // TRANSLATORS: upload config chat message
1665
    uploadFile(_("Server config Uploaded to:"),
1666
        serverConfig.getFileName(),
1667
        "?xml",
1668
        event.tab);
1669
    return true;
1670
}
1671
1672
impHandler(uploadLog)
1673
{
1674
    // TRANSLATORS: upload log chat message
1675
    uploadFile(_("Log uploaded to:"),
1676
        settings.logFileName,
1677
        "",
1678
        event.tab);
1679
    return true;
1680
}
1681
1682
impHandler0(mercenaryFire)
1683
{
1684
    if (mercenaryHandler != nullptr)
1685
        mercenaryHandler->fire();
1686
    return true;
1687
}
1688
1689
impHandler0(mercenaryToMaster)
1690
{
1691
    if (mercenaryHandler != nullptr)
1692
        mercenaryHandler->moveToMaster();
1693
    return true;
1694
}
1695
1696
impHandler0(homunculusToMaster)
1697
{
1698
    if (homunculusHandler != nullptr)
1699
        homunculusHandler->moveToMaster();
1700
    return true;
1701
}
1702
1703
impHandler0(homunculusFeed)
1704
{
1705
    if (homunculusHandler != nullptr)
1706
        homunculusHandler->feed();
1707
    return true;
1708
}
1709
1710
impHandler(useItem)
1711
{
1712
    StringVect pars;
1713
    if (!splitParameters(pars, event.args, " ,", '\"'))
1714
        return false;
1715
    const int sz = CAST_S32(pars.size());
1716
    if (sz < 1)
1717
        return false;
1718
1719
    const int itemId = atoi(pars[0].c_str());
1720
1721
    if (itemId < SPELL_MIN_ID)
1722
    {
1723
        const Inventory *const inv = PlayerInfo::getInventory();
1724
        if (inv != nullptr)
1725
        {
1726
            ItemColor color = ItemColor_one;
1727
            int16_t useType = 0;
1728
            StringVect pars2;
1729
            if (!splitParameters(pars2, pars[0], " ,", '\"'))
1730
                return false;
1731
            const int sz2 = CAST_S32(pars2.size());
1732
            if (sz2 < 1)
1733
                return false;
1734
            if (sz2 >= 2)
1735
                color = fromInt(atoi(pars2[1].c_str()), ItemColor);
1736
            if (sz >= 2)
1737
                useType = CAST_S16(atoi(pars[1].c_str()));
1738
            const Item *const item = inv->findItem(itemId,
1739
                color);
1740
            PlayerInfo::useEquipItem(item, useType, Sfx_true);
1741
        }
1742
    }
1743
    else if (itemId < SKILL_MIN_ID && (spellManager != nullptr))
1744
    {
1745
        spellManager->useItem(itemId);
1746
    }
1747
    else if (skillDialog != nullptr)
1748
    {
1749
        // +++ probably need get data parameter from args
1750
        skillDialog->useItem(itemId,
1751
            fromBool(config.getBoolValue("skillAutotarget"), AutoTarget),
1752
            0,
1753
            std::string());
1754
    }
1755
    return true;
1756
}
1757
1758
impHandler(useItemInv)
1759
{
1760
    int param1 = 0;
1761
    int param2 = 0;
1762
    const std::string args = event.args;
1763
    if (parse2Int(args, param1, param2))
1764
    {
1765
        Item *const item = getItemByInvIndex(param1,
1766
            InventoryType::Inventory);
1767
        PlayerInfo::useEquipItem(item, CAST_S16(param2), Sfx_true);
1768
    }
1769
    else
1770
    {
1771
        Item *const item = getItemByInvIndex(atoi(event.args.c_str()),
1772
            InventoryType::Inventory);
1773
        PlayerInfo::useEquipItem(item, 0, Sfx_true);
1774
    }
1775
    return true;
1776
}
1777
1778
impHandler(invToStorage)
1779
{
1780
    Item *item = nullptr;
1781
    const int amount = getAmountFromEvent(event, item,
1782
        InventoryType::Inventory);
1783
    if (item == nullptr)
1784
        return true;
1785
    if (amount != 0)
1786
    {
1787
        if (inventoryHandler != nullptr)
1788
        {
1789
            inventoryHandler->moveItem2(InventoryType::Inventory,
1790
                item->getInvIndex(),
1791
                amount,
1792
                InventoryType::Storage);
1793
        }
1794
    }
1795
    else
1796
    {
1797
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::StoreAdd,
1798
            inventoryWindow,
1799
            item,
1800
            0,
1801
            0);
1802
    }
1803
    return true;
1804
}
1805
1806
impHandler(tradeAdd)
1807
{
1808
    Item *item = nullptr;
1809
    const int amount = getAmountFromEvent(event, item,
1810
        InventoryType::Inventory);
1811
    if ((item == nullptr) || PlayerInfo::isItemProtected(item->getId()))
1812
        return true;
1813
1814
    if (amount != 0)
1815
    {
1816
        if (tradeWindow != nullptr)
1817
            tradeWindow->tradeItem(item, amount, true);
1818
    }
1819
    else
1820
    {
1821
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::TradeAdd,
1822
            tradeWindow,
1823
            item,
1824
            0,
1825
            0);
1826
    }
1827
    return true;
1828
}
1829
1830
impHandler(storageToInv)
1831
{
1832
    Item *item = nullptr;
1833
    const int amount = getAmountFromEvent(event, item, InventoryType::Storage);
1834
    if (amount != 0)
1835
    {
1836
        if ((inventoryHandler != nullptr) && (item != nullptr))
1837
        {
1838
            inventoryHandler->moveItem2(InventoryType::Storage,
1839
                item->getInvIndex(),
1840
                amount,
1841
                InventoryType::Inventory);
1842
        }
1843
    }
1844
    else
1845
    {
1846
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::StoreRemove,
1847
            storageWindow,
1848
            item,
1849
            0,
1850
            0);
1851
    }
1852
    return true;
1853
}
1854
1855
impHandler(protectItem)
1856
{
1857
    const int id = atoi(event.args.c_str());
1858
    if (id > 0)
1859
        PlayerInfo::protectItem(id);
1860
    return true;
1861
}
1862
1863
impHandler(unprotectItem)
1864
{
1865
    const int id = atoi(event.args.c_str());
1866
    if (id > 0)
1867
        PlayerInfo::unprotectItem(id);
1868
    return true;
1869
}
1870
1871
impHandler(kick)
1872
{
1873
    if ((localPlayer == nullptr) || (actorManager == nullptr))
1874
        return false;
1875
1876
    Being *target = nullptr;
1877
    std::string args = event.args;
1878
    if (!args.empty())
1879
    {
1880
        if (args[0] != ':')
1881
        {
1882
            target = actorManager->findNearestByName(args,
1883
                ActorType::Unknown);
1884
        }
1885
        else
1886
        {
1887
            target = actorManager->findBeing(fromInt(atoi(
1888
                args.substr(1).c_str()), BeingId));
1889
        }
1890
    }
1891
    if (target == nullptr)
1892
        target = localPlayer->getTarget();
1893
    if ((target != nullptr) && (adminHandler != nullptr))
1894
        adminHandler->kick(target->getId());
1895
    return true;
1896
}
1897
1898
impHandler0(clearDrop)
1899
{
1900
    if (dropShortcut != nullptr)
1901
        dropShortcut->clear(true);
1902
    return true;
1903
}
1904
1905
impHandler0(testInfo)
1906
{
1907
    if (actorManager != nullptr)
1908
    {
1909
        logger->log("actors count: %d", CAST_S32(
1910
            actorManager->size()));
1911
        return true;
1912
    }
1913
    return false;
1914
}
1915
1916
impHandler(craftKey)
1917
{
1918
    const int slot = (event.action - InputAction::CRAFT_1);
1919
    if (slot >= 0 && slot < 9)
1920
    {
1921
        if (inventoryWindow != nullptr)
1922
            inventoryWindow->moveItemToCraft(slot);
1923
        return true;
1924
    }
1925
    return false;
1926
}
1927
1928
impHandler0(resetGameModifiers)
1929
{
1930
    GameModifiers::resetModifiers();
1931
    return true;
1932
}
1933
1934
impHandler(barToChat)
1935
{
1936
    if (chatWindow != nullptr)
1937
    {
1938
        chatWindow->addInputText(event.args,
1939
            true);
1940
        return true;
1941
    }
1942
    return false;
1943
}
1944
1945
impHandler(seen)
1946
{
1947
    if (actorManager == nullptr)
1948
        return false;
1949
1950
    ChatTab *tab = event.tab;
1951
    if (tab == nullptr)
1952
        tab = localChatTab;
1953
    if (tab == nullptr)
1954
        return false;
1955
1956
    if (config.getBoolValue("enableIdCollecting") == false)
1957
    {
1958
        // TRANSLATORS: last seen disabled warning
1959
        tab->chatLog(_("Last seen disabled. "
1960
            "Enable in players / collect players ID and seen log."),
1961
            ChatMsgType::BY_SERVER,
1962
            IgnoreRecord_false,
1963
            TryRemoveColors_true);
1964
        return true;
1965
    }
1966
1967
    const std::string name = event.args;
1968
    if (name.empty())
1969
        return false;
1970
1971
    std::string dir = settings.usersDir;
1972
    dir.append(stringToHexPath(name)).append("/seen.txt");
1973
    if (Files::existsLocal(dir))
1974
    {
1975
        StringVect lines;
1976
        Files::loadTextFileLocal(dir, lines);
1977
        if (lines.size() < 3)
1978
        {
1979
            // TRANSLATORS: last seen error
1980
            tab->chatLog(_("You have never seen this nick."),
1981
                ChatMsgType::BY_SERVER,
1982
                IgnoreRecord_false,
1983
                TryRemoveColors_true);
1984
            return true;
1985
        }
1986
        const std::string message = strprintf(
1987
            // TRANSLATORS: last seen message
1988
            _("Last seen for %s: %s"),
1989
            name.c_str(),
1990
            lines[2].c_str());
1991
        tab->chatLog(message,
1992
            ChatMsgType::BY_SERVER,
1993
            IgnoreRecord_false,
1994
            TryRemoveColors_true);
1995
    }
1996
    else
1997
    {
1998
        // TRANSLATORS: last seen error
1999
        tab->chatLog(_("You have not seen this nick before."),
2000
            ChatMsgType::BY_SERVER,
2001
            IgnoreRecord_false,
2002
            TryRemoveColors_true);
2003
    }
2004
2005
    return true;
2006
}
2007
2008
impHandler(dumpMemoryUsage)
2009
{
2010
    if (event.tab != nullptr)
2011
        MemoryManager::printAllMemory(event.tab);
2012
    else
2013
        MemoryManager::printAllMemory(localChatTab);
2014
    return true;
2015
}
2016
2017
impHandler(setEmoteType)
2018
{
2019
    const std::string &args = event.args;
2020
    if (args == "player" || args.empty())
2021
    {
2022
        settings.emoteType = EmoteType::Player;
2023
    }
2024
    else if (args == "pet")
2025
    {
2026
        settings.emoteType = EmoteType::Pet;
2027
    }
2028
    else if (args == "homun" || args == "homunculus")
2029
    {
2030
        settings.emoteType = EmoteType::Homunculus;
2031
    }
2032
    else if (args == "merc" || args == "mercenary")
2033
    {
2034
        settings.emoteType = EmoteType::Mercenary;
2035
    }
2036
    return true;
2037
}
2038
2039
2
}  // namespace Actions