GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/gui/popups/popupmenu.cpp Lines: 20 1637 1.2 %
Date: 2017-11-29 Branches: 18 2805 0.6 %

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

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



56
    mAllowCleanMenu(true)
131
{
132
8
    mBrowserBox->setOpaque(Opaque_false);
133
4
    mBrowserBox->setLinkHandler(this);
134
4
    mRenameListener.setMapItem(nullptr);
135
8
    mRenameListener.setDialog(nullptr);
136
20
    mPlayerListener.setNick("");
137
8
    mPlayerListener.setDialog(nullptr);
138
8
    mPlayerListener.setType(ActorType::Unknown);
139

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

6
}