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