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