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

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