GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/popups/popupmenu.cpp Lines: 21 1624 1.3 %
Date: 2021-03-17 Branches: 14 2125 0.7 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2019  The ManaPlus Developers
6
 *  Copyright (C) 2019-2021  Andrei Karas
7
 *
8
 *  This file is part of The ManaPlus Client.
9
 *
10
 *  This program is free software; you can redistribute it and/or modify
11
 *  it under the terms of the GNU General Public License as published by
12
 *  the Free Software Foundation; either version 2 of the License, or
13
 *  any later version.
14
 *
15
 *  This program is distributed in the hope that it will be useful,
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 *  GNU General Public License for more details.
19
 *
20
 *  You should have received a copy of the GNU General Public License
21
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
#include "gui/popups/popupmenu.h"
25
26
#include "actormanager.h"
27
#include "configuration.h"
28
#include "party.h"
29
#include "settings.h"
30
31
#include "being/flooritem.h"
32
#include "being/localplayer.h"
33
#include "being/playerinfo.h"
34
#include "being/playerrelation.h"
35
#include "being/playerrelations.h"
36
37
#include "const/spells.h"
38
39
#include "enums/resources/map/mapitemtype.h"
40
41
#include "input/inputmanager.h"
42
43
#include "gui/buttontext.h"
44
#include "gui/gui.h"
45
#include "gui/popupmanager.h"
46
#include "gui/viewport.h"
47
#include "gui/windowmenu.h"
48
49
#include "gui/windows/chatwindow.h"
50
#include "gui/windows/inventorywindow.h"
51
#include "gui/windows/minimap.h"
52
#include "gui/windows/ministatuswindow.h"
53
#include "gui/windows/npcdialog.h"
54
#include "gui/windows/outfitwindow.h"
55
#include "gui/windows/socialwindow.h"
56
#include "gui/windows/textcommandeditor.h"
57
#include "gui/windows/textdialog.h"
58
#include "gui/windows/tradewindow.h"
59
60
#include "gui/widgets/button.h"
61
#include "gui/widgets/createwidget.h"
62
#include "gui/widgets/progressbar.h"
63
#include "gui/widgets/scrollarea.h"
64
#include "gui/widgets/staticbrowserbox.h"
65
#include "gui/widgets/textfield.h"
66
67
#include "gui/widgets/tabs/chat/whispertab.h"
68
69
#include "net/adminhandler.h"
70
#include "net/chathandler.h"
71
#include "net/guildhandler.h"
72
#include "net/npchandler.h"
73
#include "net/net.h"
74
75
#ifdef TMWA_SUPPORT
76
#include "net/tmwa/guildmanager.h"
77
#endif  // TMWA_SUPPORT
78
79
#include "resources/chatobject.h"
80
#include "resources/groupinfo.h"
81
#include "resources/iteminfo.h"
82
#include "resources/itemmenuitem.h"
83
84
#include "resources/db/groupdb.h"
85
#include "resources/db/npcdb.h"
86
87
#include "resources/item/item.h"
88
89
#include "resources/map/map.h"
90
#include "resources/map/mapitem.h"
91
#include "resources/map/speciallayer.h"
92
93
#include "resources/skill/skillinfo.h"
94
95
#include "utils/checkutils.h"
96
#include "utils/foreach.h"
97
#include "utils/gettext.h"
98
99
#include "debug.h"
100
101
1
std::string tradePartnerName;
102
103
PopupMenu *popupMenu = nullptr;
104
105
2
PopupMenu::PopupMenu() :
106
    Popup("PopupMenu", "popupmenu.xml"),
107
    mBrowserBox(new StaticBrowserBox(this, Opaque_true,
108

2
        "popupbrowserbox.xml")),
109
    mScrollArea(nullptr),
110
    mBeingId(BeingId_zero),
111
    mFloorItemId(BeingId_zero),
112
    mItemId(0),
113
    mItemIndex(-1),
114
    mItemColor(ItemColor_one),
115
    mMapItem(nullptr),
116
    mTab(nullptr),
117
    mSpell(nullptr),
118
    mCallerWindow(nullptr),
119
    mRenameListener(),
120
    mPlayerListener(),
121
    mDialog(nullptr),
122
    mButton(nullptr),
123
    mGroup(nullptr),
124
    mName(),
125
    mExtName(),
126
    mTextField(nullptr),
127
    mType(ActorType::Unknown),
128
    mSubType(BeingTypeId_zero),
129
    mX(0),
130
    mY(0),
131

22
    mAllowCleanMenu(true)
132
{
133
4
    mBrowserBox->setOpaque(Opaque_false);
134
2
    mBrowserBox->setLinkHandler(this);
135
2
    mRenameListener.setMapItem(nullptr);
136
4
    mRenameListener.setDialog(nullptr);
137
10
    mPlayerListener.setNick("");
138
4
    mPlayerListener.setDialog(nullptr);
139
4
    mPlayerListener.setType(ActorType::Unknown);
140
2
    mScrollArea = new ScrollArea(this,
141

4
        mBrowserBox, Opaque_false, std::string());
142
2
    mScrollArea->setVerticalScrollPolicy(ScrollArea::SHOW_AUTO);
143
2
    addMouseListener(this);
144
2
}
145
146
2
void PopupMenu::postInit()
147
{
148
4
    Popup::postInit();
149
2
    add(mScrollArea);
150
2
}
151
152
void PopupMenu::initPopup()
153
{
154
    if (localPlayer == nullptr)
155
        return;
156
    const int groupId = localPlayer->getGroupId();
157
    mGroup = GroupDb::getGroup(groupId);
158
}
159
160
bool PopupMenu::isAllowCommand(const ServerCommandTypeT command)
161
{
162
    if (mGroup == nullptr)
163
        return false;
164
#ifdef TMWA_SUPPORT
165
    // allow any commands for legacy if group > 0
166
    if (Net::getNetworkType() == ServerType::TMWATHENA &&
167
        localPlayer != nullptr &&
168
        localPlayer->isGM())
169
    {
170
        return true;
171
    }
172
#endif
173
    if (mGroup->mPermissions[CAST_SIZE(ServerPermissionType::all_commands)] ==
174
        Enable_true)
175
    {
176
        return true;
177
    }
178
    const ServerCommandEnable::Type enabled =
179
        mGroup->mCommands[CAST_SIZE(command)];
180
    return (enabled & ServerCommandEnable::Self) != 0;
181
}
182
183
bool PopupMenu::isAllowOtherCommand(const ServerCommandTypeT command)
184
{
185
    if (mGroup == nullptr ||
186
        localPlayer == nullptr)
187
        return false;
188
#ifdef TMWA_SUPPORT
189
    // allow any commands for legacy if group > 0
190
    if (Net::getNetworkType() == ServerType::TMWATHENA &&
191
        localPlayer->isGM())
192
    {
193
        return true;
194
    }
195
#endif
196
    const ServerCommandEnable::Type enabled =
197
        mGroup->mCommands[CAST_SIZE(command)];
198
    if (mName == localPlayer->getName())
199
        return (enabled & ServerCommandEnable::Self) != 0;
200
    return (enabled & ServerCommandEnable::Other) != 0;
201
}
202
203
void PopupMenu::showPopup(const int x, const int y, const Being *const being)
204
{
205
    if (being == nullptr ||
206
        localPlayer == nullptr ||
207
        actorManager == nullptr)
208
    {
209
        return;
210
    }
211
212
    initPopup();
213
    mBeingId = being->getId();
214
    mName = being->getName();
215
    mExtName = being->getExtName();
216
    mType = being->getType();
217
    mSubType = being->getSubType();
218
    mBrowserBox->clearRows();
219
    mX = x;
220
    mY = y;
221
222
    const std::string &name = mName;
223
    if (being->getType() != ActorType::SkillUnit)
224
    {
225
        mBrowserBox->addRow(name + being->getGenderSignWithSpace(),
226
            false);
227
    }
228
229
    switch (being->getType())
230
    {
231
        case ActorType::Player:
232
        {
233
            // TRANSLATORS: popup menu item
234
            // TRANSLATORS: trade with player
235
            mBrowserBox->addRow("/trade 'NAME'", _("Trade"));
236
            // TRANSLATORS: popup menu item
237
            // TRANSLATORS: trade attack player
238
            mBrowserBox->addRow("/attack 'NAME'", _("Attack"));
239
            // TRANSLATORS: popup menu item
240
            // TRANSLATORS: send whisper to player
241
            mBrowserBox->addRow("/whispertext 'NAME'", _("Whisper"));
242
            addMailCommands();
243
            addGmCommands();
244
            mBrowserBox->addSeparator("##3---");
245
246
#ifdef TMWA_SUPPORT
247
            if (Net::getNetworkType() == ServerType::TMWATHENA)
248
            {
249
                // TRANSLATORS: popup menu item
250
                // TRANSLATORS: heal player
251
                mBrowserBox->addRow("/heal :'BEINGID'", _("Heal"));
252
                mBrowserBox->addSeparator("##3---");
253
            }
254
#endif  // TMWA_SUPPORT
255
256
            addPlayerRelation(name);
257
            mBrowserBox->addSeparator("##3---");
258
259
            addFollow();
260
            addPartyName(being->getPartyName());
261
262
            const Guild *const guild1 = being->getGuild();
263
            const Guild *const guild2 = localPlayer->getGuild();
264
            if (guild2 != nullptr)
265
            {
266
                if (guild1 != nullptr)
267
                {
268
                    if (guild1->getId() == guild2->getId())
269
                    {
270
                        mBrowserBox->addRow("/kickguild 'NAME'",
271
                            // TRANSLATORS: popup menu item
272
                            // TRANSLATORS: kick player from guild
273
                            _("Kick from guild"));
274
                        if (guild2->getServerGuild())
275
                        {
276
                            mBrowserBox->addRow(strprintf(
277
                                "@@guild-pos|%s >@@",
278
                                // TRANSLATORS: popup menu item
279
                                // TRANSLATORS: change player position in guild
280
                                _("Change pos in guild")),
281
                                false);
282
                        }
283
                    }
284
                }
285
                else if (guild2->getMember(mName) != nullptr)
286
                {
287
                    mBrowserBox->addRow("/kickguild 'NAME'",
288
                        // TRANSLATORS: popup menu item
289
                        // TRANSLATORS: kick player from guild
290
                        _("Kick from guild"));
291
                    if (guild2->getServerGuild())
292
                    {
293
                        mBrowserBox->addRow(strprintf(
294
                            "@@guild-pos|%s >@@",
295
                            // TRANSLATORS: popup menu item
296
                            // TRANSLATORS: change player position in guild
297
                            _("Change pos in guild")),
298
                            false);
299
                    }
300
                }
301
                else
302
                {
303
#ifdef TMWA_SUPPORT
304
                    if (guild2->getServerGuild() ||
305
                        (guildManager != nullptr && guildManager->havePower()))
306
#endif  // TMWA_SUPPORT
307
                    {
308
                        mBrowserBox->addRow("/guild 'NAME'",
309
                            // TRANSLATORS: popup menu item
310
                            // TRANSLATORS: invite player to guild
311
                            _("Invite to guild"));
312
                    }
313
                }
314
            }
315
316
            // TRANSLATORS: popup menu item
317
            // TRANSLATORS: set player invisible for self by id
318
            mBrowserBox->addRow("/nuke 'NAME'", _("Nuke"));
319
            // TRANSLATORS: popup menu item
320
            // TRANSLATORS: move to player location
321
            mBrowserBox->addRow("/navigateto 'NAME'", _("Move"));
322
            addPlayerMisc();
323
            addBuySell(being);
324
            addChat(being);
325
            break;
326
        }
327
328
        case ActorType::Npc:
329
            if (!addBeingMenu())
330
            {
331
                // TRANSLATORS: popup menu item
332
                // TRANSLATORS: talk with npc
333
                mBrowserBox->addRow("/talk :'BEINGID'", _("Talk"));
334
#ifdef TMWA_SUPPORT
335
                if (Net::getNetworkType() != ServerType::TMWATHENA)
336
#endif
337
                {
338
                    mBrowserBox->addRow("/whispertext NPC:'NAME'",
339
                        // TRANSLATORS: popup menu item
340
                        // TRANSLATORS: whisper to npc
341
                        _("Whisper"));
342
                }
343
                // TRANSLATORS: popup menu item
344
                // TRANSLATORS: buy from npc
345
                mBrowserBox->addRow("/buy 'NAME'", _("Buy"));
346
                // TRANSLATORS: popup menu item
347
                // TRANSLATORS: sell to npc
348
                mBrowserBox->addRow("/sell 'NAME'", _("Sell"));
349
            }
350
351
            addGmCommands();
352
            mBrowserBox->addSeparator("##3---");
353
            // TRANSLATORS: popup menu item
354
            // TRANSLATORS: move to npc location
355
            mBrowserBox->addRow("/navigateto 'NAME'", _("Move"));
356
            // TRANSLATORS: popup menu item
357
            // TRANSLATORS: add comment to npc
358
            mBrowserBox->addRow("addcomment", _("Add comment"));
359
            addChat(being);
360
            break;
361
362
        case ActorType::Monster:
363
        {
364
            // Monsters can be attacked
365
            // TRANSLATORS: popup menu item
366
            // TRANSLATORS: attack monster
367
            mBrowserBox->addRow("/attack :'BEINGID'", _("Attack"));
368
            addCatchPetCommands();
369
            addGmCommands();
370
            mBrowserBox->addSeparator("##3---");
371
372
            if (config.getBoolValue("enableAttackFilter"))
373
            {
374
                mBrowserBox->addSeparator("##3---");
375
                if (actorManager->isInAttackList(name)
376
                    || actorManager->isInIgnoreAttackList(name)
377
                    || actorManager->isInPriorityAttackList(name))
378
                {
379
                    mBrowserBox->addRow("/removeattack 'NAME'",
380
                        // TRANSLATORS: remove monster from attack list
381
                        // TRANSLATORS: popup menu item
382
                        _("Remove from attack list"));
383
                }
384
                else
385
                {
386
                    mBrowserBox->addRow("/addpriorityattack 'NAME'",
387
                        // TRANSLATORS: popup menu item
388
                        // TRANSLATORS: add monster to priotiry attack list
389
                        _("Add to priority attack list"));
390
                    mBrowserBox->addRow("/addattack 'NAME'",
391
                        // TRANSLATORS: popup menu item
392
                        // TRANSLATORS: add monster to attack list
393
                        _("Add to attack list"));
394
                    mBrowserBox->addRow("/addignoreattack 'NAME'",
395
                        // TRANSLATORS: popup menu item
396
                        // TRANSLATORS: add monster to ignore list
397
                        _("Add to ignore list"));
398
                }
399
            }
400
            break;
401
        }
402
403
        case ActorType::Mercenary:
404
            // TRANSLATORS: popup menu item
405
            // TRANSLATORS: Mercenary move to master
406
            mBrowserBox->addRow("/mercenarytomaster", _("Move to master"));
407
            addGmCommands();
408
            mBrowserBox->addSeparator("##3---");
409
            // TRANSLATORS: popup menu item
410
            // TRANSLATORS: fire mercenary
411
            mBrowserBox->addRow("/firemercenary", _("Fire"));
412
            mBrowserBox->addSeparator("##3---");
413
            break;
414
415
        case ActorType::Homunculus:
416
        {
417
            const HomunculusInfo *const info = PlayerInfo::getHomunculus();
418
            if (info != nullptr)
419
            {
420
                mBrowserBox->addRow("/homunculustomaster",
421
                    // TRANSLATORS: popup menu item
422
                    // TRANSLATORS: homunculus move to master
423
                    _("Move to master"));
424
                // TRANSLATORS: popup menu item
425
                // TRANSLATORS: feed homunculus
426
                mBrowserBox->addRow("/homunculusfeed", _("Feed"));
427
                mBrowserBox->addSeparator("##3---");
428
                // TRANSLATORS: popup menu item
429
                // TRANSLATORS: pet rename item
430
                mBrowserBox->addRow("/sethomunname", _("Rename"));
431
                mBrowserBox->addSeparator("##3---");
432
                // TRANSLATORS: popup menu item
433
                // TRANSLATORS: delete homunculus
434
                mBrowserBox->addRow("/homunculusfire", _("Kill"));
435
                mBrowserBox->addSeparator("##3---");
436
            }
437
            addGmCommands();
438
            break;
439
        }
440
        case ActorType::Pet:
441
            if (being->getOwner() == localPlayer)
442
            {
443
                // TRANSLATORS: popup menu item
444
                // TRANSLATORS: feed pet
445
                mBrowserBox->addRow("/petfeed", _("Feed"));
446
                // TRANSLATORS: popup menu item
447
                // TRANSLATORS: pet drop loot
448
                mBrowserBox->addRow("/petdroploot", _("Drop loot"));
449
                // TRANSLATORS: popup menu item
450
                // TRANSLATORS: pet unequip item
451
                mBrowserBox->addRow("/petunequip", _("Unequip"));
452
                addGmCommands();
453
                mBrowserBox->addSeparator("##3---");
454
                // TRANSLATORS: popup menu item
455
                // TRANSLATORS: pet rename item
456
                mBrowserBox->addRow("/setpetname", _("Rename"));
457
                mBrowserBox->addSeparator("##3---");
458
                const BeingInfo *const info = being->getInfo();
459
                std::string msg;
460
                if (info != nullptr)
461
                    msg = info->getString(0);
462
                if (!msg.empty())
463
                {
464
                    mBrowserBox->addRow("/petreturnegg", msg.c_str());
465
                }
466
                else
467
                {
468
                    mBrowserBox->addRow("/petreturnegg",
469
                        // TRANSLATORS: popup menu item
470
                        // TRANSLATORS: pet return to egg
471
                        _("Return to egg"));
472
                }
473
                mBrowserBox->addSeparator("##3---");
474
            }
475
            else
476
            {
477
                addCatchPetCommands();
478
            }
479
            break;
480
        case ActorType::SkillUnit:
481
        {
482
            const BeingId id = being->getCreatorId();
483
            std::string creatorName;
484
            Being *const creator = actorManager->findBeing(id);
485
            if (creator != nullptr)
486
                creatorName = creator->getName();
487
            else
488
                creatorName = actorManager->getSeenPlayerById(id);
489
490
            if (creatorName.empty())
491
                creatorName = strprintf("?%d", CAST_S32(id));
492
493
            mBrowserBox->addRow(strprintf("%s, %d (%s)",
494
                name.c_str(),
495
                CAST_S32(being->getSubType()),
496
                creatorName.c_str()),
497
                false);
498
            break;
499
        }
500
        case ActorType::Avatar:
501
        case ActorType::Unknown:
502
        case ActorType::FloorItem:
503
        case ActorType::Portal:
504
        case ActorType::Elemental:
505
        default:
506
            break;
507
    }
508
    // TRANSLATORS: popup menu item
509
    // TRANSLATORS: add being name to chat
510
    mBrowserBox->addRow("/addtext 'NAME'", _("Add name to chat"));
511
    mBrowserBox->addSeparator("##3---");
512
513
    // TRANSLATORS: popup menu item
514
    // TRANSLATORS: close menu
515
    mBrowserBox->addRow("cancel", _("Cancel"));
516
517
    showPopup(x, y);
518
}
519
520
bool PopupMenu::addBeingMenu()
521
{
522
    Being *being = actorManager->findBeing(mBeingId);
523
    if (being == nullptr)
524
        return false;
525
526
    BeingInfo *const info = NPCDB::get(fromInt(
527
        being->getSubType(), BeingTypeId));
528
    if (info == nullptr)
529
        return false;
530
531
    const STD_VECTOR<BeingMenuItem> &menu = info->getMenu();
532
    FOR_EACH (STD_VECTOR<BeingMenuItem>::const_iterator, it, menu)
533
    {
534
        const BeingMenuItem &item = *it;
535
        mBrowserBox->addRow("/" + item.command, item.name.c_str());
536
    }
537
    return true;
538
}
539
540
void PopupMenu::setMousePos()
541
{
542
    if (viewport != nullptr)
543
    {
544
        mX = viewport->mMouseX;
545
        mY = viewport->mMouseY;
546
    }
547
    else
548
    {
549
        Gui::getMouseState(mX, mY);
550
    }
551
}
552
553
void PopupMenu::setMousePos2()
554
{
555
    if (mX == 0 && mY == 0)
556
    {
557
        if (viewport != nullptr)
558
        {
559
            mX = viewport->mMouseX;
560
            mY = viewport->mMouseY;
561
        }
562
        else
563
        {
564
            Gui::getMouseState(mX, mY);
565
        }
566
    }
567
}
568
569
void PopupMenu::showPopup(const int x, const int y,
570
                          const STD_VECTOR<ActorSprite*> &beings)
571
{
572
    initPopup();
573
    mX = x;
574
    mY = y;
575
    mBrowserBox->clearRows();
576
    // TRANSLATORS: popup menu header
577
    mBrowserBox->addRow(_("Players"), false);
578
    FOR_EACH (STD_VECTOR<ActorSprite*>::const_iterator, it, beings)
579
    {
580
        const Being *const being = dynamic_cast<const Being*>(*it);
581
        const ActorSprite *const actor = *it;
582
        if ((being != nullptr) && !being->getName().empty())
583
        {
584
            mBrowserBox->addRow(strprintf("@@player_%u|%s >@@",
585
                CAST_U32(being->getId()), (being->getName()
586
                + being->getGenderSignWithSpace()).c_str()),
587
                false);
588
        }
589
        else if (actor->getType() == ActorType::FloorItem)
590
        {
591
            const FloorItem *const floorItem
592
                = static_cast<const FloorItem*>(actor);
593
            mBrowserBox->addRow(strprintf("@@flooritem_%u|%s >@@",
594
                CAST_U32(actor->getId()),
595
                floorItem->getName().c_str()),
596
                false);
597
        }
598
    }
599
    mBrowserBox->addSeparator("##3---");
600
    // TRANSLATORS: popup menu item
601
    // TRANSLATORS: close menu
602
    mBrowserBox->addRow("cancel", _("Cancel"));
603
    showPopup(x, y);
604
}
605
606
void PopupMenu::showPlayerPopup(const std::string &nick)
607
{
608
    if (nick.empty() || (localPlayer == nullptr))
609
        return;
610
611
    initPopup();
612
    setMousePos();
613
    mName = nick;
614
    mExtName = nick;
615
    mBeingId = BeingId_zero;
616
    mType = ActorType::Player;
617
    mSubType = BeingTypeId_zero;
618
    mBrowserBox->clearRows();
619
620
    const std::string &name = mName;
621
622
    mBrowserBox->addRow(name, false);
623
624
    // TRANSLATORS: popup menu item
625
    // TRANSLATORS: send whisper to player
626
    mBrowserBox->addRow("/whispertext 'NAME'", _("Whisper"));
627
    addMailCommands();
628
    addGmCommands();
629
    mBrowserBox->addSeparator("##3---");
630
631
    addPlayerRelation(name);
632
    mBrowserBox->addSeparator("##3---");
633
634
    addFollow();
635
    // TRANSLATORS: popup menu item
636
    // TRANSLATORS: add comment to player
637
    mBrowserBox->addRow("addcomment", _("Add comment"));
638
639
    if (localPlayer->isInParty())
640
    {
641
        const Party *const party = localPlayer->getParty();
642
        if (party != nullptr)
643
        {
644
            const PartyMember *const member = party->getMember(mName);
645
            if (member != nullptr)
646
            {
647
                // TRANSLATORS: popup menu item
648
                // TRANSLATORS: kick player from party
649
                mBrowserBox->addRow("/kickparty 'NAME'", _("Kick from party"));
650
                mBrowserBox->addSeparator("##3---");
651
                const PartyMember *const o = party->getMember(
652
                    localPlayer->getName());
653
                showAdoptCommands();
654
                if ((o != nullptr) && member->getMap() == o->getMap())
655
                {
656
                    // TRANSLATORS: popup menu item
657
                    // TRANSLATORS: move to player position
658
                    mBrowserBox->addRow("/navigate 'X' 'Y'", _("Move"));
659
                }
660
            }
661
        }
662
    }
663
664
    const Guild *const guild2 = localPlayer->getGuild();
665
    if (guild2 != nullptr)
666
    {
667
        if (guild2->getMember(mName) != nullptr)
668
        {
669
#ifdef TMWA_SUPPORT
670
            if (guild2->getServerGuild() || (guildManager != nullptr
671
                && guildManager->havePower()))
672
#endif  // TMWA_SUPPORT
673
            {
674
                mBrowserBox->addRow("/kickguild 'NAME'",
675
                    // TRANSLATORS: popup menu item
676
                    // TRANSLATORS: kick player from guild
677
                    _("Kick from guild"));
678
            }
679
            if (guild2->getServerGuild())
680
            {
681
                mBrowserBox->addRow(strprintf(
682
                    // TRANSLATORS: popup menu item
683
                    // TRANSLATORS: change player position in guild
684
                    "@@guild-pos|%s >@@", _("Change pos in guild")),
685
                    false);
686
            }
687
        }
688
        else
689
        {
690
#ifdef TMWA_SUPPORT
691
            if (guild2->getServerGuild() || (guildManager != nullptr
692
                && guildManager->havePower()))
693
#endif  // TMWA_SUPPORT
694
            {
695
                // TRANSLATORS: popup menu item
696
                // TRANSLATORS: invite player to guild
697
                mBrowserBox->addRow("/guild 'NAME'", _("Invite to guild"));
698
            }
699
        }
700
    }
701
702
    addBuySellDefault();
703
    // TRANSLATORS: popup menu item
704
    // TRANSLATORS: add player name to chat
705
    mBrowserBox->addRow("/addtext 'NAME'", _("Add name to chat"));
706
    mBrowserBox->addSeparator("##3---");
707
    // TRANSLATORS: popup menu item
708
    // TRANSLATORS: close menu
709
    mBrowserBox->addRow("cancel", _("Cancel"));
710
711
    showPopup(mX, mY);
712
}
713
714
void PopupMenu::showPopup(const int x, const int y,
715
                          const FloorItem *const floorItem)
716
{
717
    if (floorItem == nullptr)
718
        return;
719
720
    initPopup();
721
    mX = x;
722
    mY = y;
723
    mFloorItemId = floorItem->getId();
724
    mItemId = floorItem->getItemId();
725
    mType = ActorType::FloorItem;
726
    mSubType = BeingTypeId_zero;
727
    for (int f = 0; f < maxCards; f ++)
728
        mItemCards[f] = floorItem->getCard(f);
729
    mBrowserBox->clearRows();
730
    const std::string name = floorItem->getName();
731
    mName = name;
732
    mExtName = name;
733
734
    mBrowserBox->addRow(name, false);
735
736
    if (config.getBoolValue("enablePickupFilter"))
737
    {
738
        if (actorManager->isInPickupList(name)
739
            || (actorManager->isInPickupList("")
740
            && !actorManager->isInIgnorePickupList(name)))
741
        {
742
            // TRANSLATORS: popup menu item
743
            // TRANSLATORS: pickup item from ground
744
            mBrowserBox->addRow("/pickup 'FLOORID'", _("Pick up"));
745
            mBrowserBox->addSeparator("##3---");
746
        }
747
        addPickupFilter(name);
748
    }
749
    else
750
    {
751
        // TRANSLATORS: popup menu item
752
        // TRANSLATORS: pickup item from ground
753
        mBrowserBox->addRow("/pickup 'FLOORID'", _("Pick up"));
754
    }
755
    addProtection();
756
    // TRANSLATORS: popup menu item
757
    // TRANSLATORS: add item name to chat
758
    mBrowserBox->addRow("/addchat 'FLOORID''CARDS'", _("Add to chat"));
759
    mBrowserBox->addSeparator("##3---");
760
    addGmCommands();
761
762
    // TRANSLATORS: popup menu item
763
    // TRANSLATORS: close menu
764
    mBrowserBox->addRow("cancel", _("Cancel"));
765
766
    showPopup(mX, mY);
767
}
768
769
void PopupMenu::showPopup(const int x, const int y, MapItem *const mapItem)
770
{
771
    if (mapItem == nullptr)
772
        return;
773
774
    initPopup();
775
    mMapItem = mapItem;
776
    mX = x;
777
    mY = y;
778
779
    mBrowserBox->clearRows();
780
781
    // TRANSLATORS: popup menu header
782
    mBrowserBox->addRow(_("Map Item"), false);
783
    // TRANSLATORS: popup menu item
784
    // TRANSLATORS: rename map item
785
    mBrowserBox->addRow("rename map", _("Rename"));
786
    // TRANSLATORS: popup menu item
787
    // TRANSLATORS: remove map item
788
    mBrowserBox->addRow("remove map", _("Remove"));
789
790
    if (isAllowCommand(ServerCommandType::slide))
791
    {
792
        mBrowserBox->addSeparator("##3---");
793
        // TRANSLATORS: popup menu item
794
        // TRANSLATORS: warp to map item
795
        mBrowserBox->addRow("/slide 'MAPX' 'MAPY'", _("Warp"));
796
    }
797
    mBrowserBox->addSeparator("##3---");
798
    // TRANSLATORS: popup menu item
799
    // TRANSLATORS: close menu
800
    mBrowserBox->addRow("cancel", _("Cancel"));
801
802
    showPopup(x, y);
803
}
804
805
void PopupMenu::showMapPopup(const int x, const int y,
806
                             const int x2, const int y2,
807
                             const bool isMinimap)
808
{
809
    initPopup();
810
    mX = x2;
811
    mY = y2;
812
813
    if (isMinimap)
814
        mCallerWindow = minimap;
815
816
    mBrowserBox->clearRows();
817
818
    // TRANSLATORS: popup menu header
819
    mBrowserBox->addRow(_("Map Item"), false);
820
821
    if (isAllowCommand(ServerCommandType::slide))
822
    {
823
        // TRANSLATORS: popup menu item
824
        // TRANSLATORS: warp to map item
825
        mBrowserBox->addRow("/slide 'MAPX' 'MAPY'", _("Warp"));
826
    }
827
    // TRANSLATORS: popup menu item
828
    // TRANSLATORS: move to map item
829
    mBrowserBox->addRow("/navigate 'X' 'Y'", _("Move"));
830
    // TRANSLATORS: popup menu item
831
    // TRANSLATORS: move camera to map item
832
    mBrowserBox->addRow("/movecamera 'X' 'Y'", _("Move camera"));
833
    if (settings.cameraMode != 0)
834
    {
835
        // TRANSLATORS: popup menu item
836
        // TRANSLATORS: restore camera to default view
837
        mBrowserBox->addRow("/restorecamera", _("Restore camera"));
838
    }
839
    mBrowserBox->addSeparator("##3---");
840
    if (isMinimap)
841
    {
842
        // TRANSLATORS: popup menu item
843
        mBrowserBox->addRow("window close", _("Close"));
844
    }
845
    mBrowserBox->addSeparator("##3---");
846
    // TRANSLATORS: popup menu item
847
    // TRANSLATORS: close menu
848
    mBrowserBox->addRow("cancel", _("Cancel"));
849
850
    showPopup(x, y);
851
}
852
853
void PopupMenu::showOutfitsWindowPopup(const int x, const int y)
854
{
855
    initPopup();
856
    mX = x;
857
    mY = y;
858
    mCallerWindow = outfitWindow;
859
860
    mBrowserBox->clearRows();
861
862
    // TRANSLATORS: popup menu header
863
    mBrowserBox->addRow(_("Outfits"), false);
864
    // TRANSLATORS: popup menu item
865
    // TRANSLATORS: copy selected outfit to chat input
866
    mBrowserBox->addRow("/outfittochat", _("Add to chat"));
867
    mBrowserBox->addSeparator("##3---");
868
    // TRANSLATORS: popup menu item
869
    // TRANSLATORS: copy equipment from player to outfit
870
    mBrowserBox->addRow("/itemstooutfit", _("Copy from player"));
871
    mBrowserBox->addSeparator("##3---");
872
    // TRANSLATORS: popup menu item
873
    // TRANSLATORS: clear selected outfit
874
    mBrowserBox->addRow("/clearoutfit", _("Clear outfit"));
875
    mBrowserBox->addSeparator("##3---");
876
877
    addWindowMenu(outfitWindow);
878
    mBrowserBox->addSeparator("##3---");
879
880
    // TRANSLATORS: popup menu item
881
    // TRANSLATORS: close menu
882
    mBrowserBox->addRow("cancel", _("Cancel"));
883
884
    showPopup(x, y);
885
}
886
887
void PopupMenu::showSpellPopup(const int x, const int y,
888
                               TextCommand *const cmd)
889
{
890
    if (cmd == nullptr)
891
        return;
892
893
    initPopup();
894
    mBrowserBox->clearRows();
895
896
    mSpell = cmd;
897
    mX = x;
898
    mY = y;
899
900
    // TRANSLATORS: popup menu header
901
    mBrowserBox->addRow(_("Spells"), false);
902
    // TRANSLATORS: popup menu item
903
    // TRANSLATORS: edit selected spell
904
    mBrowserBox->addRow("edit spell", _("Edit spell"));
905
    mBrowserBox->addSeparator("##3---");
906
    // TRANSLATORS: popup menu item
907
    // TRANSLATORS: close menu
908
    mBrowserBox->addRow("cancel", _("Cancel"));
909
910
    showPopup(x, y);
911
}
912
913
void PopupMenu::showChatPopup(const int x, const int y, ChatTab *const tab)
914
{
915
    if (tab == nullptr ||
916
        actorManager == nullptr ||
917
        localPlayer == nullptr)
918
    {
919
        return;
920
    }
921
922
    initPopup();
923
    mTab = tab;
924
    mX = x;
925
    mY = y;
926
    mCallerWindow = chatWindow;
927
928
    mBrowserBox->clearRows();
929
930
    const ChatTabTypeT &type = tab->getType();
931
    if (type == ChatTabType::WHISPER || type == ChatTabType::CHANNEL)
932
    {
933
        // TRANSLATORS: popup menu item
934
        // TRANSLATORS: close chat tab
935
        mBrowserBox->addRow("/close", _("Close"));
936
    }
937
938
    // TRANSLATORS: popup menu item
939
    // TRANSLATORS: remove all text from chat tab
940
    mBrowserBox->addRow("/chatclear", _("Clear"));
941
    mBrowserBox->addSeparator("##3---");
942
943
    if (tab->getAllowHighlight())
944
    {
945
        // TRANSLATORS: popup menu item
946
        // TRANSLATORS: disable chat tab highlight
947
        mBrowserBox->addRow("/disablehighlight", _("Disable highlight"));
948
    }
949
    else
950
    {
951
        // TRANSLATORS: popup menu item
952
        // TRANSLATORS: enable chat tab highlight
953
        mBrowserBox->addRow("/enablehighlight", _("Enable highlight"));
954
    }
955
    if (tab->getRemoveNames())
956
    {
957
        // TRANSLATORS: popup menu item
958
        // TRANSLATORS: do not remove player names from chat tab
959
        mBrowserBox->addRow("/dontremovename", _("Don't remove name"));
960
    }
961
    else
962
    {
963
        // TRANSLATORS: popup menu item
964
        // TRANSLATORS: remove player names from chat tab
965
        mBrowserBox->addRow("/removename", _("Remove name"));
966
    }
967
    if (tab->getNoAway())
968
    {
969
        // TRANSLATORS: popup menu item
970
        // TRANSLATORS: enable away messages in chat tab
971
        mBrowserBox->addRow("/enableaway", _("Enable away"));
972
    }
973
    else
974
    {
975
        // TRANSLATORS: popup menu item
976
        // TRANSLATORS: disable away messages in chat tab
977
        mBrowserBox->addRow("/disableaway", _("Disable away"));
978
    }
979
    mBrowserBox->addSeparator("##3---");
980
    if (type == ChatTabType::PARTY)
981
    {
982
        // TRANSLATORS: popup menu item
983
        // TRANSLATORS: enable away messages in chat tab
984
        mBrowserBox->addRow("/leaveparty", _("Leave"));
985
        mBrowserBox->addSeparator("##3---");
986
    }
987
    // TRANSLATORS: popup menu item
988
    // TRANSLATORS: copy selected text to clipboard
989
    mBrowserBox->addRow("/chatclipboard 'X' 'Y'", _("Copy to clipboard"));
990
    mBrowserBox->addSeparator("##3---");
991
992
    if (type == ChatTabType::WHISPER)
993
    {
994
        const WhisperTab *const wTab = static_cast<WhisperTab*>(tab);
995
        const std::string &name = wTab->getNick();
996
997
        const Being* const being  = actorManager->findBeingByName(
998
            name, ActorType::Player);
999
1000
        addGmCommands();
1001
        if (being != nullptr)
1002
        {
1003
            mBeingId = being->getId();
1004
            mName = being->getName();
1005
            mExtName = being->getExtName();
1006
            mType = being->getType();
1007
            mSubType = being->getSubType();
1008
1009
            // TRANSLATORS: popup menu item
1010
            // TRANSLATORS: trade with player
1011
            mBrowserBox->addRow("/trade 'NAME'", _("Trade"));
1012
            // TRANSLATORS: popup menu item
1013
            // TRANSLATORS: attack player
1014
            mBrowserBox->addRow("/attack 'NAME'", _("Attack"));
1015
            addMailCommands();
1016
            mBrowserBox->addSeparator("##3---");
1017
            // TRANSLATORS: popup menu item
1018
            // TRANSLATORS: heal player
1019
            mBrowserBox->addRow("/heal :'BEINGID'", _("Heal"));
1020
            mBrowserBox->addSeparator("##3---");
1021
            addPlayerRelation(name);
1022
            mBrowserBox->addSeparator("##3---");
1023
            addFollow();
1024
            // TRANSLATORS: popup menu item
1025
            // TRANSLATORS: move to player position
1026
            mBrowserBox->addRow("/navigateto 'NAME'", _("Move"));
1027
            addPlayerMisc();
1028
            addBuySell(being);
1029
            mBrowserBox->addSeparator("##3---");
1030
            addParty(wTab->getNick());
1031
            const Guild *const guild1 = being->getGuild();
1032
            const Guild *const guild2 = localPlayer->getGuild();
1033
            if (guild2 != nullptr)
1034
            {
1035
                if (guild1 != nullptr)
1036
                {
1037
                    if (guild1->getId() == guild2->getId())
1038
                    {
1039
#ifdef TMWA_SUPPORT
1040
                        if (guild2->getServerGuild() ||
1041
                            (guildManager != nullptr &&
1042
                            guildManager->havePower()))
1043
#endif  // TMWA_SUPPORT
1044
                        {
1045
                            mBrowserBox->addRow("/kickguild 'NAME'",
1046
                                // TRANSLATORS: popup menu item
1047
                                // TRANSLATORS: kick player from guild
1048
                                _("Kick from guild"));
1049
                        }
1050
                        if (guild2->getServerGuild())
1051
                        {
1052
                            mBrowserBox->addRow(strprintf("@@guild-pos|%s >@@",
1053
                                // TRANSLATORS: popup menu item
1054
                                // TRANSLATORS: change player position in guild
1055
                                 _("Change pos in guild")),
1056
                                false);
1057
                        }
1058
                    }
1059
                }
1060
                else
1061
                {
1062
#ifdef TMWA_SUPPORT
1063
                    if (guild2->getServerGuild() || (guildManager != nullptr
1064
                        && guildManager->havePower()))
1065
#endif  // TMWA_SUPPORT
1066
                    {
1067
                        mBrowserBox->addRow("/guild 'NAME'",
1068
                            // TRANSLATORS: popup menu item
1069
                            // TRANSLATORS: invite player to guild
1070
                            _("Invite to guild"));
1071
                    }
1072
                }
1073
            }
1074
        }
1075
        else
1076
        {
1077
            mBeingId = BeingId_zero;
1078
            mName = name;
1079
            mExtName = name;
1080
            mType = ActorType::Player;
1081
            mSubType = BeingTypeId_zero;
1082
            addPlayerRelation(name);
1083
            mBrowserBox->addSeparator("##3---");
1084
            addMailCommands();
1085
            addFollow();
1086
1087
            if (localPlayer->isInParty())
1088
            {
1089
                const Party *const party = localPlayer->getParty();
1090
                if (party != nullptr)
1091
                {
1092
                    const PartyMember *const m = party->getMember(mName);
1093
                    if (m != nullptr)
1094
                    {
1095
                        // TRANSLATORS: popup menu item
1096
                        // TRANSLATORS: move to player location
1097
                        mBrowserBox->addRow("/navigateto 'NAME'", _("Move"));
1098
                    }
1099
                }
1100
            }
1101
            addPlayerMisc();
1102
            addBuySellDefault();
1103
            if (Net::getNetworkType() != ServerType::TMWATHENA)
1104
                addParty(wTab->getNick());
1105
            mBrowserBox->addSeparator("##3---");
1106
        }
1107
    }
1108
1109
    addWindowMenu(chatWindow);
1110
    // TRANSLATORS: popup menu item
1111
    // TRANSLATORS: close menu
1112
    mBrowserBox->addRow("cancel", _("Cancel"));
1113
1114
    showPopup(x, y);
1115
}
1116
1117
void PopupMenu::showChangePos(const int x, const int y)
1118
{
1119
    initPopup();
1120
    mBrowserBox->clearRows();
1121
    // TRANSLATORS: popup menu header
1122
    mBrowserBox->addRow(_("Change guild position"), false);
1123
1124
    if (localPlayer == nullptr)
1125
        return;
1126
1127
    mX = x;
1128
    mY = y;
1129
    const Guild *const guild = localPlayer->getGuild();
1130
    if (guild != nullptr)
1131
    {
1132
        const PositionsMap &map = guild->getPositions();
1133
        FOR_EACH (PositionsMap::const_iterator, itr, map)
1134
        {
1135
            mBrowserBox->addRow(strprintf("@@guild-pos-%u|%s@@",
1136
                itr->first, itr->second.c_str()),
1137
                false);
1138
        }
1139
        // TRANSLATORS: popup menu item
1140
        // TRANSLATORS: close menu
1141
        mBrowserBox->addRow("cancel", _("Cancel"));
1142
1143
        showPopup(x, y);
1144
    }
1145
    else
1146
    {
1147
        mBeingId = BeingId_zero;
1148
        mFloorItemId = BeingId_zero;
1149
        mItemIndex = -1;
1150
        mItemId = 0;
1151
        for (int f = 0; f < maxCards; f ++)
1152
            mItemCards[f] = 0;
1153
        mMapItem = nullptr;
1154
        mName.clear();
1155
        mExtName.clear();
1156
        mType = ActorType::Unknown;
1157
        mSubType = BeingTypeId_zero;
1158
        mX = 0;
1159
        mY = 0;
1160
        setVisible(Visible_false);
1161
    }
1162
}
1163
1164
void PopupMenu::showWindowPopup(Window *const window)
1165
{
1166
    if (window == nullptr)
1167
        return;
1168
1169
    initPopup();
1170
    setMousePos();
1171
    mCallerWindow = window;
1172
    mBrowserBox->clearRows();
1173
    // TRANSLATORS: popup menu header
1174
    mBrowserBox->addRow(_("window"), false);
1175
1176
    addWindowMenu(window);
1177
1178
    // TRANSLATORS: popup menu item
1179
    // TRANSLATORS: close menu
1180
    mBrowserBox->addRow("cancel", _("Cancel"));
1181
1182
    showPopup(mX, mY);
1183
}
1184
1185
void PopupMenu::addWindowMenu(const Window *const window)
1186
{
1187
    if (window == nullptr)
1188
        return;
1189
1190
    initPopup();
1191
    if (window->getAlowClose())
1192
    {
1193
        // TRANSLATORS: popup menu item
1194
        // TRANSLATORS: close window
1195
        mBrowserBox->addRow("window close", _("Close"));
1196
    }
1197
1198
    if (window->isStickyButtonLock())
1199
    {
1200
        if (window->isSticky())
1201
        {
1202
            // TRANSLATORS: popup menu item
1203
            // TRANSLATORS: unlock window
1204
            mBrowserBox->addRow("window unlock", _("Unlock"));
1205
        }
1206
        else
1207
        {
1208
            // TRANSLATORS: popup menu item
1209
            // TRANSLATORS: lock window
1210
            mBrowserBox->addRow("window lock", _("Lock"));
1211
        }
1212
    }
1213
}
1214
1215
void PopupMenu::showEmoteType()
1216
{
1217
    initPopup();
1218
    setMousePos();
1219
1220
    mBrowserBox->clearRows();
1221
    // TRANSLATORS: popup menu header
1222
    mBrowserBox->addRow(_("Show emotes for:"), false);
1223
1224
    // TRANSLATORS: popup menu item
1225
    // TRANSLATORS: show emotes for player
1226
    mBrowserBox->addRow("/setemotetype player", _("Player"));
1227
1228
    // TRANSLATORS: popup menu item
1229
    // TRANSLATORS: show emotes for pet
1230
    mBrowserBox->addRow("/setemotetype pet", _("Pet"));
1231
1232
    if (Net::getNetworkType() == ServerType::EVOL2)
1233
    {
1234
        // TRANSLATORS: popup menu item
1235
        // TRANSLATORS: show emotes for homuncules
1236
        mBrowserBox->addRow("/setemotetype homun", _("Homunculus"));
1237
1238
        // TRANSLATORS: popup menu item
1239
        // TRANSLATORS: show emotes for mercenary
1240
        mBrowserBox->addRow("/setemotetype merc", _("Mercenary"));
1241
    }
1242
    mBrowserBox->addSeparator("##3---");
1243
1244
    // TRANSLATORS: popup menu item
1245
    // TRANSLATORS: close menu
1246
    mBrowserBox->addRow("cancel", _("Cancel"));
1247
1248
    showPopup(mX, mY);
1249
}
1250
1251
void PopupMenu::handleLink(const std::string &link,
1252
                           MouseEvent *event A_UNUSED)
1253
{
1254
    Being *being = nullptr;
1255
    if (actorManager != nullptr)
1256
        being = actorManager->findBeing(mBeingId);
1257
1258
    mAllowCleanMenu = true;
1259
1260
    if (link == "remove map" && (mMapItem != nullptr))
1261
    {
1262
        if (viewport != nullptr)
1263
        {
1264
            const Map *const map = viewport->getMap();
1265
            if (map != nullptr)
1266
            {
1267
                SpecialLayer *const specialLayer = map->getSpecialLayer();
1268
                if (specialLayer != nullptr)
1269
                {
1270
                    const bool isHome = (mMapItem->getType()
1271
                        == CAST_S32(MapItemType::HOME));
1272
                    const int x = static_cast<int>(mMapItem->getX());
1273
                    const int y = static_cast<int>(mMapItem->getY());
1274
                    specialLayer->setTile(x, y,
1275
                        CAST_S32(MapItemType::EMPTY));
1276
                    specialLayer->updateCache();
1277
                    if (socialWindow != nullptr)
1278
                        socialWindow->removePortal(x, y);
1279
                    if (isHome && (localPlayer != nullptr))
1280
                    {
1281
                        localPlayer->removeHome();
1282
                        localPlayer->saveHomes();
1283
                    }
1284
                }
1285
            }
1286
        }
1287
    }
1288
    else if (link == "rename map" && (mMapItem != nullptr))
1289
    {
1290
        mRenameListener.setMapItem(mMapItem);
1291
        CREATEWIDGETV(mDialog, TextDialog,
1292
            // TRANSLATORS: dialog caption
1293
            // TRANSLATORS: number of chars in string should be near original
1294
            _("Rename map sign          "),
1295
            // TRANSLATORS: label
1296
            // TRANSLATORS: number of chars in string should be near original
1297
            _("Name:                    "),
1298
            nullptr,
1299
            false);
1300
        mRenameListener.setDialog(mDialog);
1301
        mDialog->setText(mMapItem->getComment());
1302
        mDialog->setActionEventId("ok");
1303
        mDialog->addActionListener(&mRenameListener);
1304
    }
1305
    else if (link == "edit spell" && (mSpell != nullptr))
1306
    {
1307
        CREATEWIDGET(TextCommandEditor, mSpell);
1308
    }
1309
    else if (link == "addcomment" && !mName.empty())
1310
    {
1311
        TextDialog *const dialog = CREATEWIDGETR(TextDialog,
1312
            // TRANSLATORS: dialog caption
1313
            // TRANSLATORS: number of chars in string should be near original
1314
            _("Player comment            "),
1315
            // TRANSLATORS: label
1316
            // TRANSLATORS: number of chars in string should be near original
1317
            _("Comment:                      "),
1318
            nullptr,
1319
            false);
1320
        mPlayerListener.setDialog(dialog);
1321
        mPlayerListener.setNick(mName);
1322
        mPlayerListener.setType(mType);
1323
1324
        if (being != nullptr)
1325
        {
1326
            being->updateComment();
1327
            dialog->setText(being->getComment());
1328
        }
1329
        else
1330
        {
1331
            dialog->setText(Being::loadComment(mName,
1332
                static_cast<ActorTypeT>(mType)));
1333
        }
1334
        dialog->setActionEventId("ok");
1335
        dialog->addActionListener(&mPlayerListener);
1336
    }
1337
    else if (link == "guild-pos" && !mName.empty())
1338
    {
1339
        showChangePos(getX(), getY());
1340
        return;
1341
    }
1342
    else if (link == "clipboard copy")
1343
    {
1344
        if (mTextField != nullptr)
1345
            mTextField->handleCopy();
1346
    }
1347
    else if (link == "clipboard paste")
1348
    {
1349
        if (mTextField != nullptr)
1350
            mTextField->handlePaste();
1351
    }
1352
    else if (link == "gm" && !mName.empty())
1353
    {
1354
        showGMPopup(mName);
1355
        return;
1356
    }
1357
    else if (link == "mute" && !mName.empty())
1358
    {
1359
        showMuteCommands();
1360
        return;
1361
    }
1362
    else if (link == "show" && !mName.empty())
1363
    {
1364
        showPlayerMenu();
1365
        return;
1366
    }
1367
    else if (link == "window close" && (mCallerWindow != nullptr))
1368
    {
1369
        if (Widget::widgetExists(mCallerWindow))
1370
            mCallerWindow->close();
1371
    }
1372
    else if (link == "window unlock" && (mCallerWindow != nullptr))
1373
    {
1374
        if (Widget::widgetExists(mCallerWindow))
1375
            mCallerWindow->setSticky(false);
1376
    }
1377
    else if (link == "window lock" && (mCallerWindow != nullptr))
1378
    {
1379
        if (Widget::widgetExists(mCallerWindow))
1380
            mCallerWindow->setSticky(true);
1381
    }
1382
    else if (link == "join chat" && (being != nullptr))
1383
    {
1384
        const ChatObject *const chat = being->getChat();
1385
        if (chat != nullptr)
1386
            chatHandler->joinChat(chat, "");
1387
    }
1388
    else if (link == "craftmenu")
1389
    {
1390
        showCraftPopup();
1391
        return;
1392
    }
1393
    else if (link.compare(0, 10, "guild-pos-") == 0)
1394
    {
1395
        if (localPlayer != nullptr)
1396
        {
1397
            const Guild *const guild = localPlayer->getGuild();
1398
            if (guild != nullptr)
1399
            {
1400
                const int num = atoi(link.substr(10).c_str());
1401
                guildHandler->changeMemberPostion(
1402
                    guild->getMember(mName), num);
1403
            }
1404
        }
1405
    }
1406
    else if (link.compare(0, 7, "player_") == 0)
1407
    {
1408
        if (actorManager != nullptr)
1409
        {
1410
            mBeingId = fromInt(atoi(link.substr(7).c_str()), BeingId);
1411
            being = actorManager->findBeing(mBeingId);
1412
            if (being != nullptr)
1413
            {
1414
                showPopup(getX(), getY(), being);
1415
                return;
1416
            }
1417
        }
1418
    }
1419
    else if (link.compare(0, 10, "flooritem_") == 0)
1420
    {
1421
        if (actorManager != nullptr)
1422
        {
1423
            const BeingId id = fromInt(atoi(
1424
                link.substr(10).c_str()), BeingId);
1425
            if (id != BeingId_zero)
1426
            {
1427
                const FloorItem *const item = actorManager->findItem(id);
1428
                if (item != nullptr)
1429
                {
1430
                    mFloorItemId = item->getId();
1431
                    mItemId = item->getItemId();
1432
                    for (int f = 0; f < maxCards; f ++)
1433
                        mItemCards[f] = item->getCard(f);
1434
                    showPopup(getX(), getY(), item);
1435
                    return;
1436
                }
1437
            }
1438
        }
1439
    }
1440
    else if (link.compare(0, 12, "hide button_") == 0)
1441
    {
1442
        if (windowMenu != nullptr)
1443
            windowMenu->showButton(link.substr(12), Visible_false);
1444
    }
1445
    else if (link.compare(0, 12, "show button_") == 0)
1446
    {
1447
        if (windowMenu != nullptr)
1448
            windowMenu->showButton(link.substr(12), Visible_true);
1449
    }
1450
    else if (link.compare(0, 9, "hide bar_") == 0)
1451
    {
1452
        if (miniStatusWindow != nullptr)
1453
            miniStatusWindow->showBar(link.substr(9), Visible_false);
1454
    }
1455
    else if (link.compare(0, 9, "show bar_") == 0)
1456
    {
1457
        if (miniStatusWindow != nullptr)
1458
            miniStatusWindow->showBar(link.substr(9), Visible_true);
1459
    }
1460
    else if (link.compare(0, 12, "show window_") == 0)
1461
    {
1462
        const int id = atoi(link.substr(12).c_str());
1463
        if (id >= 0)
1464
            inputManager.executeAction(static_cast<InputActionT>(id));
1465
    }
1466
    else if (link.compare(0, 6, "mute_+") == 0)
1467
    {
1468
        if (being != nullptr)
1469
        {
1470
            const int time = atoi(link.substr(6).c_str());
1471
            adminHandler->mute(being, 1, time);
1472
        }
1473
    }
1474
    else if (link.compare(0, 6, "mute_-") == 0)
1475
    {
1476
        if (being != nullptr)
1477
        {
1478
            const int time = atoi(link.substr(6).c_str());
1479
            adminHandler->mute(being, 0, time);
1480
        }
1481
    }
1482
    else if (!link.empty() && link[0] == '/')
1483
    {
1484
        std::string cmd = link.substr(1);
1485
        replaceAll(cmd, "'NAME'", mName);
1486
        replaceAll(cmd, "'ENAME'", escapeString(mName));
1487
        replaceAll(cmd, "'EXTNAME'", mExtName);
1488
        replaceAll(cmd, "'EEXTNAME'", escapeString(mExtName));
1489
        replaceAll(cmd, "'X'", toString(mX));
1490
        replaceAll(cmd, "'Y'", toString(mY));
1491
        replaceAll(cmd, "'BEINGID'", toString(toInt(mBeingId, int)));
1492
        replaceAll(cmd, "'FLOORID'", toString(toInt(mFloorItemId, int)));
1493
        replaceAll(cmd, "'ITEMID'", toString(mItemId));
1494
        replaceAll(cmd, "'ITEMCOLOR'", toString(toInt(mItemColor, int)));
1495
        replaceAll(cmd, "'BEINGTYPEID'", toString(CAST_S32(mType)));
1496
        replaceAll(cmd, "'BEINGSUBTYPEID'", toString(CAST_S32(mSubType)));
1497
        replaceAll(cmd, "'PLAYER'", localPlayer->getName());
1498
        replaceAll(cmd, "'EPLAYER'", escapeString(localPlayer->getName()));
1499
        replaceAll(cmd, "'PLAYERX'", toString(localPlayer->getTileX()));
1500
        replaceAll(cmd, "'PLAYERY'", toString(localPlayer->getTileY()));
1501
        if (mItemIndex >= 0)
1502
            replaceAll(cmd, "'INVINDEX'", toString(mItemIndex));
1503
        else
1504
            replaceAll(cmd, "'INVINDEX'", "0");
1505
        if (mMapItem != nullptr)
1506
        {
1507
            replaceAll(cmd, "'MAPX'", toString(mMapItem->getX()));
1508
            replaceAll(cmd, "'MAPY'", toString(mMapItem->getY()));
1509
        }
1510
        else
1511
        {
1512
            replaceAll(cmd, "'MAPX'", toString(mX));
1513
            replaceAll(cmd, "'MAPY'", toString(mY));
1514
        }
1515
1516
        std::string cards;
1517
        for (int f = 0; f < maxCards; f ++)
1518
        {
1519
            const int id = mItemCards[f];
1520
            if (id != 0)
1521
            {
1522
                cards.append(",");
1523
                cards.append(toString(id));
1524
            }
1525
        }
1526
        replaceAll(cmd, "'CARDS'", cards);
1527
        replaceAll(cmd, "'ECARDS'", escapeString(cards));
1528
        if (actorManager != nullptr)
1529
        {
1530
            if (being == nullptr)
1531
            {
1532
                being = actorManager->findBeingByName(mName,
1533
                    ActorType::Player);
1534
            }
1535
        }
1536
        if (being != nullptr)
1537
            replaceAll(cmd, "'PARTY'", being->getPartyName());
1538
        else
1539
            replaceAll(cmd, "'PARTY'", "");
1540
1541
        const size_t pos = cmd.find(' ');
1542
        const std::string type(cmd, 0, pos);
1543
        std::string args(cmd, pos == std::string::npos ? cmd.size() : pos + 1);
1544
        args = trim(args);
1545
        inputManager.executeChatCommand(type, args, mTab);
1546
    }
1547
    // Unknown actions
1548
    else if (link != "cancel")
1549
    {
1550
        reportAlways("PopupMenu: Warning, unknown action '%s'", link.c_str())
1551
    }
1552
1553
    if (!mAllowCleanMenu)
1554
        return;
1555
1556
    setVisible(Visible_false);
1557
1558
    mBeingId = BeingId_zero;
1559
    mFloorItemId = BeingId_zero;
1560
    mItemId = 0;
1561
    mItemIndex = -1;
1562
    for (int f = 0; f < maxCards; f ++)
1563
        mItemCards[f] = 0;
1564
    mItemColor = ItemColor_one;
1565
    mMapItem = nullptr;
1566
    mTab = nullptr;
1567
    mSpell = nullptr;
1568
    mCallerWindow = nullptr;
1569
    mDialog = nullptr;
1570
    mButton = nullptr;
1571
    mName.clear();
1572
    mExtName.clear();
1573
    mTextField = nullptr;
1574
    mType = ActorType::Unknown;
1575
    mSubType = BeingTypeId_zero;
1576
    mX = 0;
1577
    mY = 0;
1578
}
1579
1580
void PopupMenu::showPopup(Window *const parent,
1581
                          const int x, const int y,
1582
                          const Item *const item,
1583
                          const InventoryTypeT type)
1584
{
1585
    if (item == nullptr)
1586
        return;
1587
1588
    initPopup();
1589
    mItemId = item->getId();
1590
    mItemIndex = item->getInvIndex();
1591
    for (int f = 0; f < maxCards; f ++)
1592
        mItemCards[f] = item->getCard(f);
1593
    mItemColor = item->getColor();
1594
    mCallerWindow = parent;
1595
    mX = x;
1596
    mY = y;
1597
    mName.clear();
1598
    mExtName.clear();
1599
    mBrowserBox->clearRows();
1600
1601
    const int cnt = item->getQuantity();
1602
    const bool isProtected = PlayerInfo::isItemProtected(mItemId);
1603
1604
    switch (type)
1605
    {
1606
        case InventoryType::Inventory:
1607
            if (tradeWindow != nullptr &&
1608
                tradeWindow->isWindowVisible() &&
1609
                !isProtected)
1610
            {
1611
                // TRANSLATORS: popup menu item
1612
                // TRANSLATORS: add item to trade
1613
                mBrowserBox->addRow("/addtrade 'INVINDEX'", _("Add to trade"));
1614
                if (cnt > 1)
1615
                {
1616
                    if (cnt > 10)
1617
                    {
1618
                        mBrowserBox->addRow("/addtrade 'INVINDEX' 10",
1619
                            // TRANSLATORS: popup menu item
1620
                            // TRANSLATORS: add 10 item amount to trade
1621
                            _("Add to trade 10"));
1622
                    }
1623
                    mBrowserBox->addRow("/addtrade 'INVINDEX' /",
1624
                        // TRANSLATORS: popup menu item
1625
                        // TRANSLATORS: add half item amount to trade
1626
                        _("Add to trade half"));
1627
                    mBrowserBox->addRow("/addtrade 'INVINDEX' -1",
1628
                        // TRANSLATORS: popup menu item
1629
                        // TRANSLATORS: add all amount except one item to trade
1630
                        _("Add to trade all-1"));
1631
                    mBrowserBox->addRow("/addtrade 'INVINDEX' all",
1632
                        // TRANSLATORS: popup menu item
1633
                        // TRANSLATORS: add all amount item to trade
1634
                        _("Add to trade all"));
1635
                }
1636
                mBrowserBox->addSeparator("##3---");
1637
            }
1638
            if (InventoryWindow::isStorageActive())
1639
            {
1640
                // TRANSLATORS: popup menu item
1641
                // TRANSLATORS: add item to storage
1642
                mBrowserBox->addRow("/invtostorage 'INVINDEX'", _("Store"));
1643
                if (cnt > 1)
1644
                {
1645
                    if (cnt > 10)
1646
                    {
1647
                        mBrowserBox->addRow("/invtostorage 'INVINDEX' 10",
1648
                            // TRANSLATORS: popup menu item
1649
                            // TRANSLATORS: add 10 item amount to storage
1650
                            _("Store 10"));
1651
                    }
1652
                    mBrowserBox->addRow("/invtostorage 'INVINDEX' /",
1653
                        // TRANSLATORS: popup menu item
1654
                        // TRANSLATORS: add half item amount to storage
1655
                        _("Store half"));
1656
                    mBrowserBox->addRow("/invtostorage 'INVINDEX' -1",
1657
                        // TRANSLATORS: popup menu item
1658
                        // TRANSLATORS: add all except one item to storage
1659
                        _("Store all-1"));
1660
                    mBrowserBox->addRow("/invtostorage 'INVINDEX' all",
1661
                        // TRANSLATORS: popup menu item
1662
                        // TRANSLATORS: add all item amount to storage
1663
                        _("Store all"));
1664
                }
1665
                mBrowserBox->addSeparator("##3---");
1666
            }
1667
            if (npcHandler != nullptr)
1668
            {
1669
                NpcDialog *const dialog = npcHandler->getCurrentNpcDialog();
1670
                if ((dialog != nullptr) &&
1671
                    dialog->getInputState() == NpcInputState::ITEM_CRAFT)
1672
                {
1673
                    mBrowserBox->addRow("craftmenu",
1674
                        // TRANSLATORS: popup menu item
1675
                        // TRANSLATORS: sub menu for craft
1676
                        _("Move to craft..."));
1677
                }
1678
            }
1679
            addItemMenu(item, InventoryType::Inventory);
1680
            addDrop(item, isProtected);
1681
            break;
1682
1683
        case InventoryType::Storage:
1684
            // TRANSLATORS: popup menu item
1685
            // TRANSLATORS: get item from storage
1686
            mBrowserBox->addRow("/storagetoinv 'INVINDEX'", _("Retrieve"));
1687
            if (cnt > 1)
1688
            {
1689
                if (cnt > 10)
1690
                {
1691
                    mBrowserBox->addRow("/storagetoinv 'INVINDEX' 10",
1692
                        // TRANSLATORS: popup menu item
1693
                        // TRANSLATORS: get 10 item amount from storage
1694
                        _("Retrieve 10"));
1695
                }
1696
                mBrowserBox->addRow("/storagetoinv 'INVINDEX' /",
1697
                    // TRANSLATORS: popup menu item
1698
                    // TRANSLATORS: get half item amount from storage
1699
                    _("Retrieve half"));
1700
                mBrowserBox->addRow("/storagetoinv 'INVINDEX' -1",
1701
                    // TRANSLATORS: popup menu item
1702
                    // TRANSLATORS: get all except one item amount from storage
1703
                    _("Retrieve all-1"));
1704
                mBrowserBox->addRow("/storagetoinv 'INVINDEX' all",
1705
                    // TRANSLATORS: popup menu item
1706
                    // TRANSLATORS: get all item amount from storage
1707
                    _("Retrieve all"));
1708
                mBrowserBox->addSeparator("##3---");
1709
            }
1710
            addItemMenu(item, InventoryType::Storage);
1711
            break;
1712
        case InventoryType::Cart:
1713
            addItemMenu(item, InventoryType::Cart);
1714
            break;
1715
1716
        case InventoryType::Trade:
1717
        case InventoryType::Npc:
1718
        case InventoryType::Vending:
1719
        case InventoryType::MailEdit:
1720
        case InventoryType::MailView:
1721
        case InventoryType::Craft:
1722
        case InventoryType::TypeEnd:
1723
        default:
1724
            break;
1725
    }
1726
1727
1728
    addProtection();
1729
    if (config.getBoolValue("enablePickupFilter"))
1730
    {
1731
        mName = item->getName();
1732
        mExtName = mName;
1733
        mBrowserBox->addSeparator("##3---");
1734
        addPickupFilter(mName);
1735
    }
1736
    addGmCommands();
1737
    // TRANSLATORS: popup menu item
1738
    // TRANSLATORS: add item name to chat
1739
    mBrowserBox->addRow("/addchat 'ITEMID''CARDS'", _("Add to chat"));
1740
    mBrowserBox->addSeparator("##3---");
1741
    // TRANSLATORS: popup menu item
1742
    // TRANSLATORS: close menu
1743
    mBrowserBox->addRow("cancel", _("Cancel"));
1744
1745
    showPopup(x, y);
1746
}
1747
1748
void PopupMenu::showItemPopup(const int x, const int y,
1749
                              const int itemId,
1750
                              const ItemColor color)
1751
{
1752
    const Inventory *const inv = PlayerInfo::getInventory();
1753
    if (inv == nullptr)
1754
        return;
1755
1756
    Item *const item = inv->findItem(itemId, color);
1757
    if (item != nullptr)
1758
    {
1759
        showItemPopup(x, y, item);
1760
    }
1761
    else
1762
    {
1763
        initPopup();
1764
        mItemId = itemId;
1765
        mItemIndex = -1;
1766
        mItemColor = color;
1767
        for (int f = 0; f < maxCards; f ++)
1768
            mItemCards[f] = 0;
1769
        mX = x;
1770
        mY = y;
1771
        mBrowserBox->clearRows();
1772
1773
        if (!PlayerInfo::isItemProtected(mItemId))
1774
        {
1775
            // TRANSLATORS: popup menu item
1776
            // TRANSLATORS: use item
1777
            mBrowserBox->addRow("/use 'ITEMID'", _("Use"));
1778
        }
1779
        addProtection();
1780
        addGmCommands();
1781
        mBrowserBox->addSeparator("##3---");
1782
        // TRANSLATORS: popup menu item
1783
        // TRANSLATORS: close menu
1784
        mBrowserBox->addRow("cancel", _("Cancel"));
1785
1786
        showPopup(x, y);
1787
    }
1788
}
1789
1790
void PopupMenu::showItemPopup(const int x, const int y,
1791
                              const Item *const item)
1792
{
1793
    initPopup();
1794
    mX = x;
1795
    mY = y;
1796
    if (item != nullptr)
1797
    {
1798
        mItemId = item->getId();
1799
        mItemColor = item->getColor();
1800
        mItemIndex = item->getInvIndex();
1801
        for (int f = 0; f < maxCards; f ++)
1802
            mItemCards[f] = item->getCard(f);
1803
    }
1804
    else
1805
    {
1806
        mItemId = 0;
1807
        mItemColor = ItemColor_one;
1808
        mItemIndex = -1;
1809
        for (int f = 0; f < maxCards; f ++)
1810
            mItemCards[f] = 0;
1811
    }
1812
    mName.clear();
1813
    mExtName.clear();
1814
    mBrowserBox->clearRows();
1815
1816
    if (item != nullptr)
1817
    {
1818
        const bool isProtected = PlayerInfo::isItemProtected(mItemId);
1819
        addUse(item);
1820
        addDrop(item, isProtected);
1821
        if (InventoryWindow::isStorageActive())
1822
        {
1823
            // TRANSLATORS: popup menu item
1824
            // TRANSLATORS: add item to storage
1825
            mBrowserBox->addRow("/invtostorage 'INVINDEX'", _("Store"));
1826
        }
1827
        // TRANSLATORS: popup menu item
1828
        // TRANSLATORS: add item name to chat
1829
        mBrowserBox->addRow("/addchat 'ITEMID''CARDS'", _("Add to chat"));
1830
1831
        if (config.getBoolValue("enablePickupFilter"))
1832
        {
1833
            mName = item->getName();
1834
            mExtName = mName;
1835
            mBrowserBox->addSeparator("##3---");
1836
            addPickupFilter(mName);
1837
        }
1838
    }
1839
    addProtection();
1840
    addGmCommands();
1841
    mBrowserBox->addSeparator("##3---");
1842
    // TRANSLATORS: popup menu item
1843
    // TRANSLATORS: close menu
1844
    mBrowserBox->addRow("cancel", _("Cancel"));
1845
1846
    showPopup(x, y);
1847
}
1848
1849
void PopupMenu::showDropPopup(const int x,
1850
                              const int y,
1851
                              const Item *const item)
1852
{
1853
    initPopup();
1854
    mX = x;
1855
    mY = y;
1856
    mName.clear();
1857
    mExtName.clear();
1858
    mBrowserBox->clearRows();
1859
1860
    if (item != nullptr)
1861
    {
1862
        mItemId = item->getId();
1863
        mItemColor = item->getColor();
1864
        mItemIndex = item->getInvIndex();
1865
        for (int f = 0; f < maxCards; f ++)
1866
            mItemCards[f] = item->getCard(f);
1867
        const bool isProtected = PlayerInfo::isItemProtected(mItemId);
1868
        addUse(item);
1869
        addDrop(item, isProtected);
1870
        if (InventoryWindow::isStorageActive())
1871
        {
1872
            // TRANSLATORS: popup menu item
1873
            // TRANSLATORS: add item to storage
1874
            mBrowserBox->addRow("/invtostorage 'INVINDEX'", _("Store"));
1875
        }
1876
        addProtection();
1877
        // TRANSLATORS: popup menu item
1878
        // TRANSLATORS: add item name to chat
1879
        mBrowserBox->addRow("/addchat 'ITEMID''CARDS'", _("Add to chat"));
1880
        if (config.getBoolValue("enablePickupFilter"))
1881
        {
1882
            mName = item->getName();
1883
            mExtName = mName;
1884
            mBrowserBox->addSeparator("##3---");
1885
            addPickupFilter(mName);
1886
        }
1887
    }
1888
    addGmCommands();
1889
    mBrowserBox->addSeparator("##3---");
1890
    // TRANSLATORS: popup menu item
1891
    mBrowserBox->addRow("/cleardrops", _("Clear drop window"));
1892
    mBrowserBox->addSeparator("##3---");
1893
    // TRANSLATORS: popup menu item
1894
    // TRANSLATORS: close menu
1895
    mBrowserBox->addRow("cancel", _("Cancel"));
1896
1897
    showPopup(x, y);
1898
}
1899
1900
void PopupMenu::showPopup(const int x, const int y, Button *const button)
1901
{
1902
    if ((button == nullptr) || (windowMenu == nullptr))
1903
        return;
1904
1905
    initPopup();
1906
    mButton = button;
1907
    mX = x;
1908
    mY = y;
1909
1910
    mBrowserBox->clearRows();
1911
    STD_VECTOR<Button *> names = windowMenu->getButtons();
1912
    for (STD_VECTOR<Button *>::const_iterator it = names.begin(),
1913
         it_end = names.end(); it != it_end; ++ it)
1914
    {
1915
        const Button *const btn = *it;
1916
        if ((btn == nullptr) || btn->getActionEventId() == "SET")
1917
            continue;
1918
1919
        if (btn->mVisible == Visible_true)
1920
        {
1921
            mBrowserBox->addRow(strprintf("@@hide button_%s|%s %s (%s)@@",
1922
                // TRANSLATORS: popup menu item
1923
                btn->getActionEventId().c_str(), _("Hide"),
1924
                btn->getDescription().c_str(), btn->getCaption().c_str()),
1925
                false);
1926
        }
1927
        else
1928
        {
1929
            mBrowserBox->addRow(strprintf("@@show button_%s|%s %s (%s)@@",
1930
                // TRANSLATORS: popup menu item
1931
                btn->getActionEventId().c_str(), _("Show"),
1932
                btn->getDescription().c_str(), btn->getCaption().c_str()),
1933
                false);
1934
        }
1935
    }
1936
    mBrowserBox->addSeparator("##3---");
1937
    // TRANSLATORS: popup menu item
1938
    // TRANSLATORS: close menu
1939
    mBrowserBox->addRow("cancel", _("Cancel"));
1940
1941
    showPopup(x, y);
1942
}
1943
1944
void PopupMenu::showPopup(const int x, const int y, const ProgressBar *const b)
1945
{
1946
    if ((b == nullptr) || (miniStatusWindow == nullptr))
1947
        return;
1948
1949
    initPopup();
1950
    mName = b->text();
1951
    mExtName = mName;
1952
    mX = x;
1953
    mY = y;
1954
1955
    mBrowserBox->clearRows();
1956
    STD_VECTOR <ProgressBar*> bars = miniStatusWindow->getBars();
1957
    ProgressBar *onlyBar = nullptr;
1958
    int cnt = 0;
1959
1960
    // search for alone visible bar
1961
    for (STD_VECTOR <ProgressBar*>::const_iterator it = bars.begin(),
1962
         it_end = bars.end(); it != it_end; ++it)
1963
    {
1964
        ProgressBar *const bar = *it;
1965
        if (bar == nullptr)
1966
            continue;
1967
1968
        if (bar->mVisible == Visible_true)
1969
        {
1970
            cnt ++;
1971
            onlyBar = bar;
1972
        }
1973
    }
1974
    if (cnt > 1)
1975
        onlyBar = nullptr;
1976
1977
    for (STD_VECTOR <ProgressBar*>::const_iterator it = bars.begin(),
1978
         it_end = bars.end(); it != it_end; ++it)
1979
    {
1980
        ProgressBar *const bar = *it;
1981
        if ((bar == nullptr) || bar == onlyBar)
1982
            continue;
1983
1984
        if (bar->mVisible == Visible_true)
1985
        {
1986
            mBrowserBox->addRow(strprintf("@@hide bar_%s|%s %s@@",
1987
                // TRANSLATORS: popup menu item
1988
                bar->getActionEventId().c_str(), _("Hide"),
1989
                bar->getId().c_str()),
1990
                false);
1991
        }
1992
        else
1993
        {
1994
            mBrowserBox->addRow(strprintf("@@show bar_%s|%s %s@@",
1995
                // TRANSLATORS: popup menu item
1996
                bar->getActionEventId().c_str(), _("Show"),
1997
                bar->getId().c_str()),
1998
                false);
1999
        }
2000
    }
2001
2002
    mBrowserBox->addSeparator("##3---");
2003
    // TRANSLATORS: popup menu item
2004
    mBrowserBox->addRow("/yellowbar", _("Open yellow bar settings"));
2005
    // TRANSLATORS: popup menu item
2006
    mBrowserBox->addRow("/resetmodifiers", _("Reset yellow bar"));
2007
    mBrowserBox->addSeparator("##3---");
2008
    // TRANSLATORS: popup menu item
2009
    // TRANSLATORS: copy status to chat
2010
    mBrowserBox->addRow("/bartochat 'NAME'", _("Copy to chat"));
2011
    // TRANSLATORS: popup menu item
2012
    // TRANSLATORS: close menu
2013
    mBrowserBox->addRow("cancel", _("Cancel"));
2014
2015
    showPopup(x, y);
2016
}
2017
2018
void PopupMenu::showAttackMonsterPopup(const int x, const int y,
2019
                                       const std::string &name,
2020
                                       const int type)
2021
{
2022
    if ((localPlayer == nullptr) || (actorManager == nullptr))
2023
        return;
2024
2025
    initPopup();
2026
    mName = name;
2027
    mExtName = name;
2028
    mType = ActorType::Monster;
2029
    mSubType = BeingTypeId_zero;
2030
    mX = x;
2031
    mY = y;
2032
2033
    mBrowserBox->clearRows();
2034
2035
    if (name.empty())
2036
    {
2037
        // TRANSLATORS: popup menu header
2038
        mBrowserBox->addRow(_("(default)"), false);
2039
    }
2040
    else
2041
    {
2042
        mBrowserBox->addRow(name, false);
2043
    }
2044
    switch (type)
2045
    {
2046
        case MapItemType::ATTACK:
2047
        {
2048
            const int idx = actorManager->getAttackMobIndex(name);
2049
            const int size = actorManager->getAttackMobsSize();
2050
            if (idx > 0)
2051
            {
2052
                // TRANSLATORS: popup menu item
2053
                // TRANSLATORS: move attack target up
2054
                mBrowserBox->addRow("/moveattackup 'NAME'", _("Move up"));
2055
            }
2056
            if (idx + 1 < size)
2057
            {
2058
                // TRANSLATORS: popup menu item
2059
                // TRANSLATORS: move attack target down
2060
                mBrowserBox->addRow("/moveattackdown 'NAME'", _("Move down"));
2061
            }
2062
            break;
2063
        }
2064
        case MapItemType::PRIORITY:
2065
        {
2066
            const int idx = actorManager->
2067
                getPriorityAttackMobIndex(name);
2068
            const int size = actorManager->getPriorityAttackMobsSize();
2069
            if (idx > 0)
2070
            {
2071
                mBrowserBox->addRow("/movepriorityattackup 'NAME'",
2072
                    // TRANSLATORS: popup menu item
2073
                    // TRANSLATORS: move attack target up
2074
                    _("Move up"));
2075
            }
2076
            if (idx + 1 < size)
2077
            {
2078
                mBrowserBox->addRow("/movepriorityattackdown 'NAME'",
2079
                    // TRANSLATORS: popup menu item
2080
                    // TRANSLATORS: move attack target down
2081
                    _("Move down"));
2082
            }
2083
            break;
2084
        }
2085
        case MapItemType::IGNORE_:
2086
        default:
2087
            break;
2088
    }
2089
2090
    // TRANSLATORS: popup menu item
2091
    // TRANSLATORS: remove attack target
2092
    mBrowserBox->addRow("/removeattack 'NAME'", _("Remove"));
2093
    mBrowserBox->addSeparator("##3---");
2094
    // TRANSLATORS: popup menu item
2095
    // TRANSLATORS: close menu
2096
    mBrowserBox->addRow("cancel", _("Cancel"));
2097
2098
    showPopup(x, y);
2099
}
2100
2101
void PopupMenu::showPickupItemPopup(const int x, const int y,
2102
                                    const std::string &name)
2103
{
2104
    if ((localPlayer == nullptr) || (actorManager == nullptr))
2105
        return;
2106
2107
    initPopup();
2108
    mName = name;
2109
    mExtName = name;
2110
    mType = ActorType::FloorItem;
2111
    mSubType = BeingTypeId_zero;
2112
    mX = x;
2113
    mY = y;
2114
2115
    mBrowserBox->clearRows();
2116
2117
    if (name.empty())
2118
    {
2119
        // TRANSLATORS: popup menu header
2120
        mBrowserBox->addRow(_("(default)"), false);
2121
    }
2122
    else
2123
    {
2124
        mBrowserBox->addRow(name, false);
2125
    }
2126
2127
    // TRANSLATORS: popup menu item
2128
    // TRANSLATORS: remove item from pickup filter
2129
    mBrowserBox->addRow("/removepickup 'NAME'", _("Remove"));
2130
    mBrowserBox->addSeparator("##3---");
2131
    // TRANSLATORS: popup menu item
2132
    // TRANSLATORS: close menu
2133
    mBrowserBox->addRow("cancel", _("Cancel"));
2134
2135
    showPopup(x, y);
2136
}
2137
2138
void PopupMenu::showUndressPopup(const int x, const int y,
2139
                                 const Being *const being,
2140
                                 const Item *const item)
2141
{
2142
    if ((being == nullptr) || (item == nullptr))
2143
        return;
2144
2145
    initPopup();
2146
    mBeingId = being->getId();
2147
    mItemId = item->getId();
2148
    mItemColor = item->getColor();
2149
    mItemIndex = item->getInvIndex();
2150
    for (int f = 0; f < maxCards; f ++)
2151
        mItemCards[f] = item->getCard(f);
2152
    mX = x;
2153
    mY = y;
2154
2155
    mBrowserBox->clearRows();
2156
2157
    // TRANSLATORS: popup menu item
2158
    // TRANSLATORS: undress item from player
2159
    mBrowserBox->addRow("/undress :'BEINGID' 'ITEMID'", _("Undress"));
2160
    // TRANSLATORS: popup menu item
2161
    // TRANSLATORS: add item name to chat
2162
    mBrowserBox->addRow("/addchat 'ITEMID''CARDS'", _("Add to chat"));
2163
    addGmCommands();
2164
    mBrowserBox->addSeparator("##3---");
2165
    // TRANSLATORS: popup menu item
2166
    // TRANSLATORS: close menu
2167
    mBrowserBox->addRow("cancel", _("Cancel"));
2168
2169
    showPopup(x, y);
2170
}
2171
2172
void PopupMenu::showTextFieldPopup(TextField *const input)
2173
{
2174
    initPopup();
2175
    setMousePos();
2176
    mTextField = input;
2177
2178
    mBrowserBox->clearRows();
2179
2180
    // TRANSLATORS: popup menu item
2181
    // TRANSLATORS: copy text to clipboard
2182
    mBrowserBox->addRow("clipboard copy", _("Copy"));
2183
    // TRANSLATORS: popup menu item
2184
    // TRANSLATORS: paste text from clipboard
2185
    mBrowserBox->addRow("clipboard paste", _("Paste"));
2186
    mBrowserBox->addSeparator("##3---");
2187
    // TRANSLATORS: popup menu item
2188
    // TRANSLATORS: close menu
2189
    mBrowserBox->addRow("cancel", _("Cancel"));
2190
2191
    showPopup(mX, mY);
2192
}
2193
2194
void PopupMenu::showLinkPopup(const std::string &link)
2195
{
2196
    initPopup();
2197
    setMousePos();
2198
    mName = link;
2199
    mExtName = link;
2200
2201
    mBrowserBox->clearRows();
2202
2203
    // TRANSLATORS: popup menu item
2204
    // TRANSLATORS: open link in browser
2205
    mBrowserBox->addRow("/open 'NAME'", _("Open link"));
2206
    // TRANSLATORS: popup menu item
2207
    // TRANSLATORS: copy link to clipboard
2208
    mBrowserBox->addRow("/clipboardcopy 'NAME'", _("Copy to clipboard"));
2209
    mBrowserBox->addSeparator("##3---");
2210
    // TRANSLATORS: popup menu item
2211
    // TRANSLATORS: close menu
2212
    mBrowserBox->addRow("cancel", _("Cancel"));
2213
2214
    showPopup(mX, mY);
2215
}
2216
2217
void PopupMenu::showWindowsPopup()
2218
{
2219
    initPopup();
2220
    setMousePos();
2221
    mBrowserBox->clearRows();
2222
    const STD_VECTOR<ButtonText*> &names = windowMenu->getButtonTexts();
2223
    // TRANSLATORS: popup menu header
2224
    mBrowserBox->addRow(_("Show window"), false);
2225
2226
    FOR_EACH (STD_VECTOR<ButtonText*>::const_iterator, it, names)
2227
    {
2228
        const ButtonText *const btn = *it;
2229
        if (btn == nullptr)
2230
            continue;
2231
2232
        mBrowserBox->addRow(strprintf("show window_%d",
2233
            CAST_S32(btn->key)),
2234
            btn->text.c_str());
2235
    }
2236
    mBrowserBox->addSeparator("##3---");
2237
    // TRANSLATORS: popup menu item
2238
    // TRANSLATORS: close menu
2239
    mBrowserBox->addRow("cancel", _("Cancel"));
2240
2241
    showPopup(mX, mY);
2242
}
2243
2244
void PopupMenu::showNpcDialogPopup(const BeingId npcId,
2245
                                   const int x, const int y)
2246
{
2247
    initPopup();
2248
    mBeingId = npcId;
2249
    mX = x;
2250
    mY = y;
2251
    mBrowserBox->clearRows();
2252
    // TRANSLATORS: popup menu item
2253
    // TRANSLATORS: copy npc text to clipboard
2254
    mBrowserBox->addRow("/npcclipboard 'X' 'Y'", _("Copy to clipboard"));
2255
    mBrowserBox->addSeparator("##3---");
2256
    // TRANSLATORS: popup menu item
2257
    // TRANSLATORS: close menu
2258
    mBrowserBox->addRow("cancel", _("Cancel"));
2259
2260
    showPopup(x, y);
2261
}
2262
2263
void PopupMenu::showSkillPopup(const SkillInfo *const info)
2264
{
2265
    if (info == nullptr)
2266
        return;
2267
2268
    initPopup();
2269
    setMousePos();
2270
2271
    // using mItemId as skill id
2272
    mItemId = info->id;
2273
    // using mItemIndex as skill level
2274
    mItemIndex = info->level;
2275
    mBrowserBox->clearRows();
2276
2277
    // TRANSLATORS: popup menu header
2278
    mBrowserBox->addRow(_("Skill"), false);
2279
    mBrowserBox->addRow("/addskillshortcut 'ITEMID'",
2280
        // TRANSLATORS: popup menu item
2281
        // TRANSLATORS: add skill to shortcurs tab
2282
        _("Add skill shortcut"));
2283
    mBrowserBox->addSeparator("##3---");
2284
    mBrowserBox->addRow("/showskilllevels 'ITEMID'",
2285
        // TRANSLATORS: popup menu item
2286
        // TRANSLATORS: set skill level
2287
        _("Skill level..."));
2288
    mBrowserBox->addRow("/showskilltypes 'ITEMID'",
2289
        // TRANSLATORS: popup menu item
2290
        // TRANSLATORS: set skill cast type
2291
        _("Skill cast type..."));
2292
    mBrowserBox->addRow("/showskilloffsetx 'ITEMID'",
2293
        // TRANSLATORS: popup menu item
2294
        // TRANSLATORS: set skill cast offset by x
2295
        _("Skill offset by x..."));
2296
    mBrowserBox->addRow("/showskilloffsety 'ITEMID'",
2297
        // TRANSLATORS: popup menu item
2298
        // TRANSLATORS: set skill cast offset by y
2299
        _("Skill offset by y..."));
2300
    // TRANSLATORS: popup menu item
2301
    // TRANSLATORS: close menu
2302
    mBrowserBox->addRow("cancel", _("Cancel"));
2303
2304
    showPopup(mX, mY);
2305
}
2306
2307
void PopupMenu::showSkillOffsetPopup(const SkillInfo *const info,
2308
                                     const bool isOffsetX)
2309
{
2310
    if (info == nullptr)
2311
        return;
2312
2313
    initPopup();
2314
    setMousePos2();
2315
2316
    // using mItemId as skill id
2317
    mItemId = info->id;
2318
    // using mItemIndex as skill level
2319
    mItemIndex = info->level;
2320
    mBrowserBox->clearRows();
2321
    char letter = ' ';
2322
2323
    if (isOffsetX)
2324
    {
2325
        // TRANSLATORS: popup menu header
2326
        mBrowserBox->addRow(_("Skill cast offset by x"), false);
2327
        letter = 'x';
2328
    }
2329
    else
2330
    {
2331
        // TRANSLATORS: popup menu header
2332
        mBrowserBox->addRow(_("Skill cast offset by y"), false);
2333
        letter = 'y';
2334
    }
2335
    for (int f = -9; f <= 9; f ++)
2336
    {
2337
        const std::string command = strprintf(
2338
            "/setskilloffset%c 'ITEMID' %d", letter, f);
2339
        if (f == 0)
2340
        {
2341
            mBrowserBox->addRow(command,
2342
                strprintf("%d", f).c_str());
2343
        }
2344
        else
2345
        {
2346
            mBrowserBox->addRow(command,
2347
                strprintf("%+d", f).c_str());
2348
        }
2349
    }
2350
    // TRANSLATORS: popup menu item
2351
    // TRANSLATORS: close menu
2352
    mBrowserBox->addRow("cancel", _("Cancel"));
2353
    showPopup(mX, mY);
2354
}
2355
2356
void PopupMenu::showSkillLevelPopup(const SkillInfo *const info)
2357
{
2358
    if (info == nullptr)
2359
        return;
2360
2361
    initPopup();
2362
    setMousePos2();
2363
2364
    // using mItemId as skill id
2365
    mItemId = info->id;
2366
    // using mItemIndex as skill level
2367
    mItemIndex = info->level;
2368
2369
    for (int f = 0; f < maxCards; f ++)
2370
        mItemCards[f] = 0;
2371
    mBrowserBox->clearRows();
2372
    // TRANSLATORS: popup menu item
2373
    // TRANSLATORS: skill level header
2374
    mBrowserBox->addRow(_("Select skill level"), false);
2375
    for (int f = 1; f <= mItemIndex; f ++)
2376
    {
2377
        mBrowserBox->addRow(strprintf("/selectskilllevel %d %d", mItemId, f),
2378
            // TRANSLATORS: popup menu item
2379
            // TRANSLATORS: skill level
2380
            strprintf(_("Level: %d"), f).c_str());
2381
    }
2382
    mBrowserBox->addRow(strprintf("/selectskilllevel %d 0", mItemId),
2383
        // TRANSLATORS: popup menu item
2384
        // TRANSLATORS: skill level
2385
        _("Max level"));
2386
    mBrowserBox->addSeparator("##3---");
2387
    // TRANSLATORS: popup menu item
2388
    // TRANSLATORS: close menu
2389
    mBrowserBox->addRow("cancel", _("Cancel"));
2390
2391
    showPopup(mX, mY);
2392
}
2393
2394
void PopupMenu::showSkillTypePopup(const SkillInfo *const info)
2395
{
2396
    if (info == nullptr)
2397
        return;
2398
2399
    initPopup();
2400
    setMousePos2();
2401
2402
    // using mItemId as skill id
2403
    mItemId = info->id;
2404
    // using mItemIndex as skill level
2405
    mItemIndex = info->level;
2406
2407
    for (int f = 0; f < maxCards; f ++)
2408
        mItemCards[f] = 0;
2409
    mBrowserBox->clearRows();
2410
2411
    // TRANSLATORS: popup menu item
2412
    // TRANSLATORS: skill cast type header
2413
    mBrowserBox->addRow(_("Select skill cast type"), false);
2414
    mBrowserBox->addRow(strprintf("/selectskilltype %d 0", mItemId),
2415
        // TRANSLATORS: popup menu item
2416
        // TRANSLATORS: skill cast type
2417
        _("Default"));
2418
    mBrowserBox->addRow(strprintf("/selectskilltype %d 1", mItemId),
2419
        // TRANSLATORS: popup menu item
2420
        // TRANSLATORS: skill cast type
2421
        _("Target"));
2422
    mBrowserBox->addRow(strprintf("/selectskilltype %d 2", mItemId),
2423
        // TRANSLATORS: popup menu item
2424
        // TRANSLATORS: skill cast type
2425
        _("Mouse position"));
2426
    mBrowserBox->addRow(strprintf("/selectskilltype %d 3", mItemId),
2427
        // TRANSLATORS: popup menu item
2428
        // TRANSLATORS: skill cast type
2429
        _("Self"));
2430
    mBrowserBox->addSeparator("##3---");
2431
    // TRANSLATORS: popup menu item
2432
    // TRANSLATORS: close menu
2433
    mBrowserBox->addRow("cancel", _("Cancel"));
2434
2435
    showPopup(mX, mY);
2436
}
2437
2438
void PopupMenu::showPopup(int x, int y)
2439
{
2440
    PopupManager::hideItemPopup();
2441
    const int pad2 = 2 * mPadding;
2442
    mBrowserBox->setPosition(mPadding, mPadding);
2443
    mScrollArea->setPosition(mPadding, mPadding);
2444
    mBrowserBox->updateHeight();
2445
    // add padding to initial size before draw browserbox
2446
    int height = mBrowserBox->getHeight();
2447
    if (height + pad2 >= mainGraphics->getHeight())
2448
    {
2449
        height = mainGraphics->getHeight() - pad2;
2450
        mBrowserBox->setWidth(mBrowserBox->getWidth() + 5);
2451
        mScrollArea->setWidth(mBrowserBox->getWidth() + pad2 + 10);
2452
        setContentSize(mBrowserBox->getWidth() + pad2 + 20,
2453
            height + pad2);
2454
    }
2455
    else
2456
    {
2457
        mBrowserBox->setWidth(mBrowserBox->getWidth());
2458
        mScrollArea->setWidth(mBrowserBox->getWidth() + pad2);
2459
        setContentSize(mBrowserBox->getWidth() + pad2,
2460
            height + pad2);
2461
    }
2462
    if (mainGraphics->mWidth < (x + getWidth() + 5))
2463
        x = mainGraphics->mWidth - getWidth();
2464
    if (mainGraphics->mHeight < (y + getHeight() + 5))
2465
        y = mainGraphics->mHeight - getHeight();
2466
    mScrollArea->setHeight(height);
2467
    setPosition(x, y);
2468
    setVisible(Visible_true);
2469
    requestMoveToTop();
2470
    mAllowCleanMenu = false;
2471
}
2472
2473
void PopupMenu::addNormalRelations()
2474
{
2475
    // TRANSLATORS: popup menu item
2476
    // TRANSLATORS: add player to disregarded list
2477
    mBrowserBox->addRow("/disregard 'NAME'", _("Disregard"));
2478
    // TRANSLATORS: popup menu item
2479
    // TRANSLATORS: add player to ignore list
2480
    mBrowserBox->addRow("/ignore 'NAME'", _("Ignore"));
2481
    // TRANSLATORS: popup menu item
2482
    // TRANSLATORS: add player to black list
2483
    mBrowserBox->addRow("/blacklist 'NAME'", _("Black list"));
2484
    // TRANSLATORS: popup menu item
2485
    // TRANSLATORS: add player to enemy list
2486
    mBrowserBox->addRow("/enemy 'NAME'", _("Set as enemy"));
2487
    // TRANSLATORS: popup menu item
2488
    // TRANSLATORS: add player to erased list
2489
    mBrowserBox->addRow("/erase 'NAME'", _("Erase"));
2490
}
2491
2492
void PopupMenu::addPlayerRelation(const std::string &name)
2493
{
2494
    switch (playerRelations.getRelation(name))
2495
    {
2496
        case Relation::NEUTRAL:
2497
            // TRANSLATORS: popup menu item
2498
            // TRANSLATORS: add player to friends list
2499
            mBrowserBox->addRow("/friend 'NAME'", _("Be friend"));
2500
            addNormalRelations();
2501
            break;
2502
2503
        case Relation::FRIEND:
2504
            addNormalRelations();
2505
            break;
2506
2507
        case Relation::BLACKLISTED:
2508
            // TRANSLATORS: popup menu item
2509
            // TRANSLATORS: remove player from ignore list
2510
            mBrowserBox->addRow("/unignore 'NAME'", _("Unignore"));
2511
            // TRANSLATORS: popup menu item
2512
            // TRANSLATORS: add player to disregarded list
2513
            mBrowserBox->addRow("/disregard 'NAME'", _("Disregard"));
2514
            // TRANSLATORS: popup menu item
2515
            // TRANSLATORS: add player to ignore list
2516
            mBrowserBox->addRow("/ignore 'NAME'", _("Ignore"));
2517
            // TRANSLATORS: popup menu item
2518
            // TRANSLATORS: add player to enemy list
2519
            mBrowserBox->addRow("/enemy 'NAME'", _("Set as enemy"));
2520
            // TRANSLATORS: popup menu item
2521
            // TRANSLATORS: add player to erased list
2522
            mBrowserBox->addRow("/erase 'NAME'", _("Erase"));
2523
            break;
2524
2525
        case Relation::DISREGARDED:
2526
            // TRANSLATORS: popup menu item
2527
            // TRANSLATORS: remove player from ignore list
2528
            mBrowserBox->addRow("/unignore 'NAME'", _("Unignore"));
2529
            // TRANSLATORS: popup menu item
2530
            // TRANSLATORS: add player to completle ignore list
2531
            mBrowserBox->addRow("/ignore 'NAME'", _("Completely ignore"));
2532
            // TRANSLATORS: popup menu item
2533
            // TRANSLATORS: add player to erased list
2534
            mBrowserBox->addRow("/erase 'NAME'", _("Erase"));
2535
            break;
2536
2537
        case Relation::IGNORED:
2538
            // TRANSLATORS: popup menu item
2539
            // TRANSLATORS: remove player from ignore list
2540
            mBrowserBox->addRow("/unignore 'NAME'", _("Unignore"));
2541
            // TRANSLATORS: popup menu item
2542
            // TRANSLATORS: add player to erased list
2543
            mBrowserBox->addRow("/erase 'NAME'", _("Erase"));
2544
            break;
2545
2546
        case Relation::ENEMY2:
2547
            // TRANSLATORS: popup menu item
2548
            // TRANSLATORS: remove player from ignore list
2549
            mBrowserBox->addRow("/unignore 'NAME'", _("Unignore"));
2550
            // TRANSLATORS: popup menu item
2551
            // TRANSLATORS: add player to disregarded list
2552
            mBrowserBox->addRow("/disregard 'NAME'", _("Disregard"));
2553
            // TRANSLATORS: popup menu item
2554
            // TRANSLATORS: add player to ignore list
2555
            mBrowserBox->addRow("/ignore 'NAME'", _("Ignore"));
2556
            // TRANSLATORS: popup menu item
2557
            // TRANSLATORS: add player to black list
2558
            mBrowserBox->addRow("/blacklist 'NAME'", _("Black list"));
2559
            // TRANSLATORS: popup menu item
2560
            // TRANSLATORS: add player to erased list
2561
            mBrowserBox->addRow("/erase 'NAME'", _("Erase"));
2562
            break;
2563
2564
        case Relation::ERASED:
2565
            // TRANSLATORS: popup menu item
2566
            // TRANSLATORS: remove player from ignore list
2567
            mBrowserBox->addRow("/unignore 'NAME'", _("Unignore"));
2568
            // TRANSLATORS: popup menu item
2569
            // TRANSLATORS: add player to disregarded list
2570
            mBrowserBox->addRow("/disregard 'NAME'", _("Disregard"));
2571
            // TRANSLATORS: popup menu item
2572
            // TRANSLATORS: add player to ignore list
2573
            mBrowserBox->addRow("/ignore 'NAME'", _("Completely ignore"));
2574
            break;
2575
2576
        default:
2577
            break;
2578
    }
2579
}
2580
2581
void PopupMenu::addFollow()
2582
{
2583
    if (features.getBoolValue("allowFollow"))
2584
    {
2585
        // TRANSLATORS: popup menu item
2586
        mBrowserBox->addRow("/follow 'NAME'", _("Follow"));
2587
    }
2588
    // TRANSLATORS: popup menu item
2589
    // TRANSLATORS: imitate player
2590
    mBrowserBox->addRow("/imitation 'NAME'", _("Imitate"));
2591
}
2592
2593
void PopupMenu::addBuySell(const Being *const being)
2594
{
2595
    if ((playerRelations.getDefault() & PlayerRelation::TRADE) != 0U)
2596
    {
2597
        mBrowserBox->addSeparator("##3---");
2598
        const bool haveVending =
2599
            (Net::getNetworkType() != ServerType::TMWATHENA);
2600
        if (being->isSellShopEnabled())
2601
        {
2602
            // TRANSLATORS: popup menu item
2603
            // TRANSLATORS: buy item
2604
            mBrowserBox->addRow("/buy 'NAME'", _("Buy"));
2605
        }
2606
        else if (!haveVending)
2607
        {
2608
            // TRANSLATORS: popup menu item
2609
            // TRANSLATORS: buy item
2610
            mBrowserBox->addRow("/buy 'NAME'", _("Buy (?)"));
2611
        }
2612
        if (being->isBuyShopEnabled())
2613
        {
2614
            // TRANSLATORS: popup menu item
2615
            // TRANSLATORS: sell item
2616
            mBrowserBox->addRow("/sell 'NAME'", _("Sell"));
2617
        }
2618
        else if (!haveVending)
2619
        {
2620
            // TRANSLATORS: popup menu item
2621
            // TRANSLATORS: sell item
2622
            mBrowserBox->addRow("/sell 'NAME'", _("Sell (?)"));
2623
        }
2624
    }
2625
}
2626
2627
void PopupMenu::addBuySellDefault()
2628
{
2629
    if ((playerRelations.getDefault() & PlayerRelation::TRADE) != 0U)
2630
    {
2631
        mBrowserBox->addSeparator("##3---");
2632
        // TRANSLATORS: popup menu item
2633
        // TRANSLATORS: buy item
2634
        mBrowserBox->addRow("/buy 'NAME'", _("Buy (?)"));
2635
        // TRANSLATORS: popup menu item
2636
        // TRANSLATORS: sell item
2637
        mBrowserBox->addRow("/sell 'NAME'", _("Sell (?)"));
2638
    }
2639
}
2640
2641
void PopupMenu::addPartyName(const std::string &partyName)
2642
{
2643
    if (localPlayer->isInParty())
2644
    {
2645
        if (localPlayer->getParty() != nullptr)
2646
        {
2647
            if (localPlayer->getParty()->getName() != partyName)
2648
            {
2649
                // TRANSLATORS: popup menu item
2650
                // TRANSLATORS: invite player to party
2651
                mBrowserBox->addRow("/party 'NAME'", _("Invite to party"));
2652
            }
2653
            else
2654
            {
2655
                // TRANSLATORS: popup menu item
2656
                // TRANSLATORS: kick player from party
2657
                mBrowserBox->addRow("/kickparty 'NAME'", _("Kick from party"));
2658
                showAdoptCommands();
2659
            }
2660
            mBrowserBox->addSeparator("##3---");
2661
        }
2662
    }
2663
}
2664
2665
void PopupMenu::addParty(const std::string &nick)
2666
{
2667
    if (localPlayer->isInParty())
2668
    {
2669
        const Party *const party = localPlayer->getParty();
2670
        if (party != nullptr)
2671
        {
2672
            if (!party->isMember(nick))
2673
            {
2674
                // TRANSLATORS: popup menu item
2675
                // TRANSLATORS: invite player to party
2676
                mBrowserBox->addRow("/party 'NAME'", _("Invite to party"));
2677
            }
2678
            else
2679
            {
2680
                // TRANSLATORS: popup menu item
2681
                // TRANSLATORS: kick player from party
2682
                mBrowserBox->addRow("/kickparty 'NAME'", _("Kick from party"));
2683
                showAdoptCommands();
2684
            }
2685
            mBrowserBox->addSeparator("##3---");
2686
        }
2687
    }
2688
}
2689
2690
void PopupMenu::addChat(const Being *const being)
2691
{
2692
    if (being == nullptr)
2693
        return;
2694
    const ChatObject *const chat = being->getChat();
2695
    if (chat != nullptr)
2696
    {
2697
        mBrowserBox->addRow("join chat",
2698
            // TRANSLATORS: popup menu item
2699
            // TRANSLATORS: invite player to party
2700
            strprintf(_("Join chat %s"), chat->title.c_str()).c_str());
2701
        mBrowserBox->addSeparator("##3---");
2702
    }
2703
}
2704
2705
void PopupMenu::addPlayerMisc()
2706
{
2707
    // TRANSLATORS: popup menu item
2708
    mBrowserBox->addRow("/showitems :'BEINGID'", _("Show Items"));
2709
    // TRANSLATORS: popup menu item
2710
    // TRANSLATORS: undress player
2711
    mBrowserBox->addRow("/undress :'BEINGID'", _("Undress"));
2712
    // TRANSLATORS: popup menu item
2713
    // TRANSLATORS: add comment to player
2714
    mBrowserBox->addRow("addcomment", _("Add comment"));
2715
}
2716
2717
void PopupMenu::addPickupFilter(const std::string &name)
2718
{
2719
    if (actorManager->isInPickupList(name)
2720
        || actorManager->isInIgnorePickupList(name))
2721
    {
2722
        mBrowserBox->addRow("/removepickup 'NAME'",
2723
            // TRANSLATORS: popup menu item
2724
            // TRANSLATORS: remove item from pickup list
2725
            _("Remove from pickup list"));
2726
    }
2727
    else
2728
    {
2729
        mBrowserBox->addRow("/addpickup 'NAME'",
2730
            // TRANSLATORS: popup menu item
2731
            // TRANSLATORS: popup menu item
2732
            _("Add to pickup list"));
2733
        mBrowserBox->addRow("/ignorepickup 'NAME'",
2734
            // TRANSLATORS: popup menu item
2735
            // TRANSLATORS: add item to pickup list
2736
            _("Add to ignore list"));
2737
    }
2738
}
2739
2740
void PopupMenu::showPopup(const int x, const int y,
2741
                          ListModel *const model)
2742
{
2743
    if (model == nullptr)
2744
        return;
2745
2746
    mBrowserBox->clearRows();
2747
    for (int f = 0, sz = model->getNumberOfElements(); f < sz; f ++)
2748
    {
2749
        mBrowserBox->addRow(strprintf("dropdown_%d", f),
2750
            model->getElementAt(f).c_str());
2751
    }
2752
    // TRANSLATORS: popup menu item
2753
    // TRANSLATORS: close menu
2754
    mBrowserBox->addRow("cancel", _("Cancel"));
2755
    showPopup(x, y);
2756
}
2757
2758
void PopupMenu::clear()
2759
{
2760
    if (mDialog != nullptr)
2761
    {
2762
        mDialog->close();
2763
        mDialog = nullptr;
2764
    }
2765
    mItemIndex = -1;
2766
    mItemId = 0;
2767
    for (int f = 0; f < maxCards; f ++)
2768
        mItemCards[f] = 0;
2769
    mMapItem = nullptr;
2770
    mTab = nullptr;
2771
    mSpell = nullptr;
2772
    mCallerWindow = nullptr;
2773
    mButton = nullptr;
2774
    mTextField = nullptr;
2775
}
2776
2777
void PopupMenu::addProtection()
2778
{
2779
    if (PlayerInfo::isItemProtected(mItemId))
2780
    {
2781
        mBrowserBox->addSeparator("##3---");
2782
        // TRANSLATORS: popup menu item
2783
        // TRANSLATORS: remove protection from item
2784
        mBrowserBox->addRow("/unprotectitem 'ITEMID'", _("Unprotect item"));
2785
    }
2786
    else
2787
    {
2788
        if (mItemId < SPELL_MIN_ID)
2789
        {
2790
            mBrowserBox->addSeparator("##3---");
2791
            // TRANSLATORS: popup menu item
2792
            // TRANSLATORS: add protection to item
2793
            mBrowserBox->addRow("/protectitem 'ITEMID'", _("Protect item"));
2794
        }
2795
    }
2796
}
2797
2798
void PopupMenu::addUse(const Item *const item)
2799
{
2800
    const ItemInfo &info = item->getInfo();
2801
    const std::string &str = (item->isEquipment() == Equipm_true
2802
        && item->isEquipped() == Equipped_true)
2803
        ? info.getUseButton2() : info.getUseButton();
2804
2805
    if (str.empty())
2806
    {
2807
        // TRANSLATORS: popup menu item
2808
        mBrowserBox->addRow("/useinv 'INVINDEX'", _("Use"));
2809
    }
2810
    else
2811
    {
2812
        // TRANSLATORS: popup menu item
2813
        mBrowserBox->addRow("/useinv 'INVINDEX'", str.c_str());
2814
    }
2815
}
2816
2817
void PopupMenu::addItemMenu(const Item *const item,
2818
                            const InventoryTypeT type)
2819
{
2820
    const ItemInfo &info = item->getInfo();
2821
    const STD_VECTOR<ItemMenuItem> *menu = nullptr;
2822
    switch (type)
2823
    {
2824
        case InventoryType::Inventory:
2825
            menu = &info.getInventoryMenuConst();
2826
            break;
2827
        case InventoryType::Storage:
2828
            menu = &info.getStorageMenuConst();
2829
            break;
2830
        case InventoryType::Cart:
2831
            menu = &info.getCartMenuConst();
2832
            break;
2833
        case InventoryType::Trade:
2834
        case InventoryType::Npc:
2835
        case InventoryType::Vending:
2836
        case InventoryType::MailEdit:
2837
        case InventoryType::MailView:
2838
        case InventoryType::Craft:
2839
        case InventoryType::TypeEnd:
2840
        default:
2841
            return;
2842
    }
2843
2844
    const bool firstMode = (item->isEquipment() == Equipm_true ?
2845
        (item->isEquipped() != Equipped_true) : (item->getQuantity() == 1));
2846
2847
    FOR_EACHP (STD_VECTOR<ItemMenuItem>::const_iterator, it, menu)
2848
    {
2849
        const ItemMenuItem &menuItem = *it;
2850
        const std::string &name = firstMode ?
2851
            menuItem.name1 : menuItem.name2;
2852
        const std::string &command = firstMode ?
2853
            menuItem.command1 : menuItem.command2;
2854
        if (command.empty() ||
2855
            name.empty())
2856
        {
2857
            continue;
2858
        }
2859
        mBrowserBox->addRow("/" + command, name.c_str());
2860
    }
2861
    mBrowserBox->addSeparator("##3---");
2862
}
2863
2864
void PopupMenu::addDrop(const Item *const item,
2865
                        const bool isProtected)
2866
{
2867
    if (!isProtected)
2868
    {
2869
        mBrowserBox->addSeparator("##3---");
2870
        if (item->getQuantity() > 1)
2871
        {
2872
            // TRANSLATORS: popup menu item
2873
            // TRANSLATORS: drop item
2874
            mBrowserBox->addRow("/dropinv 'INVINDEX'", _("Drop..."));
2875
            // TRANSLATORS: popup menu item
2876
            // TRANSLATORS: drop all item amount
2877
            mBrowserBox->addRow("/dropinvall 'INVINDEX'", _("Drop all"));
2878
        }
2879
        else
2880
        {
2881
            // TRANSLATORS: popup menu item
2882
            // TRANSLATORS: drop item
2883
            mBrowserBox->addRow("/dropinv 'INVINDEX'", _("Drop"));
2884
        }
2885
    }
2886
}
2887
2888
void PopupMenu::addGmCommands()
2889
{
2890
    if (localPlayer->isGM())
2891
    {
2892
        // TRANSLATORS: popup menu item
2893
        // TRANSLATORS: gm commands
2894
        mBrowserBox->addRow("gm", _("GM..."));
2895
    }
2896
}
2897
2898
void PopupMenu::showPlayerMenu()
2899
{
2900
    mBrowserBox->clearRows();
2901
    // TRANSLATORS: popup menu header
2902
    mBrowserBox->addRow(strprintf(_("Show %s"),
2903
        mName.c_str()),
2904
        false);
2905
    if (isAllowCommand(ServerCommandType::accinfo))
2906
    {
2907
        // TRANSLATORS: popup menu item
2908
        // TRANSLATORS: show player account info
2909
        mBrowserBox->addRow("/showaccountinfo 'NAME'", _("Account info"));
2910
    }
2911
    if (isAllowOtherCommand(ServerCommandType::exp))
2912
    {
2913
        // TRANSLATORS: popup menu item
2914
        // TRANSLATORS: show player level
2915
        mBrowserBox->addRow("/showlevel 'NAME'", _("Level"));
2916
    }
2917
    if (isAllowOtherCommand(ServerCommandType::stats))
2918
    {
2919
        // TRANSLATORS: popup menu item
2920
        // TRANSLATORS: show player stats
2921
        mBrowserBox->addRow("/showstats 'NAME'", _("Stats"));
2922
    }
2923
    if (isAllowOtherCommand(ServerCommandType::itemlist))
2924
    {
2925
        // TRANSLATORS: popup menu item
2926
        // TRANSLATORS: show player inventory list
2927
        mBrowserBox->addRow("/showinventory 'NAME'", _("Inventory"));
2928
    }
2929
    if (isAllowOtherCommand(ServerCommandType::storagelist))
2930
    {
2931
        // TRANSLATORS: popup menu item
2932
        // TRANSLATORS: show player storage list
2933
        mBrowserBox->addRow("/showstorage 'NAME'", _("Storage"));
2934
    }
2935
    if (isAllowOtherCommand(ServerCommandType::cartlist))
2936
    {
2937
        // TRANSLATORS: popup menu item
2938
        // TRANSLATORS: show player cart list
2939
        mBrowserBox->addRow("/showcart 'NAME'", _("Cart"));
2940
    }
2941
    if (isAllowOtherCommand(ServerCommandType::commands))
2942
    {
2943
        // TRANSLATORS: popup menu item
2944
        // TRANSLATORS: gm commands
2945
        mBrowserBox->addRow("/gmcommands 'NAME'", _("Commands"));
2946
    }
2947
    if (isAllowOtherCommand(ServerCommandType::charcommands))
2948
    {
2949
        // TRANSLATORS: popup menu item
2950
        // TRANSLATORS: gm char commands
2951
        mBrowserBox->addRow("/gmcharcommands 'NAME'", _("Char commands"));
2952
    }
2953
    // TRANSLATORS: popup menu item
2954
    // TRANSLATORS: back to gm menu
2955
    mBrowserBox->addRow("gm", _("Back"));
2956
    // TRANSLATORS: popup menu item
2957
    // TRANSLATORS: close menu
2958
    mBrowserBox->addRow("cancel", _("Cancel"));
2959
    showPopup(getX(), getY());
2960
}
2961
2962
void PopupMenu::showPlayerGMCommands(const std::string &name)
2963
{
2964
    if (localPlayer == nullptr)
2965
        return;
2966
    const bool legacy = Net::getNetworkType() == ServerType::TMWATHENA;
2967
    if (!legacy && isAllowCommand(ServerCommandType::where))
2968
    {
2969
        // TRANSLATORS: popup menu item
2970
        // TRANSLATORS: find player position
2971
        mBrowserBox->addRow("/locateplayer 'NAME'", _("Locate"));
2972
    }
2973
    if (legacy)
2974
    {
2975
        // TRANSLATORS: popup menu item
2976
        // TRANSLATORS: check player ip
2977
        mBrowserBox->addRow("/ipcheck 'NAME'", _("Check ip"));
2978
    }
2979
    if (isAllowCommand(ServerCommandType::jumpto))
2980
    {
2981
        // TRANSLATORS: popup menu item
2982
        // TRANSLATORS: go to player position
2983
        mBrowserBox->addRow("/gotopc 'NAME'", _("Goto"));
2984
    }
2985
    if (isAllowCommand(ServerCommandType::recall))
2986
    {
2987
        // TRANSLATORS: popup menu item
2988
        // TRANSLATORS: recall player to current position
2989
        mBrowserBox->addRow("/recallpc 'NAME'", _("Recall"));
2990
    }
2991
    if (isAllowOtherCommand(ServerCommandType::alive))
2992
    {
2993
        // TRANSLATORS: popup menu item
2994
        // TRANSLATORS: revive player
2995
        mBrowserBox->addRow("/alive 'NAME'", _("Revive"));
2996
    }
2997
    if (!legacy)
2998
    {
2999
        Being *const being = actorManager->findBeingByName(name,
3000
            ActorType::Player);
3001
        if (being != nullptr && being == localPlayer)
3002
        {
3003
            if (!being->getPartyName().empty() &&
3004
                isAllowCommand(ServerCommandType::partyrecall))
3005
            {
3006
                mBrowserBox->addRow("/partyrecall 'PARTY'",
3007
                    // TRANSLATORS: popup menu item
3008
                    // TRANSLATORS: recall all party members to player location
3009
                    _("Recall party"));
3010
            }
3011
            if (!being->getGuildName().empty() &&
3012
                isAllowCommand(ServerCommandType::guildrecall))
3013
            {
3014
                mBrowserBox->addRow("/guildrecall 'PARTY'",
3015
                    // TRANSLATORS: popup menu item
3016
                    // TRANSLATORS: recall all guild members to player location
3017
                    _("Recall guild"));
3018
            }
3019
        }
3020
        if (localPlayer->isInParty())
3021
        {
3022
            const Party *const party = localPlayer->getParty();
3023
            if (party != nullptr &&
3024
                party->isMember(name) &&
3025
                isAllowCommand(ServerCommandType::changeleader))
3026
            {
3027
                mBrowserBox->addRow("/gmpartyleader 'NAME'",
3028
                    // TRANSLATORS: popup menu item
3029
                    // TRANSLATORS: give party leader status
3030
                    _("Give party leader"));
3031
            }
3032
        }
3033
3034
        if (isAllowCommand(ServerCommandType::nuke))
3035
        {
3036
            // TRANSLATORS: popup menu item
3037
            // TRANSLATORS: nuke player
3038
            mBrowserBox->addRow("/gmnuke 'NAME'", _("Nuke"));
3039
        }
3040
        if (isAllowOtherCommand(ServerCommandType::kill))
3041
        {
3042
            // TRANSLATORS: popup menu item
3043
            // TRANSLATORS: kill player
3044
            mBrowserBox->addRow("/kill 'NAME'", _("Kill"));
3045
        }
3046
        if (mBeingId != BeingId_zero)
3047
        {
3048
            mBrowserBox->addSeparator("##3---");
3049
            // TRANSLATORS: popup menu item
3050
            // TRANSLATORS: show menu
3051
            mBrowserBox->addRow("show", _("Show..."));
3052
            // TRANSLATORS: popup menu item
3053
            // TRANSLATORS: mute menu
3054
            mBrowserBox->addRow("mute", _("Mute..."));
3055
        }
3056
    }
3057
    if (legacy)
3058
    {
3059
        if (localPlayer->getName() == mName)
3060
        {
3061
            // TRANSLATORS: popup menu item
3062
            // TRANSLATORS: hide player
3063
            mBrowserBox->addRow("/hide", _("Hide"));
3064
            mBrowserBox->addSeparator("##3---");
3065
        }
3066
    }
3067
    else
3068
    {
3069
        if (isAllowOtherCommand(ServerCommandType::heal))
3070
        {
3071
            // TRANSLATORS: popup menu item
3072
            // TRANSLATORS: heal player
3073
            mBrowserBox->addRow("/gmheal 'NAME'", _("Heal"));
3074
        }
3075
        if (isAllowOtherCommand(ServerCommandType::monsterignore))
3076
        {
3077
            // TRANSLATORS: popup menu item
3078
            // TRANSLATORS: enable immortal mode for player
3079
            mBrowserBox->addRow("/immortal 'NAME'", _("Immortal"));
3080
        }
3081
        if (isAllowCommand(ServerCommandType::jail))
3082
        {
3083
            // TRANSLATORS: popup menu item
3084
            // TRANSLATORS: send player to jail
3085
            mBrowserBox->addRow("/jail 'NAME'", _("Jail"));
3086
        }
3087
        if (isAllowCommand(ServerCommandType::unjail))
3088
        {
3089
            // TRANSLATORS: popup menu item
3090
            // TRANSLATORS: restore player from jail
3091
            mBrowserBox->addRow("/unjail 'NAME'", _("Unjail"));
3092
        }
3093
        if (name == localPlayer->getName() &&
3094
            isAllowCommand(ServerCommandType::hide))
3095
        {
3096
            // TRANSLATORS: popup menu item
3097
            // TRANSLATORS: hide player
3098
            mBrowserBox->addRow("/hide 'NAME'", _("Hide"));
3099
        }
3100
        mBrowserBox->addSeparator("##3---");
3101
        if (isAllowOtherCommand(ServerCommandType::killer))
3102
        {
3103
            // TRANSLATORS: popup menu item
3104
            // TRANSLATORS: set player as killer
3105
            mBrowserBox->addRow("/killer 'NAME'", _("Killer"));
3106
        }
3107
        if (isAllowOtherCommand(ServerCommandType::killable))
3108
        {
3109
            // TRANSLATORS: popup menu item
3110
            // TRANSLATORS: set player as killable
3111
            mBrowserBox->addRow("/killable 'NAME'", _("Killable"));
3112
        }
3113
        if (isAllowOtherCommand(ServerCommandType::save))
3114
        {
3115
            // TRANSLATORS: popup menu item
3116
            // TRANSLATORS: set player save position
3117
            mBrowserBox->addRow("/savepos 'NAME'", _("Set save"));
3118
        }
3119
        if (isAllowOtherCommand(ServerCommandType::load))
3120
        {
3121
            // TRANSLATORS: popup menu item
3122
            // TRANSLATORS: warp player to save position
3123
            mBrowserBox->addRow("/loadpos 'NAME'", _("Warp to save"));
3124
        }
3125
        if (isAllowOtherCommand(ServerCommandType::jump))
3126
        {
3127
            // TRANSLATORS: popup menu item
3128
            // TRANSLATORS: warp player to random position on same map
3129
            mBrowserBox->addRow("/randomwarp 'NAME'", _("Warp to random"));
3130
        }
3131
        mBrowserBox->addSeparator("##3---");
3132
        if (isAllowCommand(ServerCommandType::clone))
3133
        {
3134
            // TRANSLATORS: popup menu item
3135
            // TRANSLATORS: spawn player clone
3136
            mBrowserBox->addRow("/spawnclone 'NAME'", _("Spawn clone"));
3137
        }
3138
        if (isAllowCommand(ServerCommandType::slaveclone))
3139
        {
3140
            mBrowserBox->addRow("/spawnslaveclone 'NAME'",
3141
                // TRANSLATORS: popup menu item
3142
                // TRANSLATORS: spawn slave player clone
3143
                _("Spawn slave clone"));
3144
        }
3145
        if (isAllowCommand(ServerCommandType::evilclone))
3146
        {
3147
            mBrowserBox->addRow("/spawnevilclone 'NAME'",
3148
                // TRANSLATORS: popup menu item
3149
                // TRANSLATORS: spawn evil player clone
3150
                _("Spawn evil clone"));
3151
        }
3152
        mBrowserBox->addSeparator("##3---");
3153
        if (isAllowOtherCommand(ServerCommandType::breakguild))
3154
        {
3155
            // TRANSLATORS: popup menu item
3156
            // TRANSLATORS: break guild
3157
            mBrowserBox->addRow("/gmbreakguild 'NAME'", _("Break guild"));
3158
        }
3159
    }
3160
    if (mBeingId != BeingId_zero &&
3161
        isAllowCommand(ServerCommandType::kick))
3162
    {
3163
        mBrowserBox->addSeparator("##3---");
3164
        // TRANSLATORS: popup menu item
3165
        // TRANSLATORS: kick player
3166
        mBrowserBox->addRow("/kick :'BEINGID'", _("Kick"));
3167
    }
3168
}
3169
3170
void PopupMenu::showMuteCommands()
3171
{
3172
    mBrowserBox->clearRows();
3173
    // TRANSLATORS: popup menu header
3174
    mBrowserBox->addRow(strprintf(_("Mute %s"),
3175
        mName.c_str()),
3176
        false);
3177
    if (mBeingId != BeingId_zero &&
3178
        Net::getNetworkType() != ServerType::TMWATHENA &&
3179
        isAllowCommand(ServerCommandType::mute))
3180
    {
3181
        mBrowserBox->addRow("mute_+1",
3182
            // TRANSLATORS: popup menu item
3183
            // TRANSLATORS: mute player
3184
            strprintf(_("Mute %d"), 1).c_str());
3185
        mBrowserBox->addRow("mute_+5",
3186
            // TRANSLATORS: popup menu item
3187
            // TRANSLATORS: mute player
3188
            strprintf(_("Mute %d"), 5).c_str());
3189
        mBrowserBox->addRow("mute_+10",
3190
            // TRANSLATORS: popup menu item
3191
            // TRANSLATORS: mute player
3192
            strprintf(_("Mute %d"), 10).c_str());
3193
        mBrowserBox->addRow("mute_+15",
3194
            // TRANSLATORS: popup menu item
3195
            // TRANSLATORS: mute player
3196
            strprintf(_("Mute %d"), 15).c_str());
3197
        mBrowserBox->addRow("mute_+30",
3198
            // TRANSLATORS: popup menu item
3199
            // TRANSLATORS: mute player
3200
            strprintf(_("Mute %d"), 30).c_str());
3201
3202
        mBrowserBox->addRow("mute_-1",
3203
            // TRANSLATORS: popup menu item
3204
            // TRANSLATORS: mute player
3205
            strprintf(_("Unmute %d"), 1).c_str());
3206
        mBrowserBox->addRow("mute_-5",
3207
            // TRANSLATORS: popup menu item
3208
            // TRANSLATORS: mute player
3209
            strprintf(_("Unmute %d"), 5).c_str());
3210
        mBrowserBox->addRow("mute_-10",
3211
            // TRANSLATORS: popup menu item
3212
            // TRANSLATORS: mute player
3213
            strprintf(_("Unmute %d"), 10).c_str());
3214
        mBrowserBox->addRow("mute_-15",
3215
            // TRANSLATORS: popup menu item
3216
            // TRANSLATORS: mute player
3217
            strprintf(_("Unmute %d"), 15).c_str());
3218
        mBrowserBox->addRow("mute_-30",
3219
            // TRANSLATORS: popup menu item
3220
            // TRANSLATORS: mute player
3221
            strprintf(_("Unmute %d"), 30).c_str());
3222
        mBrowserBox->addSeparator("##3---");
3223
    }
3224
    // TRANSLATORS: popup menu item
3225
    // TRANSLATORS: back to gm menu
3226
    mBrowserBox->addRow("gm", _("Back"));
3227
    // TRANSLATORS: popup menu item
3228
    // TRANSLATORS: close menu
3229
    mBrowserBox->addRow("cancel", _("Cancel"));
3230
    showPopup(getX(), getY());
3231
}
3232
3233
void PopupMenu::showNpcGMCommands()
3234
{
3235
    if (mBeingId != BeingId_zero)
3236
    {
3237
        if (isAllowCommand(ServerCommandType::kick))
3238
        {
3239
            // TRANSLATORS: popup menu item
3240
            // TRANSLATORS: kick player
3241
            mBrowserBox->addRow("/kick :'BEINGID'", _("Kick"));
3242
        }
3243
        const bool legacy = Net::getNetworkType() == ServerType::TMWATHENA;
3244
        if (!legacy)
3245
        {
3246
            if (isAllowCommand(ServerCommandType::hidenpc))
3247
            {
3248
                // TRANSLATORS: popup menu item
3249
                // TRANSLATORS: hide npc
3250
                mBrowserBox->addRow("/hidenpc 'EXTNAME'", _("Hide"));
3251
            }
3252
            mBrowserBox->addSeparator("##3---");
3253
            if (isAllowCommand(ServerCommandType::npcmove))
3254
            {
3255
                mBrowserBox->addRow("/npcmove 'EEXTNAME' 'PLAYERX' 'PLAYERY'",
3256
                    // TRANSLATORS: popup menu item
3257
                    // TRANSLATORS: warp npc to player location
3258
                    _("Recall"));
3259
            }
3260
            if (isAllowCommand(ServerCommandType::disguise))
3261
            {
3262
                mBrowserBox->addRow("/disguise 'BEINGSUBTYPEID'",
3263
                    // TRANSLATORS: popup menu item
3264
                    // TRANSLATORS: disguise to npc
3265
                    _("Disguise"));
3266
            }
3267
            if (isAllowCommand(ServerCommandType::tonpc))
3268
            {
3269
                // TRANSLATORS: popup menu item
3270
                // TRANSLATORS: warp to npc
3271
                mBrowserBox->addRow("/gotonpc 'EXTNAME'", _("Goto"));
3272
            }
3273
        }
3274
    }
3275
}
3276
3277
void PopupMenu::showMonsterGMCommands()
3278
{
3279
    if (mBeingId != BeingId_zero)
3280
    {
3281
        const bool legacy = Net::getNetworkType() == ServerType::TMWATHENA;
3282
        if (isAllowCommand(ServerCommandType::kick))
3283
        {
3284
            // TRANSLATORS: popup menu item
3285
            // TRANSLATORS: kick monster
3286
            mBrowserBox->addRow("/kick :'BEINGID'", _("Kick"));
3287
        }
3288
        if (isAllowCommand(ServerCommandType::monster))
3289
        {
3290
            // TRANSLATORS: popup menu item
3291
            // TRANSLATORS: spawn monster
3292
            mBrowserBox->addRow("/spawn 'BEINGSUBTYPEID'", _("Spawn same"));
3293
        }
3294
        if (!legacy)
3295
        {
3296
            if (isAllowCommand(ServerCommandType::summon))
3297
            {
3298
                mBrowserBox->addRow("/spawnslave 'BEINGSUBTYPEID'",
3299
                    // TRANSLATORS: popup menu item
3300
                    // TRANSLATORS: spawn slave monster
3301
                    _("Spawn slave"));
3302
            }
3303
            if (isAllowCommand(ServerCommandType::disguise))
3304
            {
3305
                mBrowserBox->addRow("/disguise 'BEINGSUBTYPEID'",
3306
                    // TRANSLATORS: popup menu item
3307
                    // TRANSLATORS: disguise to monster
3308
                    _("Disguise"));
3309
            }
3310
            mBrowserBox->addSeparator("##3---");
3311
            if (isAllowCommand(ServerCommandType::mobinfo))
3312
            {
3313
                mBrowserBox->addRow("/monsterinfo 'BEINGSUBTYPEID'",
3314
                    // TRANSLATORS: popup menu item
3315
                    // TRANSLATORS: show monster information
3316
                    _("Info"));
3317
            }
3318
            if (isAllowCommand(ServerCommandType::mobsearch))
3319
            {
3320
                mBrowserBox->addRow("/mobsearch 'BEINGSUBTYPEID'",
3321
                    // TRANSLATORS: popup menu item
3322
                    // TRANSLATORS: show selected monster in current map
3323
                    _("Search"));
3324
            }
3325
            if (isAllowCommand(ServerCommandType::whereis))
3326
            {
3327
                mBrowserBox->addRow("/mobspawnsearch 'BEINGSUBTYPEID'",
3328
                    // TRANSLATORS: popup menu item
3329
                    // TRANSLATORS: show selected monster spawns in all maps
3330
                    _("Search spawns"));
3331
            }
3332
        }
3333
    }
3334
}
3335
3336
void PopupMenu::showFloorItemGMCommands()
3337
{
3338
    const bool legacy = Net::getNetworkType() == ServerType::TMWATHENA;
3339
    if (legacy)
3340
        return;
3341
    if (isAllowCommand(ServerCommandType::iteminfo))
3342
    {
3343
        // TRANSLATORS: popup menu item
3344
        // TRANSLATORS: show item information
3345
        mBrowserBox->addRow("/iteminfo 'ITEMID'", _("Info"));
3346
    }
3347
    if (isAllowCommand(ServerCommandType::whodrops))
3348
    {
3349
        // TRANSLATORS: popup menu item
3350
        // TRANSLATORS: show who drops item
3351
        mBrowserBox->addRow("/whodrops 'ITEMID'", _("Who drops"));
3352
    }
3353
}
3354
3355
void PopupMenu::showItemGMCommands()
3356
{
3357
    const bool legacy = Net::getNetworkType() == ServerType::TMWATHENA;
3358
    if (legacy)
3359
        return;
3360
    if (isAllowCommand(ServerCommandType::iteminfo))
3361
    {
3362
        // TRANSLATORS: popup menu item
3363
        // TRANSLATORS: show item information
3364
        mBrowserBox->addRow("/iteminfo 'ITEMID'", _("Info"));
3365
    }
3366
    if (isAllowCommand(ServerCommandType::whodrops))
3367
    {
3368
        // TRANSLATORS: popup menu item
3369
        // TRANSLATORS: show who drops item
3370
        mBrowserBox->addRow("/whodrops 'ITEMID'", _("Who drops"));
3371
    }
3372
    mBrowserBox->addSeparator("##3---");
3373
    if (isAllowCommand(ServerCommandType::item))
3374
    {
3375
        // TRANSLATORS: popup menu item
3376
        // TRANSLATORS: gm create item
3377
        mBrowserBox->addRow("/createitem 'ITEMID' 1", _("Add 1"));
3378
        // TRANSLATORS: popup menu item
3379
        // TRANSLATORS: gm create item
3380
        mBrowserBox->addRow("/createitem 'ITEMID' 5", _("Add 5"));
3381
        // TRANSLATORS: popup menu item
3382
        // TRANSLATORS: gm create item
3383
        mBrowserBox->addRow("/createitem 'ITEMID' 10", _("Add 10"));
3384
        // TRANSLATORS: popup menu item
3385
        // TRANSLATORS: gm create item
3386
        mBrowserBox->addRow("/createitem 'ITEMID' 100", _("Add 100"));
3387
        // TRANSLATORS: popup menu item
3388
        // TRANSLATORS: gm create item
3389
        mBrowserBox->addRow("/createitem 'ITEMID' 1000", _("Add 1000"));
3390
        // TRANSLATORS: popup menu item
3391
        // TRANSLATORS: gm create item
3392
        mBrowserBox->addRow("/createitem 'ITEMID' 10000", _("Add 10000"));
3393
    }
3394
}
3395
3396
void PopupMenu::showGMPopup(const std::string &name)
3397
{
3398
    mBrowserBox->clearRows();
3399
    // TRANSLATORS: popup menu header
3400
    mBrowserBox->addRow(_("GM commands"), false);
3401
    if (localPlayer->isGM())
3402
    {
3403
        switch (mType)
3404
        {
3405
            case ActorType::Player:
3406
                showPlayerGMCommands(name);
3407
                break;
3408
            case ActorType::Npc:
3409
                showNpcGMCommands();
3410
                break;
3411
            case ActorType::Monster:
3412
                showMonsterGMCommands();
3413
                break;
3414
            case ActorType::FloorItem:
3415
                showFloorItemGMCommands();
3416
                break;
3417
            case ActorType::Homunculus:
3418
                showHomunGMCommands();
3419
                break;
3420
            case ActorType::Pet:
3421
                showPetGMCommands();
3422
                break;
3423
            case ActorType::Mercenary:
3424
                showMercenaryGMCommands();
3425
                break;
3426
            case ActorType::SkillUnit:
3427
                break;
3428
            default:
3429
            case ActorType::Unknown:
3430
                if (mItemId != 0)
3431
                    showItemGMCommands();
3432
                break;
3433
            case ActorType::Portal:
3434
            case ActorType::Avatar:
3435
            case ActorType::Elemental:
3436
                break;
3437
        }
3438
    }
3439
3440
    mBrowserBox->addSeparator("##3---");
3441
    // TRANSLATORS: popup menu item
3442
    // TRANSLATORS: close menu
3443
    mBrowserBox->addRow("cancel", _("Cancel"));
3444
3445
    showPopup(getX(), getY());
3446
}
3447
3448
void PopupMenu::showHomunGMCommands()
3449
{
3450
}
3451
3452
void PopupMenu::showPetGMCommands()
3453
{
3454
}
3455
3456
void PopupMenu::showMercenaryGMCommands()
3457
{
3458
}
3459
3460
void PopupMenu::showCraftPopup()
3461
{
3462
    mBrowserBox->clearRows();
3463
3464
    for (int f = 0; f < 9; f ++)
3465
    {
3466
        const std::string cmd = strprintf("/craft %d", f);
3467
        mBrowserBox->addRow(cmd,
3468
            // TRANSLATORS: popup menu item
3469
            // TRANSLATORS: move current item to craft slot
3470
            strprintf(_("Move to craft %d"), f + 1).c_str());
3471
    }
3472
3473
    // TRANSLATORS: popup menu item
3474
    // TRANSLATORS: close menu
3475
    mBrowserBox->addRow("cancel", _("Cancel"));
3476
3477
    showPopup(mX, mY);
3478
}
3479
3480
void PopupMenu::addMailCommands()
3481
{
3482
    if (Net::getNetworkType() == ServerType::TMWATHENA)
3483
        return;
3484
3485
    // TRANSLATORS: popup menu item
3486
    // TRANSLATORS: open mail dialog
3487
    mBrowserBox->addRow("/mailto 'NAME'", _("Mail to..."));
3488
}
3489
3490
void PopupMenu::addCatchPetCommands()
3491
{
3492
    if (Net::getNetworkType() == ServerType::TMWATHENA)
3493
        return;
3494
    // TRANSLATORS: popup menu item
3495
    // TRANSLATORS: catch pet command
3496
    mBrowserBox->addRow("/catchpet :'BEINGID'", _("Taming pet"));
3497
}
3498
3499
void PopupMenu::showAdoptCommands()
3500
{
3501
    if (Net::getNetworkType() == ServerType::TMWATHENA)
3502
        return;
3503
    // TRANSLATORS: popup menu item
3504
    // TRANSLATORS: adopt child command
3505
    mBrowserBox->addRow("/adoptchild 'NAME'", _("Adopt child"));
3506
}
3507
3508
void PopupMenu::addSocialMenu()
3509
{
3510
    initPopup();
3511
    mBrowserBox->clearRows();
3512
    setMousePos();
3513
    const Party *const party = localPlayer->getParty();
3514
    if (party != nullptr)
3515
    {
3516
        // TRANSLATORS: popup menu item
3517
        // TRANSLATORS: leave party
3518
        mBrowserBox->addRow("/leaveparty", _("Leave party"));
3519
    }
3520
    else
3521
    {
3522
        // TRANSLATORS: popup menu item
3523
        // TRANSLATORS: create party
3524
        mBrowserBox->addRow("/createparty", _("Create party"));
3525
    }
3526
3527
    if (Net::getNetworkType() != ServerType::TMWATHENA)
3528
    {
3529
        const Guild *const guild = localPlayer->getGuild();
3530
        if (guild != nullptr)
3531
        {
3532
            // TRANSLATORS: popup menu item
3533
            // TRANSLATORS: leave guild
3534
            mBrowserBox->addRow("/leaveguild", _("Leave guild"));
3535
        }
3536
        else
3537
        {
3538
            // TRANSLATORS: popup menu item
3539
            // TRANSLATORS: create guild
3540
            mBrowserBox->addRow("/createguild", _("Create guild"));
3541
        }
3542
    }
3543
    mBrowserBox->addSeparator("##3---");
3544
}
3545
3546
void PopupMenu::showPartyPopup()
3547
{
3548
    addSocialMenu();
3549
3550
    // TRANSLATORS: popup menu item
3551
    // TRANSLATORS: close menu
3552
    mBrowserBox->addRow("cancel", _("Cancel"));
3553
    showPopup(mX, mY);
3554
}
3555
3556
void PopupMenu::showGuildPopup()
3557
{
3558
    addSocialMenu();
3559
3560
    // TRANSLATORS: popup menu item
3561
    // TRANSLATORS: change guild notice message
3562
    mBrowserBox->addRow("/guildnotice", _("Change notice"));
3563
3564
    // TRANSLATORS: popup menu item
3565
    // TRANSLATORS: close menu
3566
    mBrowserBox->addRow("cancel", _("Cancel"));
3567
    showPopup(mX, mY);
3568
}
3569
3570
void PopupMenu::showAttackPopup()
3571
{
3572
    addSocialMenu();
3573
3574
    // TRANSLATORS: popup menu item
3575
    // TRANSLATORS: close menu
3576
    mBrowserBox->addRow("cancel", _("Cancel"));
3577
    showPopup(mX, mY);
3578
}
3579
3580
void PopupMenu::showNavigationPopup()
3581
{
3582
    addSocialMenu();
3583
3584
    // TRANSLATORS: popup menu item
3585
    // TRANSLATORS: close menu
3586
    mBrowserBox->addRow("cancel", _("Cancel"));
3587
    showPopup(mX, mY);
3588
}
3589
3590
void PopupMenu::showPickupPopup()
3591
{
3592
    addSocialMenu();
3593
3594
    // TRANSLATORS: popup menu item
3595
    // TRANSLATORS: close menu
3596
    mBrowserBox->addRow("cancel", _("Cancel"));
3597
    showPopup(mX, mY);
3598
}
3599
3600
void PopupMenu::showPlayersPopup()
3601
{
3602
    addSocialMenu();
3603
3604
    // TRANSLATORS: popup menu item
3605
    // TRANSLATORS: close menu
3606
    mBrowserBox->addRow("cancel", _("Cancel"));
3607
    showPopup(mX, mY);
3608
}
3609
3610
void PopupMenu::showFriendsPopup()
3611
{
3612
    addSocialMenu();
3613
3614
    // TRANSLATORS: popup menu item
3615
    // TRANSLATORS: close menu
3616
    mBrowserBox->addRow("cancel", _("Cancel"));
3617
    showPopup(mX, mY);
3618
}
3619
3620
void PopupMenu::moveUp()
3621
{
3622
    mBrowserBox->moveSelectionUp();
3623
}
3624
3625
void PopupMenu::moveDown()
3626
{
3627
    mBrowserBox->moveSelectionDown();
3628
}
3629
3630
void PopupMenu::select()
3631
{
3632
    mBrowserBox->selectSelection();
3633

3
}