GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/progs/manaplus/actions/actions.cpp Lines: 1 711 0.1 %
Date: 2017-11-29 Branches: 0 883 0.0 %

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