GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/progs/manaplus/actions/actions.cpp Lines: 1 725 0.1 %
Date: 2018-06-18 21:15:20 Branches: 0 909 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
    Being *being = findBeing(event.args, true);
829
    if (being == nullptr)
830
        return false;
831
832
    if (being->canTalk())
833
    {
834
        being->talkTo();
835
    }
836
    else if (being->getType() == ActorType::Player)
837
    {
838
        CREATEWIDGET(BuySellDialog,
839
            being->getName());
840
    }
841
    return true;
842
}
843
844
impHandler0(stopAttack)
845
{
846
    if (localPlayer != nullptr)
847
    {
848
        localPlayer->stopAttack(false);
849
        // not consume if target attack key pressed
850
        if (inputManager.isActionActive(InputAction::TARGET_ATTACK))
851
            return false;
852
        return true;
853
    }
854
    return false;
855
}
856
857
impHandler0(untarget)
858
{
859
    if (localPlayer != nullptr)
860
    {
861
        localPlayer->untarget();
862
        return true;
863
    }
864
    return false;
865
}
866
867
impHandler(attack)
868
{
869
    if ((localPlayer == nullptr) || (actorManager == nullptr))
870
        return false;
871
872
    Being *target = nullptr;
873
    std::string args = event.args;
874
    if (!args.empty())
875
    {
876
        if (args[0] != ':')
877
        {
878
            target = actorManager->findNearestByName(args,
879
                ActorType::Unknown);
880
        }
881
        else
882
        {
883
            target = actorManager->findBeing(fromInt(atoi(
884
                args.substr(1).c_str()), BeingId));
885
            if (target != nullptr &&
886
                target->getType() != ActorType::Monster)
887
            {
888
                target = nullptr;
889
            }
890
        }
891
    }
892
    if (target == nullptr)
893
        target = localPlayer->getTarget();
894
    else
895
        localPlayer->setTarget(target);
896
    if (target != nullptr)
897
        localPlayer->attack(target, true, false);
898
    return true;
899
}
900
901
impHandler(targetAttack)
902
{
903
    if ((localPlayer != nullptr) && (actorManager != nullptr))
904
    {
905
        Being *target = nullptr;
906
        std::string args = event.args;
907
        const bool newTarget = !inputManager.isActionActive(
908
            InputAction::STOP_ATTACK);
909
910
        if (!args.empty())
911
        {
912
            if (args[0] != ':')
913
            {
914
                target = actorManager->findNearestByName(args,
915
                    ActorType::Unknown);
916
            }
917
            else
918
            {
919
                target = actorManager->findBeing(fromInt(atoi(
920
                    args.substr(1).c_str()), BeingId));
921
                if (target != nullptr &&
922
                    target->getType() != ActorType::Monster)
923
                {
924
                    target = nullptr;
925
                }
926
            }
927
        }
928
929
        if ((target == nullptr) && (settings.targetingType == 0u))
930
            target = localPlayer->getTarget();
931
932
        if (target == nullptr)
933
        {
934
            target = actorManager->findNearestLivingBeing(
935
                localPlayer, 90, ActorType::Monster, AllowSort_true);
936
        }
937
938
        localPlayer->attack2(target, newTarget, false);
939
        return true;
940
    }
941
    return false;
942
}
943
944
impHandler0(attackHuman)
945
{
946
    if ((actorManager == nullptr) || (localPlayer == nullptr))
947
        return false;
948
949
    Being *const target = actorManager->findNearestPvpPlayer();
950
    if (target != nullptr)
951
    {
952
        localPlayer->setTarget(target);
953
        localPlayer->attack2(target, true, false);
954
    }
955
    return true;
956
}
957
958
impHandler0(safeVideoMode)
959
{
960
    WindowManager::setFullScreen(false);
961
962
    return true;
963
}
964
965
impHandler0(stopSit)
966
{
967
    if (localPlayer != nullptr)
968
    {
969
        localPlayer->stopAttack(false);
970
        // not consume if target attack key pressed
971
        if (inputManager.isActionActive(InputAction::TARGET_ATTACK))
972
            return false;
973
        if (localPlayer->getTarget() == nullptr)
974
        {
975
            doSit();
976
            return true;
977
        }
978
        return true;
979
    }
980
    return false;
981
}
982
983
impHandler0(showKeyboard)
984
{
985
#ifdef ANDROID
986
#ifdef USE_SDL2
987
    if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE)
988
        SDL_StopTextInput();
989
    else
990
        SDL_StartTextInput();
991
#else  // USE_SDL2
992
993
    SDL_ANDROID_ToggleScreenKeyboardTextInput(nullptr);
994
#endif  // USE_SDL2
995
996
    return true;
997
#else  // ANDROID
998
999
    return false;
1000
#endif  // ANDROID
1001
}
1002
1003
impHandler0(showWindows)
1004
{
1005
    if (popupMenu != nullptr)
1006
    {
1007
        popupMenu->showWindowsPopup();
1008
        return true;
1009
    }
1010
    return false;
1011
}
1012
1013
impHandler0(openTrade)
1014
{
1015
    const Being *const being = localPlayer->getTarget();
1016
    if ((being != nullptr) && being->getType() == ActorType::Player)
1017
    {
1018
        if (tradeHandler != nullptr)
1019
            tradeHandler->request(being);
1020
        tradePartnerName = being->getName();
1021
        if (tradeWindow != nullptr)
1022
            tradeWindow->clear();
1023
        return true;
1024
    }
1025
    return false;
1026
}
1027
1028
impHandler0(ipcToggle)
1029
{
1030
    if (ipc != nullptr)
1031
    {
1032
        IPC::stop();
1033
        if (ipc == nullptr)
1034
        {
1035
            debugChatTab->chatLog("IPC service stopped.",
1036
                ChatMsgType::BY_SERVER,
1037
                IgnoreRecord_false,
1038
                TryRemoveColors_true);
1039
        }
1040
        else
1041
        {
1042
            debugChatTab->chatLog("Unable to stop IPC service.",
1043
                ChatMsgType::BY_SERVER,
1044
                IgnoreRecord_false,
1045
                TryRemoveColors_true);
1046
        }
1047
    }
1048
    else
1049
    {
1050
        IPC::start();
1051
        if (ipc != nullptr)
1052
        {
1053
            debugChatTab->chatLog(
1054
                strprintf("IPC service available on port %d", ipc->getPort()),
1055
                ChatMsgType::BY_SERVER,
1056
                IgnoreRecord_false,
1057
                TryRemoveColors_true);
1058
        }
1059
        else
1060
        {
1061
            debugChatTab->chatLog("Unable to start IPC service",
1062
                ChatMsgType::BY_SERVER,
1063
                IgnoreRecord_false,
1064
                TryRemoveColors_true);
1065
        }
1066
    }
1067
    return true;
1068
}
1069
1070
impHandler(where)
1071
{
1072
    ChatTab *const tab = event.tab != nullptr ? event.tab : debugChatTab;
1073
    if (tab == nullptr)
1074
        return false;
1075
    std::ostringstream where;
1076
    where << Game::instance()->getCurrentMapName() << ", coordinates: "
1077
        << ((localPlayer->getPixelX() - mapTileSize / 2) / mapTileSize)
1078
        << ", " << ((localPlayer->getPixelY() - mapTileSize) / mapTileSize);
1079
    tab->chatLog(where.str(),
1080
        ChatMsgType::BY_SERVER,
1081
        IgnoreRecord_false,
1082
        TryRemoveColors_true);
1083
    return true;
1084
}
1085
1086
impHandler0(who)
1087
{
1088
    if (chatHandler != nullptr)
1089
        chatHandler->who();
1090
    return true;
1091
}
1092
1093
impHandler0(cleanGraphics)
1094
{
1095
    ResourceManager::clearCache();
1096
1097
    if (debugChatTab != nullptr)
1098
    {
1099
        // TRANSLATORS: clear graphics command message
1100
        debugChatTab->chatLog(_("Cache cleared"),
1101
            ChatMsgType::BY_SERVER,
1102
            IgnoreRecord_false,
1103
            TryRemoveColors_true);
1104
    }
1105
    return true;
1106
}
1107
1108
impHandler0(cleanFonts)
1109
{
1110
    if (gui != nullptr)
1111
        gui->clearFonts();
1112
    if (debugChatTab != nullptr)
1113
    {
1114
        // TRANSLATORS: clear fonts cache message
1115
        debugChatTab->chatLog(_("Cache cleared"),
1116
            ChatMsgType::BY_SERVER,
1117
            IgnoreRecord_false,
1118
            TryRemoveColors_true);
1119
    }
1120
    return true;
1121
}
1122
1123
impHandler(trade)
1124
{
1125
    if (actorManager == nullptr)
1126
        return false;
1127
1128
    const Being *being = actorManager->findBeingByName(
1129
        event.args, ActorType::Player);
1130
    if (being == nullptr)
1131
        being = localPlayer->getTarget();
1132
    if (being != nullptr)
1133
    {
1134
        if (tradeHandler != nullptr)
1135
            tradeHandler->request(being);
1136
        tradePartnerName = being->getName();
1137
        if (tradeWindow != nullptr)
1138
            tradeWindow->clear();
1139
    }
1140
    return true;
1141
}
1142
1143
impHandler0(priceLoad)
1144
{
1145
    if (shopWindow != nullptr)
1146
    {
1147
        shopWindow->loadList();
1148
        return true;
1149
    }
1150
    return false;
1151
}
1152
1153
impHandler0(priceSave)
1154
{
1155
    if (shopWindow != nullptr)
1156
    {
1157
        shopWindow->saveList();
1158
        return true;
1159
    }
1160
    return false;
1161
}
1162
1163
impHandler0(cacheInfo)
1164
{
1165
    if ((chatWindow == nullptr) || (debugChatTab == nullptr))
1166
        return false;
1167
1168
/*
1169
    Font *const font = chatWindow->getFont();
1170
    if (!font)
1171
        return;
1172
1173
    const TextChunkList *const cache = font->getCache();
1174
    if (!cache)
1175
        return;
1176
1177
    unsigned int all = 0;
1178
    // TRANSLATORS: chat fonts message
1179
    debugChatTab->chatLog(_("font cache size"),
1180
        ChatMsgType::BY_SERVER,
1181
        IgnoreRecord_false,
1182
        TryRemoveColors_true);
1183
    std::string str;
1184
    for (int f = 0; f < 256; f ++)
1185
    {
1186
        if (!cache[f].size)
1187
        {
1188
            const unsigned int sz = CAST_S32(cache[f].size);
1189
            all += sz;
1190
            str.append(strprintf("%d: %u, ", f, sz));
1191
        }
1192
    }
1193
    debugChatTab->chatLog(str,
1194
        ChatMsgType::BY_SERVER,
1195
        IgnoreRecord_false,
1196
        TryRemoveColors_true);
1197
    // TRANSLATORS: chat fonts message
1198
    debugChatTab->chatLog(strprintf("%s %d", _("Cache size:"), all),
1199
        ChatMsgType::BY_SERVER,
1200
        IgnoreRecord_false,
1201
        TryRemoveColors_true);
1202
#ifdef DEBUG_FONT_COUNTERS
1203
    debugChatTab->chatLog("",
1204
        ChatMsgType::BY_SERVER,
1205
        IgnoreRecord_false,
1206
        TryRemoveColors_true);
1207
    debugChatTab->chatLog(strprintf("%s %d",
1208
        // TRANSLATORS: chat fonts message
1209
        _("Created:"), font->getCreateCounter()),
1210
        ChatMsgType::BY_SERVER,
1211
        IgnoreRecord_false,
1212
        TryRemoveColors_true);
1213
    debugChatTab->chatLog(strprintf("%s %d",
1214
        // TRANSLATORS: chat fonts message
1215
        _("Deleted:"), font->getDeleteCounter()),
1216
        ChatMsgType::BY_SERVER,
1217
        IgnoreRecord_false,
1218
        TryRemoveColors_true);
1219
#endif
1220
*/
1221
    return true;
1222
}
1223
1224
impHandler0(disconnect)
1225
{
1226
    if (gameHandler != nullptr)
1227
        gameHandler->disconnect2();
1228
    return true;
1229
}
1230
1231
impHandler(undress)
1232
{
1233
    if ((actorManager == nullptr) || (localPlayer == nullptr))
1234
        return false;
1235
1236
    const std::string args = event.args;
1237
    StringVect pars;
1238
    if (!splitParameters(pars, args, " ,", '\"'))
1239
        return false;
1240
    Being *target = nullptr;
1241
    const size_t sz = pars.size();
1242
    if (sz == 0)
1243
    {
1244
        target = localPlayer->getTarget();
1245
    }
1246
    else
1247
    {
1248
        if (pars[0][0] == ':')
1249
        {
1250
            target = actorManager->findBeing(fromInt(atoi(
1251
                pars[0].substr(1).c_str()), BeingId));
1252
            if ((target != nullptr) && target->getType() == ActorType::Monster)
1253
                target = nullptr;
1254
        }
1255
        else
1256
        {
1257
            target = actorManager->findNearestByName(args,
1258
                ActorType::Unknown);
1259
        }
1260
    }
1261
1262
    if (sz == 2)
1263
    {
1264
        const int itemId = atoi(pars[1].c_str());
1265
        if (target != nullptr)
1266
            target->undressItemById(itemId);
1267
    }
1268
    else
1269
    {
1270
        if ((target != nullptr) && (beingHandler != nullptr))
1271
            beingHandler->undress(target);
1272
    }
1273
1274
    return true;
1275
}
1276
1277
impHandler0(dirs)
1278
{
1279
    if (debugChatTab == nullptr)
1280
        return false;
1281
1282
    debugChatTab->chatLog("config directory: "
1283
        + settings.configDir,
1284
        ChatMsgType::BY_SERVER,
1285
        IgnoreRecord_false,
1286
        TryRemoveColors_true);
1287
    debugChatTab->chatLog("logs directory: "
1288
        + settings.localDataDir,
1289
        ChatMsgType::BY_SERVER,
1290
        IgnoreRecord_false,
1291
        TryRemoveColors_true);
1292
    debugChatTab->chatLog("screenshots directory: "
1293
        + settings.screenshotDir,
1294
        ChatMsgType::BY_SERVER,
1295
        IgnoreRecord_false,
1296
        TryRemoveColors_true);
1297
    debugChatTab->chatLog("temp directory: "
1298
        + settings.tempDir,
1299
        ChatMsgType::BY_SERVER,
1300
        IgnoreRecord_false,
1301
        TryRemoveColors_true);
1302
    return true;
1303
}
1304
1305
impHandler0(uptime)
1306
{
1307
    if (debugChatTab == nullptr)
1308
        return false;
1309
1310
    if (cur_time < start_time)
1311
    {
1312
        // TRANSLATORS: uptime command
1313
        debugChatTab->chatLog(strprintf(_("Client uptime: %s"), "unknown"),
1314
            ChatMsgType::BY_SERVER,
1315
            IgnoreRecord_false,
1316
            TryRemoveColors_true);
1317
    }
1318
    else
1319
    {
1320
        // TRANSLATORS: uptime command
1321
        debugChatTab->chatLog(strprintf(_("Client uptime: %s"),
1322
            timeDiffToString(CAST_S32(cur_time - start_time)).c_str()),
1323
            ChatMsgType::BY_SERVER,
1324
            IgnoreRecord_false,
1325
            TryRemoveColors_true);
1326
    }
1327
    return true;
1328
}
1329
1330
#ifdef DEBUG_DUMP_LEAKS1
1331
static void showRes(std::string str, ResourceManager::Resources *res)
1332
{
1333
    if (!res)
1334
        return;
1335
1336
    str.append(toString(res->size()));
1337
    if (debugChatTab)
1338
    {
1339
        debugChatTab->chatLog(str,
1340
            ChatMsgType::BY_SERVER,
1341
            IgnoreRecord_false,
1342
            TryRemoveColors_true);
1343
    }
1344
    logger->log(str);
1345
    ResourceManager::ResourceIterator iter = res->begin();
1346
    const ResourceManager::ResourceIterator iter_end = res->end();
1347
    while (iter != iter_end)
1348
    {
1349
        if (iter->second && iter->second->mRefCount)
1350
        {
1351
            char type = ' ';
1352
            char isNew = 'N';
1353
            if (iter->second->getDumped())
1354
                isNew = 'O';
1355
            else
1356
                iter->second->setDumped(true);
1357
1358
            SubImage *const subImage = dynamic_cast<SubImage *>(
1359
                iter->second);
1360
            Image *const image = dynamic_cast<Image *>(iter->second);
1361
            int id = 0;
1362
            if (subImage)
1363
                type = 'S';
1364
            else if (image)
1365
                type = 'I';
1366
            if (image)
1367
                id = image->getGLImage();
1368
            logger->log("Resource %c%c: %s (%d) id=%d", type,
1369
                isNew, iter->second->getIdPath().c_str(),
1370
                iter->second->mRefCount, id);
1371
        }
1372
        ++ iter;
1373
    }
1374
}
1375
1376
impHandler(dump)
1377
{
1378
    if (!debugChatTab)
1379
        return false;
1380
1381
    if (!event.args.empty())
1382
    {
1383
        ResourceManager::Resources *res = ResourceManager::getResources();
1384
        // TRANSLATORS: dump command
1385
        showRes(_("Resource images:"), res);
1386
        res = ResourceManager::getOrphanedResources();
1387
        // TRANSLATORS: dump command
1388
        showRes(_("Orphaned resource images:"), res);
1389
    }
1390
    else
1391
    {
1392
        ResourceManager::Resources *res = ResourceManager::getResources();
1393
        // TRANSLATORS: dump command
1394
        debugChatTab->chatLog(_("Resource images:") + toString(res->size()),
1395
            ChatMsgType::BY_SERVER,
1396
            IgnoreRecord_false,
1397
            TryRemoveColors_true);
1398
        res = ResourceManager::getOrphanedResources();
1399
        // TRANSLATORS: dump command
1400
        debugChatTab->chatLog(_("Orphaned resource images:")
1401
            + toString(res->size()),
1402
            ChatMsgType::BY_SERVER,
1403
            IgnoreRecord_false,
1404
            TryRemoveColors_true);
1405
    }
1406
    return true;
1407
}
1408
1409
#elif defined ENABLE_MEM_DEBUG
1410
impHandler0(dump)
1411
{
1412
    nvwa::check_leaks();
1413
    return true;
1414
}
1415
#else  // DEBUG_DUMP_LEAKS1
1416
1417
impHandler0(dump)
1418
{
1419
    return true;
1420
}
1421
#endif  // DEBUG_DUMP_LEAKS1
1422
1423
impHandler0(serverIgnoreAll)
1424
{
1425
    if (chatHandler != nullptr)
1426
        chatHandler->ignoreAll();
1427
    return true;
1428
}
1429
1430
impHandler0(serverUnIgnoreAll)
1431
{
1432
    if (chatHandler != nullptr)
1433
        chatHandler->unIgnoreAll();
1434
    return true;
1435
}
1436
1437
PRAGMA6(GCC diagnostic push)
1438
PRAGMA6(GCC diagnostic ignored "-Wnull-dereference")
1439
impHandler0(error)
1440
{
1441
    int *const ptr = nullptr;
1442
    *(ptr + 1) = 20;
1443
//    logger->log("test %d", *ptr);
1444
    exit(1);
1445
}
1446
PRAGMA6(GCC diagnostic pop)
1447
1448
impHandler(dumpGraphics)
1449
{
1450
    std::string str = strprintf("%s,%s,%dX%dX%d,", PACKAGE_OS, SMALL_VERSION,
1451
        mainGraphics->getWidth(), mainGraphics->getHeight(),
1452
        mainGraphics->getBpp());
1453
1454
    if (mainGraphics->getFullScreen())
1455
        str.append("F");
1456
    else
1457
        str.append("W");
1458
    if (mainGraphics->getHWAccel())
1459
        str.append("H");
1460
    else
1461
        str.append("S");
1462
1463
    if (mainGraphics->getDoubleBuffer())
1464
        str.append("D");
1465
    else
1466
        str.append("_");
1467
1468
#if defined USE_OPENGL
1469
    str.append(strprintf(",%d", mainGraphics->getOpenGL()));
1470
#else  // defined USE_OPENGL
1471
1472
    str.append(",0");
1473
#endif  // defined USE_OPENGL
1474
1475
    str.append(strprintf(",%f,", static_cast<double>(settings.guiAlpha)))
1476
        .append(config.getBoolValue("adjustPerfomance") ? "1" : "0")
1477
        .append(config.getBoolValue("alphaCache") ? "1" : "0")
1478
        .append(config.getBoolValue("enableMapReduce") ? "1" : "0")
1479
        .append(config.getBoolValue("beingopacity") ? "1" : "0")
1480
        .append(",")
1481
        .append(config.getBoolValue("enableAlphaFix") ? "1" : "0")
1482
        .append(config.getBoolValue("disableAdvBeingCaching") ? "1" : "0")
1483
        .append(config.getBoolValue("disableBeingCaching") ? "1" : "0")
1484
        .append(config.getBoolValue("particleeffects") ? "1" : "0")
1485
        .append(strprintf(",%d-%d", fps, config.getIntValue("fpslimit")));
1486
    outStringNormal(event.tab, str, str);
1487
    return true;
1488
}
1489
1490
impHandler0(dumpEnvironment)
1491
{
1492
    logger->log1("Start environment variables");
1493
    for (char **env = environ; *env != nullptr; ++ env)
1494
        logger->log1(*env);
1495
    logger->log1("End environment variables");
1496
    if (debugChatTab != nullptr)
1497
    {
1498
        // TRANSLATORS: dump environment command
1499
        debugChatTab->chatLog(_("Environment variables dumped"),
1500
            ChatMsgType::BY_SERVER,
1501
            IgnoreRecord_false,
1502
            TryRemoveColors_true);
1503
    }
1504
    return true;
1505
}
1506
1507
impHandler(dumpTests)
1508
{
1509
    const std::string str = config.getStringValue("testInfo");
1510
    outStringNormal(event.tab, str, str);
1511
    return true;
1512
}
1513
1514
impHandler0(dumpOGL)
1515
{
1516
#if defined(USE_OPENGL) && !defined(ANDROID) && !defined(__native_client__)
1517
    NormalOpenGLGraphics::dumpSettings();
1518
#endif  // defined(USE_OPENGL) && !defined(ANDROID) &&
1519
        // !defined(__native_client__)
1520
1521
    return true;
1522
}
1523
1524
#ifdef USE_OPENGL
1525
impHandler(dumpGL)
1526
{
1527
    std::string str = graphicsManager.getGLVersion();
1528
    outStringNormal(event.tab, str, str);
1529
    return true;
1530
}
1531
#else  // USE_OPENGL
1532
1533
impHandler0(dumpGL)
1534
{
1535
    return true;
1536
}
1537
#endif  // USE_OPENGL
1538
1539
impHandler(dumpMods)
1540
{
1541
    std::string str = "enabled mods: " + serverConfig.getValue("mods", "");
1542
    outStringNormal(event.tab, str, str);
1543
    return true;
1544
}
1545
1546
#if defined USE_OPENGL && defined DEBUG_SDLFONT
1547
impHandler0(testSdlFont)
1548
{
1549
    Font *font = new Font("fonts/dejavusans.ttf", 18, TTF_STYLE_NORMAL);
1550
    timespec time1;
1551
    timespec time2;
1552
    NullOpenGLGraphics *nullGraphics = new NullOpenGLGraphics;
1553
    STD_VECTOR<std::string> data;
1554
    volatile int width = 0;
1555
1556
    for (int f = 0; f < 300; f ++)
1557
        data.push_back("test " + toString(f) + "string");
1558
    nullGraphics->beginDraw();
1559
1560
    clock_gettime(CLOCK_MONOTONIC, &time1);
1561
    Color color(0, 0, 0, 255);
1562
1563
    for (int f = 0; f < 500; f ++)
1564
    {
1565
        FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, data)
1566
        {
1567
            width += font->getWidth(*it);
1568
            font->drawString(nullGraphics, color, color, *it, 10, 10);
1569
        }
1570
        FOR_EACH (STD_VECTOR<std::string>::const_iterator, it, data)
1571
            font->drawString(nullGraphics, color, color, *it, 10, 10);
1572
1573
        font->doClean();
1574
    }
1575
1576
    clock_gettime(CLOCK_MONOTONIC, &time2);
1577
1578
    delete nullGraphics;
1579
    delete font;
1580
1581
    int64_t diff = (static_cast<long long int>(
1582
        time2.tv_sec) * 1000000000LL + static_cast<long long int>(
1583
        time2.tv_nsec)) / 100000 - (static_cast<long long int>(
1584
        time1.tv_sec) * 1000000000LL + static_cast<long long int>(
1585
        time1.tv_nsec)) / 100000;
1586
    if (debugChatTab)
1587
    {
1588
        debugChatTab->chatLog("sdlfont time: " + toString(diff),
1589
            ChatMsgType::BY_SERVER,
1590
            IgnoreRecord_false,
1591
            TryRemoveColors_true);
1592
    }
1593
    return true;
1594
}
1595
#endif  // defined USE_OPENGL && defined DEBUG_SDLFONT
1596
1597
impHandler0(createItems)
1598
{
1599
    BuyDialog *const dialog = CREATEWIDGETR0(BuyDialog);
1600
    const ItemDB::ItemInfos &items = ItemDB::getItemInfos();
1601
    FOR_EACH (ItemDB::ItemInfos::const_iterator, it, items)
1602
    {
1603
        const ItemInfo *const info = (*it).second;
1604
        if (info == nullptr)
1605
            continue;
1606
        const int id = info->getId();
1607
        if (id <= 500)
1608
            continue;
1609
1610
        dialog->addItem(id,
1611
            ItemType::Unknown,
1612
            ItemColor_one,
1613
            100,
1614
            0);
1615
    }
1616
    dialog->sort();
1617
    return true;
1618
}
1619
1620
impHandler(createItem)
1621
{
1622
    int id = 0;
1623
    int amount = 0;
1624
1625
    if (adminHandler == nullptr)
1626
        return false;
1627
1628
    if (parse2Int(event.args, id, amount))
1629
        adminHandler->createItems(id, ItemColor_one, amount);
1630
    else
1631
        adminHandler->createItems(atoi(event.args.c_str()), ItemColor_one, 1);
1632
    return true;
1633
}
1634
1635
impHandler(uploadConfig)
1636
{
1637
    // TRANSLATORS: upload config chat message
1638
    uploadFile(_("Config uploaded to:"),
1639
        config.getFileName(),
1640
        "?xml",
1641
        event.tab);
1642
    return true;
1643
}
1644
1645
impHandler(uploadServerConfig)
1646
{
1647
    // TRANSLATORS: upload config chat message
1648
    uploadFile(_("Server config Uploaded to:"),
1649
        serverConfig.getFileName(),
1650
        "?xml",
1651
        event.tab);
1652
    return true;
1653
}
1654
1655
impHandler(uploadLog)
1656
{
1657
    // TRANSLATORS: upload log chat message
1658
    uploadFile(_("Log uploaded to:"),
1659
        settings.logFileName,
1660
        "",
1661
        event.tab);
1662
    return true;
1663
}
1664
1665
impHandler0(mercenaryFire)
1666
{
1667
    if (mercenaryHandler != nullptr)
1668
        mercenaryHandler->fire();
1669
    return true;
1670
}
1671
1672
impHandler0(mercenaryToMaster)
1673
{
1674
    if (mercenaryHandler != nullptr)
1675
        mercenaryHandler->moveToMaster();
1676
    return true;
1677
}
1678
1679
impHandler0(homunculusToMaster)
1680
{
1681
    if (homunculusHandler != nullptr)
1682
        homunculusHandler->moveToMaster();
1683
    return true;
1684
}
1685
1686
impHandler0(homunculusFeed)
1687
{
1688
    if (homunculusHandler != nullptr)
1689
        homunculusHandler->feed();
1690
    return true;
1691
}
1692
1693
impHandler(useItem)
1694
{
1695
    StringVect pars;
1696
    if (!splitParameters(pars, event.args, " ,", '\"'))
1697
        return false;
1698
    const int sz = CAST_S32(pars.size());
1699
    if (sz < 1)
1700
        return false;
1701
1702
    const int itemId = atoi(pars[0].c_str());
1703
1704
    if (itemId < SPELL_MIN_ID)
1705
    {
1706
        const Inventory *const inv = PlayerInfo::getInventory();
1707
        if (inv != nullptr)
1708
        {
1709
            ItemColor color = ItemColor_one;
1710
            int16_t useType = 0;
1711
            StringVect pars2;
1712
            if (!splitParameters(pars2, pars[0], " ,", '\"'))
1713
                return false;
1714
            const int sz2 = CAST_S32(pars2.size());
1715
            if (sz2 < 1)
1716
                return false;
1717
            if (sz2 >= 2)
1718
                color = fromInt(atoi(pars2[1].c_str()), ItemColor);
1719
            if (sz >= 2)
1720
                useType = CAST_S16(atoi(pars[1].c_str()));
1721
            const Item *const item = inv->findItem(itemId,
1722
                color);
1723
            PlayerInfo::useEquipItem(item, useType, Sfx_true);
1724
        }
1725
    }
1726
    else if (itemId < SKILL_MIN_ID && (spellManager != nullptr))
1727
    {
1728
        spellManager->useItem(itemId);
1729
    }
1730
    else if (skillDialog != nullptr)
1731
    {
1732
        // +++ probably need get data parameter from args
1733
        skillDialog->useItem(itemId,
1734
            fromBool(config.getBoolValue("skillAutotarget"), AutoTarget),
1735
            0,
1736
            std::string());
1737
    }
1738
    return true;
1739
}
1740
1741
impHandler(useItemInv)
1742
{
1743
    int param1 = 0;
1744
    int param2 = 0;
1745
    const std::string args = event.args;
1746
    if (parse2Int(args, param1, param2))
1747
    {
1748
        Item *const item = getItemByInvIndex(param1,
1749
            InventoryType::Inventory);
1750
        PlayerInfo::useEquipItem(item, CAST_S16(param2), Sfx_true);
1751
    }
1752
    else
1753
    {
1754
        Item *const item = getItemByInvIndex(atoi(event.args.c_str()),
1755
            InventoryType::Inventory);
1756
        PlayerInfo::useEquipItem(item, 0, Sfx_true);
1757
    }
1758
    return true;
1759
}
1760
1761
impHandler(invToStorage)
1762
{
1763
    Item *item = nullptr;
1764
    const int amount = getAmountFromEvent(event, item,
1765
        InventoryType::Inventory);
1766
    if (item == nullptr)
1767
        return true;
1768
    if (amount != 0)
1769
    {
1770
        if (inventoryHandler != nullptr)
1771
        {
1772
            inventoryHandler->moveItem2(InventoryType::Inventory,
1773
                item->getInvIndex(),
1774
                amount,
1775
                InventoryType::Storage);
1776
        }
1777
    }
1778
    else
1779
    {
1780
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::StoreAdd,
1781
            inventoryWindow,
1782
            item,
1783
            0,
1784
            0);
1785
    }
1786
    return true;
1787
}
1788
1789
impHandler(tradeAdd)
1790
{
1791
    Item *item = nullptr;
1792
    const int amount = getAmountFromEvent(event, item,
1793
        InventoryType::Inventory);
1794
    if ((item == nullptr) || PlayerInfo::isItemProtected(item->getId()))
1795
        return true;
1796
1797
    if (amount != 0)
1798
    {
1799
        if (tradeWindow != nullptr)
1800
            tradeWindow->tradeItem(item, amount, true);
1801
    }
1802
    else
1803
    {
1804
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::TradeAdd,
1805
            tradeWindow,
1806
            item,
1807
            0,
1808
            0);
1809
    }
1810
    return true;
1811
}
1812
1813
impHandler(storageToInv)
1814
{
1815
    Item *item = nullptr;
1816
    const int amount = getAmountFromEvent(event, item, InventoryType::Storage);
1817
    if (amount != 0)
1818
    {
1819
        if ((inventoryHandler != nullptr) && (item != nullptr))
1820
        {
1821
            inventoryHandler->moveItem2(InventoryType::Storage,
1822
                item->getInvIndex(),
1823
                amount,
1824
                InventoryType::Inventory);
1825
        }
1826
    }
1827
    else
1828
    {
1829
        ItemAmountWindow::showWindow(ItemAmountWindowUsage::StoreRemove,
1830
            storageWindow,
1831
            item,
1832
            0,
1833
            0);
1834
    }
1835
    return true;
1836
}
1837
1838
impHandler(protectItem)
1839
{
1840
    const int id = atoi(event.args.c_str());
1841
    if (id > 0)
1842
        PlayerInfo::protectItem(id);
1843
    return true;
1844
}
1845
1846
impHandler(unprotectItem)
1847
{
1848
    const int id = atoi(event.args.c_str());
1849
    if (id > 0)
1850
        PlayerInfo::unprotectItem(id);
1851
    return true;
1852
}
1853
1854
impHandler(kick)
1855
{
1856
    if ((localPlayer == nullptr) || (actorManager == nullptr))
1857
        return false;
1858
1859
    Being *target = nullptr;
1860
    std::string args = event.args;
1861
    if (!args.empty())
1862
    {
1863
        if (args[0] != ':')
1864
        {
1865
            target = actorManager->findNearestByName(args,
1866
                ActorType::Unknown);
1867
        }
1868
        else
1869
        {
1870
            target = actorManager->findBeing(fromInt(atoi(
1871
                args.substr(1).c_str()), BeingId));
1872
        }
1873
    }
1874
    if (target == nullptr)
1875
        target = localPlayer->getTarget();
1876
    if ((target != nullptr) && (adminHandler != nullptr))
1877
        adminHandler->kick(target->getId());
1878
    return true;
1879
}
1880
1881
impHandler0(clearDrop)
1882
{
1883
    if (dropShortcut != nullptr)
1884
        dropShortcut->clear(true);
1885
    return true;
1886
}
1887
1888
impHandler0(testInfo)
1889
{
1890
    if (actorManager != nullptr)
1891
    {
1892
        logger->log("actors count: %d", CAST_S32(
1893
            actorManager->size()));
1894
        return true;
1895
    }
1896
    return false;
1897
}
1898
1899
impHandler(craftKey)
1900
{
1901
    const int slot = (event.action - InputAction::CRAFT_1);
1902
    if (slot >= 0 && slot < 9)
1903
    {
1904
        if (inventoryWindow != nullptr)
1905
            inventoryWindow->moveItemToCraft(slot);
1906
        return true;
1907
    }
1908
    return false;
1909
}
1910
1911
impHandler0(resetGameModifiers)
1912
{
1913
    GameModifiers::resetModifiers();
1914
    return true;
1915
}
1916
1917
impHandler(barToChat)
1918
{
1919
    if (chatWindow != nullptr)
1920
    {
1921
        chatWindow->addInputText(event.args,
1922
            true);
1923
        return true;
1924
    }
1925
    return false;
1926
}
1927
1928
impHandler(seen)
1929
{
1930
    if (actorManager == nullptr)
1931
        return false;
1932
1933
    ChatTab *tab = event.tab;
1934
    if (tab == nullptr)
1935
        tab = localChatTab;
1936
    if (tab == nullptr)
1937
        return false;
1938
1939
    if (config.getBoolValue("enableIdCollecting") == false)
1940
    {
1941
        // TRANSLATORS: last seen disabled warning
1942
        tab->chatLog(_("Last seen disabled. "
1943
            "Enable in players / collect players ID and seen log."),
1944
            ChatMsgType::BY_SERVER,
1945
            IgnoreRecord_false,
1946
            TryRemoveColors_true);
1947
        return true;
1948
    }
1949
1950
    const std::string name = event.args;
1951
    if (name.empty())
1952
        return false;
1953
1954
    std::string dir = settings.usersDir;
1955
    dir.append(stringToHexPath(name)).append("/seen.txt");
1956
    if (Files::existsLocal(dir))
1957
    {
1958
        StringVect lines;
1959
        Files::loadTextFileLocal(dir, lines);
1960
        if (lines.size() < 3)
1961
        {
1962
            // TRANSLATORS: last seen error
1963
            tab->chatLog(_("You have never seen this nick."),
1964
                ChatMsgType::BY_SERVER,
1965
                IgnoreRecord_false,
1966
                TryRemoveColors_true);
1967
            return true;
1968
        }
1969
        const std::string message = strprintf(
1970
            // TRANSLATORS: last seen message
1971
            _("Last seen for %s: %s"),
1972
            name.c_str(),
1973
            lines[2].c_str());
1974
        tab->chatLog(message,
1975
            ChatMsgType::BY_SERVER,
1976
            IgnoreRecord_false,
1977
            TryRemoveColors_true);
1978
    }
1979
    else
1980
    {
1981
        // TRANSLATORS: last seen error
1982
        tab->chatLog(_("You have not seen this nick before."),
1983
            ChatMsgType::BY_SERVER,
1984
            IgnoreRecord_false,
1985
            TryRemoveColors_true);
1986
    }
1987
1988
    return true;
1989
}
1990
1991
impHandler(dumpMemoryUsage)
1992
{
1993
    if (event.tab != nullptr)
1994
        memoryManager.printAllMemory(event.tab);
1995
    else
1996
        memoryManager.printAllMemory(localChatTab);
1997
    return true;
1998
}
1999
2000
impHandler(setEmoteType)
2001
{
2002
    const std::string &args = event.args;
2003
    if (args == "player" || args.empty())
2004
    {
2005
        settings.emoteType = EmoteType::Player;
2006
    }
2007
    else if (args == "pet")
2008
    {
2009
        settings.emoteType = EmoteType::Pet;
2010
    }
2011
    else if (args == "homun" || args == "homunculus")
2012
    {
2013
        settings.emoteType = EmoteType::Homunculus;
2014
    }
2015
    else if (args == "merc" || args == "mercenary")
2016
    {
2017
        settings.emoteType = EmoteType::Mercenary;
2018
    }
2019
    return true;
2020
}
2021
2022
4
}  // namespace Actions