ManaPlus
game.cpp
Go to the documentation of this file.
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-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "game.h"
24 
25 #include "actormanager.h"
26 #include "client.h"
27 #include "configuration.h"
28 #include "effectmanager.h"
29 #include "eventsmanager.h"
30 #include "gamemodifiers.h"
31 #include "soundmanager.h"
32 #include "settings.h"
33 
34 #include "being/crazymoves.h"
35 #include "being/localplayer.h"
36 #include "being/playerinfo.h"
37 
38 #include "const/itemshortcut.h"
39 #include "const/spells.h"
40 
41 #include "const/gui/chat.h"
42 
44 
45 #include "fs/mkdir.h"
46 
47 #include "fs/virtfs/fs.h"
48 
49 #include "gui/dialogsmanager.h"
50 #include "gui/gui.h"
51 #include "gui/popupmanager.h"
52 #include "gui/viewport.h"
53 #include "gui/windowmanager.h"
54 #include "gui/windowmenu.h"
55 
56 #include "gui/fonts/font.h"
57 
60 
61 #include "gui/popups/popupmenu.h"
62 
63 #include "gui/windows/bankwindow.h"
65 #include "gui/windows/mailwindow.h"
66 #include "gui/windows/chatwindow.h"
72 #include "gui/windows/killstats.h"
73 #include "gui/windows/minimap.h"
75 #include "gui/windows/npcdialog.h"
78 #include "gui/windows/shopwindow.h"
86 
88 
94 
98 
99 #include "input/inputmanager.h"
100 #include "input/joystick.h"
101 #include "input/keyboardconfig.h"
102 
104 
105 #include "net/generalhandler.h"
106 #include "net/gamehandler.h"
107 #include "net/net.h"
108 #include "net/packetcounters.h"
109 
110 #include "particle/particleengine.h"
111 
113 #include "resources/mapreader.h"
115 
116 #include "resources/db/mapdb.h"
117 
118 #include "resources/map/map.h"
119 
121 
123 
124 #include "utils/delete2.h"
125 #include "utils/foreach.h"
126 #include "utils/gettext.h"
127 #include "utils/pnglib.h"
128 #include "utils/sdlcheckutils.h"
129 #include "utils/timer.h"
130 
131 #ifdef __native_client__
132 #include "utils/naclmessages.h"
133 #endif // __native_client__
134 
136 #include "listeners/errorlistener.h"
137 
138 #ifdef TMWA_SUPPORT
139 #include "net/tmwa/guildmanager.h"
140 #endif // TMWA_SUPPORT
141 
142 #ifdef USE_MUMBLE
143 #include "mumblemanager.h"
144 #endif // USE_MUMBLE
145 
146 #ifdef WIN32
147 #include <sys/time.h>
148 #undef ERROR
149 #endif // WIN32
150 
151 #include "debug.h"
152 
155 
156 bool mStatsReUpdated = false;
157 const time_t adjustDelay = 10;
158 
162 static void initEngines()
163 {
166 #ifdef TMWA_SUPPORT
168 #endif // TMWA_SUPPORT
169 
170  crazyMoves = new CrazyMoves;
171 
173  particleEngine->setMap(nullptr);
175  BeingInfo::init();
176 
177  if (gameHandler != nullptr)
179 
180  keyboard.update();
181  if (joystick != nullptr)
182  joystick->update();
183 
185 }
186 
190 static void createGuiWindows()
191 {
192  if (setupWindow != nullptr)
194 
195  if (emoteShortcut != nullptr)
196  emoteShortcut->load();
197 
199 
200  // Create dialogs
203  if (chatWindow != nullptr)
204  {
206  chatWindow = nullptr;
207  }
209  "Chat");
213  localPlayer,
214  false);
216  nullptr,
217  nullptr,
218  true);
225  {
228  }
233  if (debugWindow != nullptr)
234  {
236  debugWindow = nullptr;
237  }
239  "Debug");
241  "ItemShortcut", "items.xml", 83, 460);
242 
243  for (unsigned f = 0; f < SHORTCUT_TABS - 1; f ++)
244  {
246  new ItemShortcutContainer(nullptr, f));
247  }
249  {
251  new ItemShortcutContainer(nullptr, SHORTCUT_TABS - 1));
252  }
253  if (config.getBoolValue("showDidYouKnow"))
254  {
257  }
258 
260  "EmoteShortcut",
261  new EmoteShortcutContainer(nullptr),
262  "emotes.xml",
263  130, 480);
266  "DropShortcut",
267  new VirtShortcutContainer(nullptr, dropShortcut),
268  "drops.xml",
269  0, 0);
271  "SpellShortcut",
272  "spells.xml",
273  265, 328);
274  for (unsigned f = 0; f < SPELL_SHORTCUT_TABS; f ++)
275  {
277  new SpellShortcutContainer(nullptr, f));
278  }
279 
286 
287  // TRANSLATORS: chat tab header
288  localChatTab = new ChatTab(chatWindow, _("General"),
289  GENERAL_CHANNEL, "#General", ChatTabType::INPUT);
291  if (config.getBoolValue("showChatHistory"))
292  localChatTab->loadFromLogFile("#General");
293 
294  // TRANSLATORS: chat tab header
295  debugChatTab = new ChatTab(chatWindow, _("Debug"), "",
296  "#Debug", ChatTabType::DEBUG);
298 
299  if (assertListener != nullptr)
300  {
301  const StringVect &messages = assertListener->getMessages();
302  FOR_EACH (StringVectCIter, it, messages)
303  {
304  debugChatTab->chatLog(*it,
308  }
310  }
311  if (config.getBoolValue("enableTradeTab"))
313  else
314  tradeChatTab = nullptr;
315 
316  if (config.getBoolValue("enableBattleTab"))
317  {
320  }
321  else
322  {
323  battleChatTab = nullptr;
324  }
325 
327  if (!isSafeMode)
329 
330  if (setupWindow != nullptr)
332 
333  if (localPlayer != nullptr)
335 
336  if (generalHandler != nullptr)
338 }
339 
343 static void destroyGuiWindows()
344 {
345  if (generalHandler != nullptr)
347 
348  if (whoIsOnline != nullptr)
349  whoIsOnline->setAllowUpdate(false);
350 
351 #ifdef TMWA_SUPPORT
353 #endif // TMWA_SUPPORT
354 
356  delete2(localChatTab) // Need to do this first, so it can remove itself
362 #ifdef TMWA_SUPPORT
363  if (guildManager != nullptr && GuildManager::getEnableGuildBot())
364  guildManager->reload();
365 #endif // TMWA_SUPPORT
366 
367  logger->log("start deleting");
370  logger->log("end deleting");
394 }
395 
396 Game *Game::mInstance = nullptr;
397 
399  mCurrentMap(nullptr),
400  mMapName(""),
401  mValidSpeed(true),
402  mNextAdjustTime(cur_time + adjustDelay),
403  mAdjustLevel(0),
404  mAdjustPerfomance(config.getBoolValue("adjustPerfomance")),
405  mLowerCounter(0),
406  mPing(0),
407  mTime(cur_time + 1),
408  mTime2(cur_time + 10)
409 {
410  touchManager.setInGame(true);
411 
412 // assert(!mInstance);
413  if (mInstance != nullptr)
414  logger->log("error: double game creation");
415  mInstance = this;
416 
417  config.incValue("gamecount");
418 
419  disconnectedDialog = nullptr;
420 
421  // Create the viewport
422  viewport = new Viewport;
425 
427 
428  BasicContainer2 *const top = static_cast<BasicContainer2*>(gui->getTop());
429  if (top != nullptr)
430  top->add(viewport);
432 
435  config.getBoolValue("enableDelayedAnimations"));
436 
438  config.getBoolValue("enableCompoundSpriteDelay"));
439 
441  windowMenu = new WindowMenu(nullptr);
442 
443  if (windowContainer != nullptr)
445 
446 #ifdef USE_OPENGL
448 #endif // USE_OPENGL
449 
450  initEngines();
451 
454 
455  // Initialize beings
456  if (actorManager != nullptr)
458 
460 
461  if (setupWindow != nullptr)
462  setupWindow->setInGame(true);
463  clearKeysArray();
464 
465 #ifdef TMWA_SUPPORT
466  if (guildManager != nullptr && GuildManager::getEnableGuildBot())
468 #endif // TMWA_SUPPORT
469 
471  "disableLoggingInGame");
472 }
473 
475 {
476 #ifdef USE_OPENGL
478 #endif // USE_OPENGL
479 
481  touchManager.setInGame(false);
482  config.write();
486 
488 
492  if (effectManager != nullptr)
493  effectManager->clear();
498 #ifdef TMWA_SUPPORT
500 #endif // TMWA_SUPPORT
501 #ifdef USE_MUMBLE
502  delete2(mumbleManager)
503 #endif // USE_MUMBLE
504 
507 
509  mInstance = nullptr;
511 }
512 
514 {
515  if ((boldFont == nullptr) || !config.getBoolValue("addwatermark"))
516  return;
517 
518  const Color &color1 = theme->getColor(ThemeColorId::TEXT, 255);
519  const Color &color2 = theme->getColor(ThemeColorId::TEXT_OUTLINE, 255);
520 
522  color1,
523  color2,
525  100, 50);
526 }
527 
528 bool Game::createScreenshot(const std::string &prefix)
529 {
530  if ((mainGraphics == nullptr) || (screenshortHelper == nullptr))
531  return false;
532 
533  SDL_Surface *screenshot = nullptr;
534 
535  if (!config.getBoolValue("showip") && (gui != nullptr))
536  {
537  mainGraphics->setSecure(true);
539  gui->draw();
540  addWatermark();
541  screenshot = screenshortHelper->getScreenshot();
542  mainGraphics->setSecure(false);
543  }
544  else
545  {
546  addWatermark();
547  screenshot = screenshortHelper->getScreenshot();
548  }
549 
550  if (screenshot == nullptr)
551  return false;
552 
553  return saveScreenshot(screenshot, prefix);
554 }
555 
556 bool Game::saveScreenshot(SDL_Surface *const screenshot,
557  const std::string &prefix)
558 {
559  std::string screenshotDirectory = settings.screenshotDir;
560  if (mkdir_r(screenshotDirectory.c_str()) != 0)
561  {
562  logger->log("Directory %s doesn't exist and can't be created! "
563  "Setting screenshot directory to home.",
564  screenshotDirectory.c_str());
565  screenshotDirectory = std::string(VirtFs::getUserDir());
566  }
567 
568  // Search for an unused screenshot name
569  std::stringstream filename;
570  std::fstream testExists;
571 
572  time_t rawtime;
573  char buffer [100];
574  time(&rawtime);
575  struct tm *const timeinfo = localtime(&rawtime);
576  strftime(buffer, 99, "%Y-%m-%d_%H-%M-%S", timeinfo);
577 
578  const std::string serverName = settings.serverName;
579  std::string screenShortStr;
580  if (prefix.empty())
581  {
582  if (serverName.empty())
583  {
584  screenShortStr = strprintf("%s_Screenshot_%s_",
585  branding.getValue("appName", "ManaPlus").c_str(),
586  buffer);
587  }
588  else
589  {
590  screenShortStr = strprintf("%s_Screenshot_%s_%s_",
591  branding.getValue("appName", "ManaPlus").c_str(),
592  serverName.c_str(), buffer);
593  }
594 
595  bool found = false;
596  static unsigned int screenshotCount = 0;
597  do
598  {
599  screenshotCount++;
600  filename.str("");
601  filename << screenshotDirectory << "/";
602  filename << screenShortStr << screenshotCount << ".png";
603  testExists.open(filename.str().c_str(), std::ios::in);
604  found = !testExists.is_open();
605  testExists.close();
606  }
607  while (!found);
608  }
609  else
610  {
611  screenShortStr = prefix;
612  filename.str("");
613  filename << screenshotDirectory << "/";
614  filename << screenShortStr;
615  }
616 
617  const std::string fileNameStr = filename.str();
618  const bool success = PngLib::writePNG(screenshot, fileNameStr);
619 #ifdef __native_client__
620  std::string nacScreenshotlDir = fileNameStr;
621  cutFirst(nacScreenshotlDir, "/persistent");
622  naclPostMessage("copy-from-persistent", nacScreenshotlDir);
623  logger->log("nacl screenshot path: " + nacScreenshotlDir);
624 #endif // __native_client__
625 
626  if (success)
627  {
628  if (localChatTab != nullptr)
629  {
630  // TRANSLATORS: save file message
631  std::string str = strprintf(_("Screenshot saved as %s"),
632  fileNameStr.c_str());
633  localChatTab->chatLog(str,
637  }
638  }
639  else
640  {
641  if (localChatTab != nullptr)
642  {
643  // TRANSLATORS: save file message
644  localChatTab->chatLog(_("Saving screenshot failed!"),
648  }
649  logger->log1("Error: could not save screenshot.");
650  }
651 
652  MSDL_FreeSurface(screenshot);
653  return success;
654 }
655 
657 {
658  BLOCK_START("Game::logic")
659  handleInput();
660 
661  // Handle all necessary game logic
662  if (actorManager != nullptr)
663  actorManager->logic();
664  if (particleEngine != nullptr)
666  if (mCurrentMap != nullptr)
667  mCurrentMap->update(1);
668 
669  BLOCK_END("Game::logic")
670 }
671 
673 {
674  BLOCK_START("Game::slowLogic")
675  if (localPlayer != nullptr)
677  const time_t time = cur_time;
678  if (mTime != time)
679  {
680  if (valTest(Updated))
681  mValidSpeed = false;
682 
683  mTime = time + 1;
684  if (debugWindow != nullptr)
686  if (killStats != nullptr)
687  killStats->update();
688  if (socialWindow != nullptr)
690  if (whoIsOnline != nullptr)
693  if (killStats != nullptr)
694  cilk_spawn killStats->recalcStats();
695 
696  if (time > mTime2 || mTime2 - time > 10)
697  {
698  mTime2 = time + 10;
701  }
702  if (effectManager != nullptr)
703  effectManager->logic();
704  }
705 
708 
709 #ifdef TMWA_SUPPORT
710  if (shopWindow != nullptr)
711  cilk_spawn shopWindow->updateTimes();
712  if (guildManager != nullptr)
714 #endif // TMWA_SUPPORT
715 
716  if (skillDialog != nullptr)
717  cilk_spawn skillDialog->slowLogic();
718 
719  cilk_spawn PacketCounters::update();
720 
721  // Handle network stuff
722  if (!gameHandler->isConnected())
723  {
725  return; // Not a problem here
726 
727  if (client->getState() != State::ERROR)
728  {
729  if (disconnectedDialog == nullptr)
730  {
731  // TRANSLATORS: error message text
732  errorMessage = _("The connection to the server was lost.");
733  disconnectedDialog = DialogsManager::openErrorDialog(
734  // TRANSLATORS: error message header
735  _("Network Error"),
736  errorMessage,
737  Modal_false);
738  disconnectedDialog->addActionListener(&errorListener);
739  disconnectedDialog->requestMoveToTop();
740  }
741  }
742 
743  if ((viewport != nullptr) && !errorMessage.empty())
744  {
745  const Map *const map = viewport->getMap();
746  if (map != nullptr)
747  map->saveExtraLayer();
748  }
752  if (client->getState() != State::ERROR)
753  errorMessage.clear();
754  }
755  else
756  {
757  if (gameHandler->mustPing()
758  && get_elapsed_time1(mPing) > 3000)
759  {
760  mPing = tick_time;
762  }
763 
764  if (mAdjustPerfomance)
766  if (disconnectedDialog != nullptr)
767  {
768  disconnectedDialog->scheduleDelete();
769  disconnectedDialog = nullptr;
770  }
771  }
772  BLOCK_END("Game::slowLogic")
773 }
774 
776 {
777  FUNC_BLOCK("Game::adjustPerfomance", 1)
778  const time_t time = cur_time;
780  {
781  mNextAdjustTime = time + adjustDelay;
782  }
783  else if (mNextAdjustTime < time)
784  {
785  mNextAdjustTime = time + adjustDelay;
786 
787  if (mAdjustLevel > 3 ||
788  localPlayer == nullptr ||
791  {
792  return;
793  }
794 
795  int maxFps = WindowManager::getFramerate();
796  if (maxFps != config.getIntValue("fpslimit"))
797  return;
798 
799  if (maxFps == 0)
800  maxFps = 30;
801  else if (maxFps < 10)
802  return;
803 
804  if (fps < maxFps - 10)
805  {
806  if (mLowerCounter < 2)
807  {
808  mLowerCounter ++;
810  return;
811  }
812  mLowerCounter = 0;
813  mAdjustLevel ++;
814  switch (mAdjustLevel)
815  {
816  case 1:
817  {
818  if (config.getBoolValue("beingopacity"))
819  {
820  config.setValue("beingopacity", false);
821  config.setSilent("beingopacity", true);
822  if (localChatTab != nullptr)
823  {
825  // TRANSLATORS: auto adjust settings message
826  _("Auto disable Show beings transparency"),
830  }
831  }
832  else
833  {
834  mNextAdjustTime = time + 1;
835  mLowerCounter = 2;
836  }
837  break;
838  }
839  case 2:
841  {
843  if (localChatTab != nullptr)
844  {
846  // TRANSLATORS: auto adjust settings message
847  _("Auto lower Particle effects"),
851  }
852  }
853  else
854  {
855  mNextAdjustTime = time + 1;
856  mLowerCounter = 2;
857  }
858  break;
859  case 3:
860  if (!config.getBoolValue("alphaCache"))
861  {
862  config.setValue("alphaCache", true);
863  config.setSilent("alphaCache", false);
864  if (localChatTab != nullptr)
865  {
867  // TRANSLATORS: auto adjust settings message
868  _("Auto enable opacity cache"),
872  }
873  }
874  break;
875  default:
876  break;
877  }
878  }
879  }
880 }
881 
883 {
884  if (!mAdjustPerfomance)
885  return;
886 
888  switch (mAdjustLevel)
889  {
890  case 1:
891  config.setValue("beingopacity",
892  config.getBoolValue("beingopacity"));
893  break;
894  case 2:
895  config.setValue("beingopacity",
896  config.getBoolValue("beingopacity"));
898  "particleEmitterSkip") + 1;
899  break;
900  default:
901  case 3:
902  config.setValue("beingopacity",
903  config.getBoolValue("beingopacity"));
905  "particleEmitterSkip") + 1;
906  config.setValue("alphaCache",
907  config.getBoolValue("alphaCache"));
908  break;
909  }
910  mAdjustLevel = 0;
911 }
912 
914 {
915  BLOCK_START("Game::handleMove")
916  if (localPlayer == nullptr)
917  {
918  BLOCK_END("Game::handleMove")
919  return;
920  }
921 
922  // Moving player around
923  if ((chatWindow != nullptr) &&
924  (quitDialog == nullptr) &&
925  localPlayer->canMove() &&
929  {
930  NpcDialog *const dialog = NpcDialog::getActive();
931  if (dialog != nullptr)
932  {
933  BLOCK_END("Game::handleMove")
934  return;
935  }
936 
937  // Ignore input if either "ignore" key is pressed
938  // Stops the character moving about if the user's window manager
939  // uses "ignore+arrow key" to switch virtual desktops.
942  {
943  BLOCK_END("Game::handleMove")
944  return;
945  }
946 
947  unsigned char direction = 0;
948 
949  // Translate pressed keys to movement and direction
951  ((joystick != nullptr) && joystick->isUp()))
952  {
953  direction |= BeingDirection::UP;
954  setValidSpeed();
956  }
958  ((joystick != nullptr) && joystick->isDown()))
959  {
960  direction |= BeingDirection::DOWN;
961  setValidSpeed();
963  }
964 
966  ((joystick != nullptr) && joystick->isLeft()))
967  {
968  direction |= BeingDirection::LEFT;
969  setValidSpeed();
971  }
973  ((joystick != nullptr) && joystick->isRight()))
974  {
975  direction |= BeingDirection::RIGHT;
976  setValidSpeed();
978  }
980  {
981  direction = localPlayer->getDirection();
982  setValidSpeed();
984  }
985 
990  || direction == 0)
991  {
992  moveInDirection(direction);
993  }
994  }
995  BLOCK_END("Game::handleMove")
996 }
997 
998 void Game::moveInDirection(const unsigned char direction)
999 {
1000  if (viewport == nullptr)
1001  return;
1002 
1003  if (settings.cameraMode == 0u)
1004  {
1005  if (localPlayer != nullptr)
1006  localPlayer->specialMove(direction);
1007  }
1008  else
1009  {
1010  int dx = 0;
1011  int dy = 0;
1012  if ((direction & BeingDirection::LEFT) != 0)
1013  dx = -5;
1014  else if ((direction & BeingDirection::RIGHT) != 0)
1015  dx = 5;
1016 
1017  if ((direction & BeingDirection::UP) != 0)
1018  dy = -5;
1019  else if ((direction & BeingDirection::DOWN) != 0)
1020  dy = 5;
1021  viewport->moveCamera(dx, dy);
1022  }
1023 }
1024 
1025 void Game::updateFrameRate(int fpsLimit)
1026 {
1027  if (fpsLimit == 0)
1028  {
1029  if (settings.awayMode)
1030  {
1033  {
1034  fpsLimit = config.getIntValue("fpslimit");
1035  }
1036  else
1037  {
1038  fpsLimit = config.getIntValue("altfpslimit");
1039  }
1040  }
1041  else
1042  {
1043  fpsLimit = config.getIntValue("fpslimit");
1044  }
1045  }
1046  WindowManager::setFramerate(fpsLimit);
1048 }
1049 
1054 {
1055  BLOCK_START("Game::handleInput 1")
1056  if (joystick != nullptr)
1057  joystick->logic();
1058 
1060 
1061  // If the user is configuring the keys then don't respond.
1062  if (!keyboard.isEnabled() || settings.awayMode)
1063  {
1064  BLOCK_END("Game::handleInput 1")
1065  return;
1066  }
1067 
1068  // If pressed outfits keys, stop processing keys.
1071  || ((setupWindow != nullptr) && setupWindow->isWindowVisible()))
1072  {
1073  BLOCK_END("Game::handleInput 1")
1074  return;
1075  }
1076 
1077  handleMove();
1079  BLOCK_END("Game::handleInput 1")
1080 }
1081 
1086 void Game::changeMap(const std::string &mapPath)
1087 {
1088  BLOCK_START("Game::changeMap")
1089 
1090  resetAdjustLevel();
1092 
1095 
1096  // Clean up floor items, beings and particles
1097  if (actorManager != nullptr)
1098  actorManager->clear();
1099 
1100  // Close the popup menu on map change so that invalid options can't be
1101  // executed.
1102  if (viewport != nullptr)
1104 
1105  // Unset the map of the player so that its particles are cleared before
1106  // being deleted in the next step
1107  if (localPlayer != nullptr)
1108  localPlayer->setMap(nullptr);
1109 
1110  if (particleEngine != nullptr)
1111  particleEngine->clear();
1112 
1113  mMapName = mapPath;
1114 
1115  std::string fullMap = pathJoin(paths.getValue("maps", "maps/"),
1116  mMapName).append(".tmx");
1117  std::string realFullMap = pathJoin(paths.getValue("maps", "maps/"),
1118  MapDB::getMapName(mMapName)).append(".tmx");
1119 
1120  if (!VirtFs::exists(realFullMap))
1121  realFullMap.append(".gz");
1122 
1123  // Attempt to load the new map
1124  Map *const newMap = MapReader::readMap(fullMap, realFullMap);
1125 
1126  if (mCurrentMap != nullptr)
1128 
1129  if (newMap != nullptr)
1130  newMap->addExtraLayer();
1131 
1132  if (socialWindow != nullptr)
1133  socialWindow->setMap(newMap);
1134 
1135  // Notify the minimap and actorManager about the map change
1136  if (minimap != nullptr)
1137  minimap->setMap(newMap);
1138  if (actorManager != nullptr)
1139  actorManager->setMap(newMap);
1140  if (particleEngine != nullptr)
1141  particleEngine->setMap(newMap);
1142  if (viewport != nullptr)
1143  viewport->setMap(newMap);
1144 
1145  // Initialize map-based particle effects
1146  if (newMap != nullptr)
1147  newMap->initializeParticleEffects();
1148 
1149  // Start playing new music file when necessary
1150  const std::string oldMusic = mCurrentMap != nullptr
1151  ? mCurrentMap->getMusicFile() : "";
1152  const std::string newMusic = newMap != nullptr ?
1153  newMap->getMusicFile() : "";
1154  if (newMusic != oldMusic)
1155  {
1156  if (newMusic.empty())
1157  soundManager.fadeOutMusic(1000);
1158  else
1159  soundManager.fadeOutAndPlayMusic(newMusic, 1000);
1160  }
1161 
1162  if (mCurrentMap != nullptr)
1164 
1165  delete mCurrentMap;
1166  mCurrentMap = newMap;
1167 
1168  if (questsWindow != nullptr)
1170 
1171 #ifdef USE_MUMBLE
1172  if (mumbleManager)
1173  mumbleManager->setMap(mapPath);
1174 #endif // USE_MUMBLE
1175 
1176  if (localPlayer != nullptr)
1178 
1180  BLOCK_END("Game::changeMap")
1181 }
1182 
1183 void Game::updateHistory(const SDL_Event &event)
1184 {
1185  if ((localPlayer == nullptr) || (settings.attackType == 0u))
1186  return;
1187 
1188  if (CAST_S32(event.key.keysym.sym) != -1)
1189  {
1190  bool old = false;
1191 
1192  const InputActionT key = KeyboardConfig::getKeyIndex(event, 1);
1193  const time_t time = cur_time;
1194  int idx = -1;
1195  for (int f = 0; f < MAX_LASTKEYS; f ++)
1196  {
1197  LastKey &lastKey = mLastKeys[f];
1198  if (lastKey.key == key)
1199  {
1200  idx = f;
1201  old = true;
1202  break;
1203  }
1204  else if (idx >= 0 && lastKey.time < mLastKeys[idx].time)
1205  {
1206  idx = f;
1207  }
1208  }
1209  if (idx < 0)
1210  {
1211  idx = 0;
1212  for (int f = 0; f < MAX_LASTKEYS; f ++)
1213  {
1214  LastKey &lastKey = mLastKeys[f];
1215  if (lastKey.key == InputAction::NO_VALUE ||
1216  lastKey.time < mLastKeys[idx].time)
1217  {
1218  idx = f;
1219  }
1220  }
1221  }
1222 
1223  if (idx < 0)
1224  idx = 0;
1225 
1226  LastKey &keyIdx = mLastKeys[idx];
1227  if (!old)
1228  {
1229  keyIdx.time = time;
1230  keyIdx.key = key;
1231  keyIdx.cnt = 0;
1232  }
1233  else
1234  {
1235  keyIdx.cnt++;
1236  }
1237  }
1238 }
1239 
1241 {
1242  const int timeRange = 120;
1243  const int cntInTime = 130;
1244 
1245  if ((localPlayer == nullptr) || (settings.attackType == 0u))
1246  return;
1247 
1248  const time_t time = cur_time;
1249  for (int f = 0; f < MAX_LASTKEYS; f ++)
1250  {
1251  LastKey &lastKey = mLastKeys[f];
1252  if (lastKey.key != InputAction::NO_VALUE)
1253  {
1254  if (lastKey.time + timeRange < time)
1255  {
1256  if (lastKey.cnt > cntInTime)
1257  mValidSpeed = false;
1258  lastKey.key = InputAction::NO_VALUE;
1259  }
1260  }
1261  }
1262 }
1263 
1265 {
1266  clearKeysArray();
1267  mValidSpeed = true;
1268 }
1269 
1271 {
1272  for (int f = 0; f < MAX_LASTKEYS; f ++)
1273  {
1274  mLastKeys[f].time = 0;
1276  mLastKeys[f].cnt = 0;
1277  }
1278 }
1279 
1280 void Game::videoResized(const int width, const int height)
1281 {
1282  if (viewport != nullptr)
1283  viewport->setSize(width, height);
1284  if (windowMenu != nullptr)
1285  windowMenu->setPosition(width - windowMenu->getWidth(), 0);
1286 }
void setSize(const int width, const int height)
Definition: widget.cpp:366
void gameDestroyed()
Definition: playerinfo.cpp:460
Configuration branding
void scheduleDelete()
#define CREATEWIDGETV0(var, type)
Definition: createwidget.h:31
DebugWindow * debugWindow
Definition: debugwindow.cpp:39
ChatWindow * chatWindow
Definition: chatwindow.cpp:88
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
bool mAdjustPerfomance
Definition: game.h:148
#define _(s)
Definition: gettext.h:34
DropShortcut * dropShortcut
static void init()
void checkKeys()
Definition: game.cpp:1240
int getWidth() const
Definition: widget.h:220
void updateFrameRate(int fpsLimit)
Definition: game.cpp:1025
void log1(const char *const log_text)
Definition: logger.cpp:222
Font * boldFont
Definition: gui.cpp:111
static bool createScreenshot(const std::string &prefix)
Definition: game.cpp:528
void showGMTab()
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:30
void clearWindowsForReset()
Definition: setupwindow.h:67
#define valTest(num)
std::string serverName
Definition: settings.h:112
unsigned int attackType
Definition: settings.h:136
TradeWindow * tradeWindow
Definition: tradewindow.cpp:64
volatile int tick_time
Definition: timer.cpp:52
ChatTab * localChatTab
Definition: chattab.cpp:61
Gui * gui
Definition: gui.cpp:110
static Game * mInstance
Definition: game.h:154
const bool Visible_true
Definition: visible.h:29
void setValidSpeed()
Definition: game.cpp:1264
OutfitWindow * outfitWindow
QuestsWindow * questsWindow
void slowLogic()
Joystick * joystick
Definition: joystick.cpp:42
WindowContainer * windowContainer
Equipment * getEquipment()
Definition: playerinfo.cpp:217
LangTab * langChatTab
Definition: langtab.cpp:27
time_t time
Definition: game.h:53
QuitDialog * quitDialog
Definition: game.cpp:153
virtual void gameStarted() const =0
static void init()
void addActionListener(ActionListener *const actionListener)
Definition: widget.cpp:251
void setMap(Map *const map)
void setVisible(Visible visible)
const std::string getMusicFile() const
Definition: map.cpp:823
std::string pathJoin(std::string str1, const std::string &str2)
static void clear()
void handleInput()
Definition: game.cpp:1053
static NpcDialog * getActive()
Definition: npcdialog.cpp:851
virtual void requestMoveToTop()
Definition: widget.cpp:212
int mkdir_r(const char *const pathname)
Create a directory, making leading components first if necessary.
Definition: mkdir.cpp:108
void updateStatus() const
TradeTab * tradeChatTab
Definition: tradetab.cpp:35
Inventory * getInventory()
Definition: playerinfo.cpp:192
BankWindow * bankWindow
Definition: bankwindow.cpp:39
Definition: window.h:98
int mWidth
Definition: graphics.h:483
#define MSDL_FreeSurface(surface)
Definition: debug.h:53
void setPlayer(LocalPlayer *const player)
void postConnection()
#define BLOCK_START(name)
Definition: perfomance.h:78
SoundManager soundManager
ParticleEngine * particleEngine
Configuration config
void postConnection()
Definition: mailwindow.cpp:340
const unsigned int SPELL_SHORTCUT_TABS
Definition: spells.h:29
void clear()
Definition: playerinfo.cpp:449
time_t mTime2
Definition: game.h:152
void fadeOutMusic(const int ms)
int mLowerCounter
Definition: game.h:149
void cancelFollow()
bool isInputFocused() const
Definition: chatwindow.cpp:573
StatusWindow * statusWindow
void handleGameEvents() const
static void addWatermark()
Definition: game.cpp:513
bool screenshot(InputEvent &event)
Definition: actions.cpp:50
WhoIsOnline * whoIsOnline
Definition: whoisonline.cpp:78
#define BLOCK_END(name)
Definition: perfomance.h:79
const bool TryRemoveColors_true
void chatLog(std::string line, ChatMsgTypeT own, const IgnoreRecord ignoreRecord, const TryRemoveColors tryRemoveColors)
Definition: chattab.cpp:110
static int emitterSkip
uint8_t getDirection() const
Definition: being.h:487
int getIntValue(const std::string &key) const
bool isPopupVisible() const
Definition: popup.h:173
void draw()
Definition: gui.cpp:469
bool isUp() const
Definition: joystick.h:104
bool mValidSpeed
Definition: game.h:144
const char * getUserDir()
Definition: fs.cpp:83
const StringVect & getMessages() const
Client * client
Definition: client.cpp:113
std::vector< std::string > StringVect
Definition: stringvector.h:28
#define CREATEWIDGETV(var, type,...)
Definition: createwidget.h:24
volatile int fps
Definition: timer.cpp:53
#define delete2(var)
Definition: delete2.h:24
const Image *restrict const top
Configuration serverConfig
void slowLogic()
InventoryWindow * inventoryWindow
static void update()
Net::GeneralHandler * generalHandler
Definition: net.cpp:81
DidYouKnowWindow * didYouKnowWindow
bool isLeft() const
Definition: joystick.h:110
WindowMenu * windowMenu
Definition: windowmenu.cpp:47
bool isEnabled() const
void slowLogic()
Definition: debugwindow.cpp:94
static void unloadEmptyAtlas()
Definition: mapreader.cpp:1320
bool isActionActive(const InputActionT index) const
BeingSlot * emptyBeingSlot
Definition: beingslot.cpp:25
void setSilent(const std::string &key, const std::string &value)
bool mStatsReUpdated
Definition: game.cpp:156
static void setEnableDelay(bool b)
Logger * logger
Definition: logger.cpp:95
void loadFromLogFile(const std::string &name)
Definition: chattab.cpp:510
void slowLogic()
Definition: game.cpp:672
ShortcutWindow * dropShortcutWindow
BattleTab * battleChatTab
Definition: battletab.cpp:31
KillStats * killStats
Definition: killstats.cpp:45
void update()
Definition: joystick.cpp:350
virtual void prepare()=0
time_t mNextAdjustTime
Definition: game.h:146
void logic()
Definition: game.cpp:656
std::string errorMessage
Definition: client.cpp:111
Settings settings
Definition: settings.cpp:31
virtual void initEngines() const =0
MiniStatusWindow * miniStatusWindow
static void clearPopup()
~Game()
Definition: game.cpp:474
std::string screenshotDir
Definition: settings.h:113
bool getBoolValue(const std::string &key) const
void changeMap(const std::string &mapName)
Definition: game.cpp:1086
int get_elapsed_time1(const int startTime)
Definition: timer.cpp:104
Inventory * getCartInventory()
Definition: playerinfo.cpp:204
static void handleRepeat()
void externalUpdate()
static void videoResized(const int width, const int height)
Definition: game.cpp:1280
bool writePNG(SDL_Surface *const surface, const std::string &filename)
Definition: pnglib.cpp:36
#define CAST_S32
Definition: cast.h:29
std::string strprintf(const char *const format,...)
Definition: stringutils.cpp:99
ChatTab * addSpecialChannelTab(const std::string &name, const bool switchTo)
void setFramerate(const unsigned int fpsLimit)
void loadState()
void setInGame(const bool inGame)
const bool Visible_false
Definition: visible.h:29
EmoteWindow * emoteWindow
Definition: emotewindow.cpp:48
void initializeParticleEffects() const
Definition: map.cpp:1096
static bool saveScreenshot(SDL_Surface *const screenshot, const std::string &prefix)
Definition: game.cpp:556
Definition: game.h:62
CrazyMoves * crazyMoves
Definition: crazymoves.cpp:46
void handleMove()
Definition: game.cpp:913
static void destroyGuiWindows()
Definition: game.cpp:343
void updateTimes()
static bool isAnyInputFocused()
int mAdjustLevel
Definition: game.h:147
void requestGuildInfo()
LocalPlayer * localPlayer
PopupMenu * popupMenu
Definition: popupmenu.cpp:102
GuildManager * guildManager
EquipmentWindow * beingEquipmentWindow
void drawString(Graphics *const graphics, Color col, const Color &col2, const std::string &text, const int x, const int y)
Definition: font.cpp:253
virtual void add(Widget *const widget)
void setSecure(const bool n)
Definition: graphics.h:289
const bool IgnoreRecord_false
Definition: ignorerecord.h:29
static bool getEnableGuildBot()
Definition: guildmanager.h:55
std::string mMapName
Definition: game.h:143
RenderType getOpenGL() const
Definition: graphics.h:307
KeyboardFocusT inputFocused
Definition: settings.h:152
ErrorListener errorListener
void setMap(Map *const map)
void moveCamera(const int dx, const int dy)
Definition: viewport.cpp:1069
void setAllowUpdate(const bool n)
Definition: whoisonline.h:89
InputAction ::T InputActionT
Definition: inputaction.h:714
#define nullptr
Definition: localconsts.h:44
Graphics * mainGraphics
Definition: graphics.cpp:108
void setMap(const Map *const map)
Definition: minimap.cpp:118
bool isWindowVisible() const
Definition: window.h:483
void setMap(Map *const map)
Definition: viewport.cpp:88
ShortcutWindow * itemShortcutWindow
void updateHistory(const SDL_Event &event)
Definition: game.cpp:1183
const unsigned int SHORTCUT_TABS
Definition: itemshortcut.h:27
void setPosition(const int x, const int y)
Definition: widget.cpp:160
void cleanHoverItems()
Definition: viewport.cpp:258
static void closePopupMenu()
ShortcutWindow * spellShortcutWindow
Game()
Definition: game.cpp:398
static void closeDialogs()
int mHeight
Definition: graphics.h:484
volatile time_t cur_time
Definition: timer.cpp:57
const Color & getColor(ThemeColorIdT type, const unsigned int alpha)
Definition: theme.h:135
const std::string getMapName(const std::string &name)
Definition: mapdb.cpp:193
void cutFirst(std::string &str1, const std::string &str2)
void setMap(const Map *const map)
SocialWindow * socialWindow
#define FUNC_BLOCK(name, id)
Definition: perfomance.h:80
bool isRight() const
Definition: joystick.h:113
static const int MAX_LASTKEYS
Definition: game.h:37
void update(const int ticks)
Definition: map.cpp:319
Definition: map.h:68
AssertListener * assertListener
static Map * readMap(const std::string &filename, const std::string &realFilename)
virtual void ping(const int tick) const =0
virtual void scheduleDelete()
Definition: window.cpp:826
EventsManager eventsManager
unsigned int cameraMode
Definition: settings.h:142
void saveExtraLayer() const
Definition: map.cpp:1213
ShortcutWindow * emoteShortcutWindow
static void loadEmptyAtlas()
Definition: mapreader.cpp:1304
bool isDown() const
Definition: joystick.h:107
const std::string GENERAL_CHANNEL
Definition: chat.h:28
Definition: game.h:43
ShopWindow * shopWindow
Definition: shopwindow.cpp:99
bool disableLoggingInGame
Definition: settings.h:158
ServerTypeT getNetworkType()
Definition: net.cpp:178
Configuration paths
bool isSafeMode
Definition: client.cpp:118
EmoteShortcut * emoteShortcut
void setMap(Map *const map)
ChatTab * debugChatTab
Definition: chattab.cpp:62
SkillDialog * skillDialog
Definition: skilldialog.cpp:65
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
std::string getValue(const std::string &key, const std::string &deflt) const
Theme * theme
Definition: theme.cpp:61
virtual void setVisible(Visible visible)
Definition: window.cpp:773
static void reReadConfig()
Definition: being.cpp:3405
void setInGame(const bool b)
void adjustPerfomance()
Definition: game.cpp:775
InventoryWindow * cartWindow
GmTab * gmChatTab
Definition: gmtab.cpp:33
Widget * getTop() const
Definition: gui.h:247
bool canMove() const
virtual void mapLoadedEvent() const =0
virtual void requestMoveToBottom()
Definition: widget.cpp:218
bool exists(std::string name)
Definition: fs.cpp:123
StateT getState() const
Definition: client.h:68
virtual void gameEnded() const =0
static void initEngines()
Definition: game.cpp:162
virtual bool mustPing() const =0
EquipmentWindow * equipmentWindow
Map * mCurrentMap
Definition: game.h:142
Window * disconnectedDialog
Definition: game.cpp:154
bool awayMode
Definition: settings.h:155
virtual bool isConnected() const =0
static InputActionT getKeyIndex(const SDL_Event &event, const int grp)
void recalcStats()
Definition: killstats.cpp:309
time_t mTime
Definition: game.h:151
void logic()
Definition: joystick.cpp:221
Definition: color.h:74
static void clearCache()
Definition: being.cpp:4690
KeyboardConfig keyboard
int mPing
Definition: game.h:150
SetupWindow * setupWindow
Definition: setupwindow.cpp:63
InputManager inputManager
TouchManager touchManager
static void createGuiWindows()
Definition: game.cpp:190
MailWindow * mailWindow
Definition: mailwindow.cpp:53
void update()
Definition: killstats.cpp:363
void setMap(Map *const map)
Definition: socialwindow.h:103
LastKey mLastKeys[MAX_LASTKEYS]
Definition: game.h:145
void log(const char *const log_text,...)
Definition: logger.cpp:243
static void delayedLoad()
ScreenshotHelper * screenshortHelper
Map * getMap() const
Definition: viewport.h:134
const std::string TRADE_CHANNEL
Definition: chat.h:30
static Window * openErrorDialog(const std::string &header, const std::string &message, const Modal modal)
static void moveInDirection(const unsigned char direction)
Definition: game.cpp:998
void slowLogic()
Net::GameHandler * gameHandler
Definition: net.cpp:84
void fadeOutAndPlayMusic(const std::string &fileName, const int ms)
virtual SDL_Surface * getScreenshot()=0
void incValue(const std::string &key)
EffectManager * effectManager
void clearKeysArray()
Definition: game.cpp:1270
void setValue(const std::string &key, const std::string &value)
void setAllowHighlight(const bool n)
Definition: chattab.h:160
bool mouseFocused
Definition: settings.h:153
void specialMove(const unsigned char direction)
static void setEnableCache(const bool b)
void addTab(const std::string &name, ShortcutContainer *const content)
void recreateItemParticles()
Definition: being.cpp:5134
void loadData(int num)
static void init()
Definition: beinginfo.cpp:222
ActorManager * actorManager
Viewport * viewport
Definition: viewport.cpp:35
void addExtraLayer()
Definition: map.cpp:1129
CutInWindow * cutInWindow
Definition: cutinwindow.cpp:36
Minimap * minimap
Definition: minimap.cpp:61
void resetAdjustLevel()
Definition: game.cpp:882
const time_t adjustDelay
Definition: game.cpp:157
int cnt
Definition: game.h:55
bool getHalfAway() const
Definition: localplayer.h:238
InputActionT key
Definition: game.h:54