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