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"
64 #include "gui/windows/clanwindow.h"
66 #include "gui/windows/mailwindow.h"
67 #include "gui/windows/chatwindow.h"
73 #include "gui/windows/killstats.h"
74 #include "gui/windows/minimap.h"
76 #include "gui/windows/npcdialog.h"
79 #include "gui/windows/shopwindow.h"
87 
89 
95 
99 
100 #include "input/inputmanager.h"
101 #include "input/joystick.h"
102 #include "input/keyboardconfig.h"
103 
105 
106 #include "net/generalhandler.h"
107 #include "net/gamehandler.h"
108 #include "net/net.h"
109 #include "net/packetcounters.h"
110 
111 #include "particle/particleengine.h"
112 
114 #include "resources/mapreader.h"
116 
117 #include "resources/db/mapdb.h"
118 
119 #include "resources/map/map.h"
120 
122 
124 
125 #include "utils/delete2.h"
126 #include "utils/foreach.h"
127 #include "utils/gettext.h"
128 #include "utils/perfstat.h"
129 #include "utils/pnglib.h"
130 #include "utils/sdlcheckutils.h"
131 #include "utils/timer.h"
132 
133 #ifdef __native_client__
134 #include "utils/naclmessages.h"
135 #endif // __native_client__
136 
138 #include "listeners/errorlistener.h"
139 
140 #ifdef TMWA_SUPPORT
141 #include "net/tmwa/guildmanager.h"
142 #endif // TMWA_SUPPORT
143 
144 #ifdef USE_MUMBLE
145 #include "mumblemanager.h"
146 #endif // USE_MUMBLE
147 
148 #ifdef WIN32
149 #include <sys/time.h>
150 #undef ERROR
151 #endif // WIN32
152 
153 #include <fstream>
154 
155 #include "debug.h"
156 
159 
160 bool mStatsReUpdated = false;
161 const time_t adjustDelay = 10;
162 
166 static void initEngines()
167 {
170 #ifdef TMWA_SUPPORT
172 #endif // TMWA_SUPPORT
173 
174  crazyMoves = new CrazyMoves;
175 
177  particleEngine->setMap(nullptr);
179  BeingInfo::init();
180 
181  if (gameHandler != nullptr)
183 
184  keyboard.update();
185  if (joystick != nullptr)
186  joystick->update();
187 
189 }
190 
194 static void createGuiWindows()
195 {
196  if (setupWindow != nullptr)
198 
199  if (emoteShortcut != nullptr)
200  emoteShortcut->load();
201 
203 
204  // Create dialogs
207  if (chatWindow != nullptr)
208  {
210  chatWindow = nullptr;
211  }
213  "Chat");
217  localPlayer,
218  false);
220  nullptr,
221  nullptr,
222  true);
229  {
232  }
237  if (debugWindow != nullptr)
238  {
240  debugWindow = nullptr;
241  }
243  "Debug");
245  "ItemShortcut", "items.xml", 83, 460);
246 
247  for (unsigned f = 0; f < SHORTCUT_TABS - 1; f ++)
248  {
250  new ItemShortcutContainer(nullptr, f));
251  }
253  {
255  new ItemShortcutContainer(nullptr, SHORTCUT_TABS - 1));
256  }
257  if (config.getBoolValue("showDidYouKnow"))
258  {
261  }
262 
264  "EmoteShortcut",
265  new EmoteShortcutContainer(nullptr),
266  "emotes.xml",
267  130, 480);
270  "DropShortcut",
271  new VirtShortcutContainer(nullptr, dropShortcut),
272  "drops.xml",
273  0, 0);
275  "SpellShortcut",
276  "spells.xml",
277  265, 328);
278  for (unsigned f = 0; f < SPELL_SHORTCUT_TABS; f ++)
279  {
281  new SpellShortcutContainer(nullptr, f));
282  }
283 
291 
292  // TRANSLATORS: chat tab header
293  localChatTab = new ChatTab(chatWindow, _("General"),
294  GENERAL_CHANNEL, "#General", ChatTabType::INPUT);
296  if (config.getBoolValue("showChatHistory"))
297  localChatTab->loadFromLogFile("#General");
298 
299  // TRANSLATORS: chat tab header
300  debugChatTab = new ChatTab(chatWindow, _("Debug"), "",
301  "#Debug", ChatTabType::DEBUG);
303 
304  if (assertListener != nullptr)
305  {
306  const StringVect &messages = assertListener->getMessages();
307  FOR_EACH (StringVectCIter, it, messages)
308  {
309  debugChatTab->chatLog(*it,
313  }
315  }
316  if (config.getBoolValue("enableTradeTab"))
318  else
319  tradeChatTab = nullptr;
320 
321  if (config.getBoolValue("enableBattleTab"))
322  {
325  }
326  else
327  {
328  battleChatTab = nullptr;
329  }
330 
332  if (!isSafeMode)
334 
335  if (setupWindow != nullptr)
337 
338  if (localPlayer != nullptr)
340 
341  if (generalHandler != nullptr)
343 }
344 
348 static void destroyGuiWindows()
349 {
350  if (generalHandler != nullptr)
352 
353  if (whoIsOnline != nullptr)
354  whoIsOnline->setAllowUpdate(false);
355 
356 #ifdef TMWA_SUPPORT
358 #endif // TMWA_SUPPORT
359 
361  delete2(localChatTab) // Need to do this first, so it can remove itself
367 #ifdef TMWA_SUPPORT
368  if (guildManager != nullptr && GuildManager::getEnableGuildBot())
369  guildManager->reload();
370 #endif // TMWA_SUPPORT
371 
372  logger->log("start deleting");
375  logger->log("end deleting");
400 }
401 
402 Game *Game::mInstance = nullptr;
403 
405  mCurrentMap(nullptr),
406  mMapName(""),
407  mValidSpeed(true),
408  mNextAdjustTime(cur_time + adjustDelay),
409  mAdjustLevel(0),
410  mAdjustPerfomance(config.getBoolValue("adjustPerfomance")),
411  mLowerCounter(0),
412  mPing(0),
413  mTime(cur_time + 1),
414  mTime2(cur_time + 10)
415 {
416  touchManager.setInGame(true);
417 
418 // assert(!mInstance);
419  if (mInstance != nullptr)
420  logger->log("error: double game creation");
421  mInstance = this;
422 
423  config.incValue("gamecount");
424 
425  disconnectedDialog = nullptr;
426 
427  // Create the viewport
428  viewport = new Viewport;
431 
433 
434  BasicContainer2 *const top = static_cast<BasicContainer2*>(gui->getTop());
435  if (top != nullptr)
436  top->add(viewport);
438 
441  config.getBoolValue("enableDelayedAnimations"));
442 
444  config.getBoolValue("enableCompoundSpriteDelay"));
445 
447  windowMenu = new WindowMenu(nullptr);
448 
449  if (windowContainer != nullptr)
451 
452 #ifdef USE_OPENGL
454 #endif // USE_OPENGL
455 
456  initEngines();
457 
460 
461  // Initialize beings
462  if (actorManager != nullptr)
464 
466 
467  if (setupWindow != nullptr)
468  setupWindow->setInGame(true);
469  clearKeysArray();
470 
471 #ifdef TMWA_SUPPORT
472  if (guildManager != nullptr && GuildManager::getEnableGuildBot())
474 #endif // TMWA_SUPPORT
475 
477  "disableLoggingInGame");
478 }
479 
481 {
482 #ifdef USE_OPENGL
484 #endif // USE_OPENGL
485 
487  touchManager.setInGame(false);
488  config.write();
492 
494 
498  if (effectManager != nullptr)
499  effectManager->clear();
504 #ifdef TMWA_SUPPORT
506 #endif // TMWA_SUPPORT
507 #ifdef USE_MUMBLE
508  delete2(mumbleManager)
509 #endif // USE_MUMBLE
510 
513 
515  mInstance = nullptr;
517 }
518 
520 {
521  if ((boldFont == nullptr) || !config.getBoolValue("addwatermark"))
522  return;
523 
524  const Color &color1 = theme->getColor(ThemeColorId::TEXT, 255);
525  const Color &color2 = theme->getColor(ThemeColorId::TEXT_OUTLINE, 255);
526 
528  color1,
529  color2,
531  100, 50);
532 }
533 
534 bool Game::createScreenshot(const std::string &prefix)
535 {
536  if ((mainGraphics == nullptr) || (screenshortHelper == nullptr))
537  return false;
538 
539  SDL_Surface *screenshot = nullptr;
540 
541  if (!config.getBoolValue("showip") && (gui != nullptr))
542  {
543  mainGraphics->setSecure(true);
545  gui->draw();
546  addWatermark();
547  screenshot = screenshortHelper->getScreenshot();
548  mainGraphics->setSecure(false);
549  }
550  else
551  {
552  addWatermark();
553  screenshot = screenshortHelper->getScreenshot();
554  }
555 
556  if (screenshot == nullptr)
557  return false;
558 
559  return saveScreenshot(screenshot, prefix);
560 }
561 
562 bool Game::saveScreenshot(SDL_Surface *const screenshot,
563  const std::string &prefix)
564 {
565  std::string screenshotDirectory = settings.screenshotDir;
566  if (mkdir_r(screenshotDirectory.c_str()) != 0)
567  {
568  logger->log("Directory %s doesn't exist and can't be created! "
569  "Setting screenshot directory to home.",
570  screenshotDirectory.c_str());
571  screenshotDirectory = std::string(VirtFs::getUserDir());
572  }
573 
574  // Search for an unused screenshot name
575  std::stringstream filename;
576  std::fstream testExists;
577 
578  time_t rawtime;
579  char buffer [100];
580  time(&rawtime);
581  struct tm *const timeinfo = localtime(&rawtime);
582  strftime(buffer, 99, "%Y-%m-%d_%H-%M-%S", timeinfo);
583 
584  const std::string serverName = settings.serverName;
585  std::string screenShortStr;
586  if (prefix.empty())
587  {
588  if (serverName.empty())
589  {
590  screenShortStr = strprintf("%s_Screenshot_%s_",
591  branding.getValue("appName", "ManaPlus").c_str(),
592  buffer);
593  }
594  else
595  {
596  screenShortStr = strprintf("%s_Screenshot_%s_%s_",
597  branding.getValue("appName", "ManaPlus").c_str(),
598  serverName.c_str(), buffer);
599  }
600 
601  bool found = false;
602  static unsigned int screenshotCount = 0;
603  do
604  {
605  screenshotCount++;
606  filename.str("");
607  filename << screenshotDirectory << "/";
608  filename << screenShortStr << screenshotCount << ".png";
609  testExists.open(filename.str().c_str(), std::ios::in);
610  found = !testExists.is_open();
611  testExists.close();
612  }
613  while (!found);
614  }
615  else
616  {
617  screenShortStr = prefix;
618  filename.str("");
619  filename << screenshotDirectory << "/";
620  filename << screenShortStr;
621  }
622 
623  const std::string fileNameStr = filename.str();
624  const bool success = PngLib::writePNG(screenshot, fileNameStr);
625 #ifdef __native_client__
626  std::string nacScreenshotlDir = fileNameStr;
627  cutFirst(nacScreenshotlDir, "/persistent");
628  naclPostMessage("copy-from-persistent", nacScreenshotlDir);
629  logger->log("nacl screenshot path: " + nacScreenshotlDir);
630 #endif // __native_client__
631 
632  if (success)
633  {
634  if (localChatTab != nullptr)
635  {
636  // TRANSLATORS: save file message
637  std::string str = strprintf(_("Screenshot saved as %s"),
638  fileNameStr.c_str());
639  localChatTab->chatLog(str,
643  }
644  }
645  else
646  {
647  if (localChatTab != nullptr)
648  {
649  // TRANSLATORS: save file message
650  localChatTab->chatLog(_("Saving screenshot failed!"),
654  }
655  logger->log1("Error: could not save screenshot.");
656  }
657 
658  MSDL_FreeSurface(screenshot);
659  return success;
660 }
661 
663 {
664  BLOCK_START("Game::logic")
665  handleInput();
666 
667  // Handle all necessary game logic
668  if (actorManager != nullptr)
669  actorManager->logic();
670  if (particleEngine != nullptr)
672  if (mCurrentMap != nullptr)
673  mCurrentMap->update(1);
674 
675  BLOCK_END("Game::logic")
676 }
677 
679 {
680  BLOCK_START("Game::slowLogic")
681  if (localPlayer != nullptr)
683  const time_t time = cur_time;
684  if (mTime != time)
685  {
686  if (valTest(Updated))
687  mValidSpeed = false;
688 
689  mTime = time + 1;
690  if (debugWindow != nullptr)
692  if (killStats != nullptr)
693  killStats->update();
694  if (socialWindow != nullptr)
696  if (whoIsOnline != nullptr)
699  if (killStats != nullptr)
701 
702  if (time > mTime2 || mTime2 - time > 10)
703  {
704  mTime2 = time + 10;
707  }
708  if (effectManager != nullptr)
709  effectManager->logic();
710  }
711 
714 
715 #ifdef TMWA_SUPPORT
716  if (shopWindow != nullptr)
718  if (guildManager != nullptr)
720 #endif // TMWA_SUPPORT
721 
722  if (skillDialog != nullptr)
724 
726 
727  // Handle network stuff
728  if (!gameHandler->isConnected())
729  {
731  return; // Not a problem here
732 
733  if (client->getState() != State::ERROR)
734  {
735  if (disconnectedDialog == nullptr)
736  {
737  // TRANSLATORS: error message text
738  errorMessage = _("The connection to the server was lost.");
739  disconnectedDialog = DialogsManager::openErrorDialog(
740  // TRANSLATORS: error message header
741  _("Network Error"),
742  errorMessage,
743  Modal_false);
744  disconnectedDialog->addActionListener(&errorListener);
745  disconnectedDialog->requestMoveToTop();
746  }
747  }
748 
749  if ((viewport != nullptr) && !errorMessage.empty())
750  {
751  const Map *const map = viewport->getMap();
752  if (map != nullptr)
753  map->saveExtraLayer();
754  }
758  if (client->getState() != State::ERROR)
759  errorMessage.clear();
760  }
761  else
762  {
763  if (gameHandler->mustPing()
764  && get_elapsed_time1(mPing) > 3000)
765  {
766  mPing = tick_time;
768  }
769 
770  if (mAdjustPerfomance)
772  if (disconnectedDialog != nullptr)
773  {
774  disconnectedDialog->scheduleDelete();
775  disconnectedDialog = nullptr;
776  }
777  }
778  BLOCK_END("Game::slowLogic")
779 }
780 
782 {
783  FUNC_BLOCK("Game::adjustPerfomance", 1)
784  const time_t time = cur_time;
786  {
787  mNextAdjustTime = time + adjustDelay;
788  }
789  else if (mNextAdjustTime < time)
790  {
791  mNextAdjustTime = time + adjustDelay;
792 
793  if (mAdjustLevel > 3 ||
794  localPlayer == nullptr ||
797  {
798  return;
799  }
800 
801  int maxFps = WindowManager::getFramerate();
802  if (maxFps != config.getIntValue("fpslimit"))
803  return;
804 
805  if (maxFps == 0)
806  maxFps = 30;
807  else if (maxFps < 10)
808  return;
809 
810  if (fps < maxFps - 10)
811  {
812  if (mLowerCounter < 2)
813  {
814  mLowerCounter ++;
816  return;
817  }
818  mLowerCounter = 0;
819  mAdjustLevel ++;
820  switch (mAdjustLevel)
821  {
822  case 1:
823  {
824  if (config.getBoolValue("beingopacity"))
825  {
826  config.setValue("beingopacity", false);
827  config.setSilent("beingopacity", true);
828  if (localChatTab != nullptr)
829  {
831  // TRANSLATORS: auto adjust settings message
832  _("Auto disable Show beings transparency"),
836  }
837  }
838  else
839  {
840  mNextAdjustTime = time + 1;
841  mLowerCounter = 2;
842  }
843  break;
844  }
845  case 2:
847  {
849  if (localChatTab != nullptr)
850  {
852  // TRANSLATORS: auto adjust settings message
853  _("Auto lower Particle effects"),
857  }
858  }
859  else
860  {
861  mNextAdjustTime = time + 1;
862  mLowerCounter = 2;
863  }
864  break;
865  case 3:
866  if (!config.getBoolValue("alphaCache"))
867  {
868  config.setValue("alphaCache", true);
869  config.setSilent("alphaCache", false);
870  if (localChatTab != nullptr)
871  {
873  // TRANSLATORS: auto adjust settings message
874  _("Auto enable opacity cache"),
878  }
879  }
880  break;
881  default:
882  break;
883  }
884  }
885  }
886 }
887 
889 {
890  if (!mAdjustPerfomance)
891  return;
892 
894  switch (mAdjustLevel)
895  {
896  case 1:
897  config.setValue("beingopacity",
898  config.getBoolValue("beingopacity"));
899  break;
900  case 2:
901  config.setValue("beingopacity",
902  config.getBoolValue("beingopacity"));
904  "particleEmitterSkip") + 1;
905  break;
906  default:
907  case 3:
908  config.setValue("beingopacity",
909  config.getBoolValue("beingopacity"));
911  "particleEmitterSkip") + 1;
912  config.setValue("alphaCache",
913  config.getBoolValue("alphaCache"));
914  break;
915  }
916  mAdjustLevel = 0;
917 }
918 
920 {
921  BLOCK_START("Game::handleMove")
922  if (localPlayer == nullptr)
923  {
924  BLOCK_END("Game::handleMove")
925  return;
926  }
927 
928  // Moving player around
929  if ((chatWindow != nullptr) &&
930  (quitDialog == nullptr) &&
931  localPlayer->canMove() &&
935  {
936  NpcDialog *const dialog = NpcDialog::getActive();
937  if (dialog != nullptr)
938  {
939  BLOCK_END("Game::handleMove")
940  return;
941  }
942 
943  // Ignore input if either "ignore" key is pressed
944  // Stops the character moving about if the user's window manager
945  // uses "ignore+arrow key" to switch virtual desktops.
948  {
949  BLOCK_END("Game::handleMove")
950  return;
951  }
952 
953  unsigned char direction = 0;
954 
955  // Translate pressed keys to movement and direction
957  ((joystick != nullptr) && joystick->isUp()))
958  {
959  direction |= BeingDirection::UP;
960  setValidSpeed();
962  }
964  ((joystick != nullptr) && joystick->isDown()))
965  {
966  direction |= BeingDirection::DOWN;
967  setValidSpeed();
969  }
970 
972  ((joystick != nullptr) && joystick->isLeft()))
973  {
974  direction |= BeingDirection::LEFT;
975  setValidSpeed();
977  }
979  ((joystick != nullptr) && joystick->isRight()))
980  {
981  direction |= BeingDirection::RIGHT;
982  setValidSpeed();
984  }
986  {
987  direction = localPlayer->getDirection();
988  setValidSpeed();
990  }
991 
996  || direction == 0)
997  {
998  moveInDirection(direction);
999  }
1000  }
1001  BLOCK_END("Game::handleMove")
1002 }
1003 
1004 void Game::moveInDirection(const unsigned char direction)
1005 {
1006  if (viewport == nullptr)
1007  return;
1008 
1009  if (settings.cameraMode == 0u)
1010  {
1011  if (localPlayer != nullptr)
1012  localPlayer->specialMove(direction);
1013  }
1014  else
1015  {
1016  int dx = 0;
1017  int dy = 0;
1018  if ((direction & BeingDirection::LEFT) != 0)
1019  dx = -5;
1020  else if ((direction & BeingDirection::RIGHT) != 0)
1021  dx = 5;
1022 
1023  if ((direction & BeingDirection::UP) != 0)
1024  dy = -5;
1025  else if ((direction & BeingDirection::DOWN) != 0)
1026  dy = 5;
1027  viewport->moveCamera(dx, dy);
1028  }
1029 }
1030 
1031 void Game::updateFrameRate(int fpsLimit)
1032 {
1033  if (fpsLimit == 0)
1034  {
1035  if (settings.awayMode)
1036  {
1039  {
1040  fpsLimit = config.getIntValue("fpslimit");
1041  }
1042  else
1043  {
1044  fpsLimit = config.getIntValue("altfpslimit");
1045  }
1046  }
1047  else
1048  {
1049  fpsLimit = config.getIntValue("fpslimit");
1050  }
1051  }
1052  WindowManager::setFramerate(fpsLimit);
1054 }
1055 
1060 {
1061  BLOCK_START("Game::handleInput 1")
1062  if (joystick != nullptr)
1063  joystick->logic();
1064 
1066 
1067  // If the user is configuring the keys then don't respond.
1068  if (!keyboard.isEnabled() || settings.awayMode)
1069  {
1070  BLOCK_END("Game::handleInput 1")
1071  return;
1072  }
1073 
1074  // If pressed outfits keys, stop processing keys.
1077  || ((setupWindow != nullptr) && setupWindow->isWindowVisible()))
1078  {
1079  BLOCK_END("Game::handleInput 1")
1080  return;
1081  }
1082 
1083  handleMove();
1085  BLOCK_END("Game::handleInput 1")
1086 }
1087 
1092 void Game::changeMap(const std::string &mapPath)
1093 {
1094  BLOCK_START("Game::changeMap")
1095 
1096  skipPerfFrames = 3;
1097  resetAdjustLevel();
1099 
1102 
1103  // Clean up floor items, beings and particles
1104  if (actorManager != nullptr)
1105  actorManager->clear();
1106 
1107  // Close the popup menu on map change so that invalid options can't be
1108  // executed.
1109  if (viewport != nullptr)
1111 
1112  // Unset the map of the player so that its particles are cleared before
1113  // being deleted in the next step
1114  if (localPlayer != nullptr)
1115  localPlayer->setMap(nullptr);
1116 
1117  if (particleEngine != nullptr)
1118  particleEngine->clear();
1119 
1120  mMapName = mapPath;
1121 
1122  std::string fullMap = pathJoin(paths.getValue("maps", "maps/"),
1123  mMapName).append(".tmx");
1124  std::string realFullMap = pathJoin(paths.getValue("maps", "maps/"),
1125  MapDB::getMapName(mMapName)).append(".tmx");
1126 
1127  if (!VirtFs::exists(realFullMap))
1128  realFullMap.append(".gz");
1129 
1130  // Attempt to load the new map
1131  Map *const newMap = MapReader::readMap(fullMap, realFullMap);
1132 
1133  if (mCurrentMap != nullptr)
1135 
1136  if (newMap != nullptr)
1137  newMap->addExtraLayer();
1138 
1139  if (socialWindow != nullptr)
1140  socialWindow->setMap(newMap);
1141 
1142  // Notify the minimap and actorManager about the map change
1143  if (minimap != nullptr)
1144  minimap->setMap(newMap);
1145  if (actorManager != nullptr)
1146  actorManager->setMap(newMap);
1147  if (particleEngine != nullptr)
1148  particleEngine->setMap(newMap);
1149  if (viewport != nullptr)
1150  viewport->setMap(newMap);
1151 
1152  // Initialize map-based particle effects
1153  if (newMap != nullptr)
1154  newMap->initializeParticleEffects();
1155 
1156  // Start playing new music file when necessary
1157  const std::string oldMusic = mCurrentMap != nullptr
1158  ? mCurrentMap->getMusicFile() : "";
1159  const std::string newMusic = newMap != nullptr ?
1160  newMap->getMusicFile() : "";
1161  if (newMusic != oldMusic)
1162  {
1163  if (newMusic.empty())
1164  soundManager.fadeOutMusic(1000);
1165  else
1166  soundManager.fadeOutAndPlayMusic(newMusic, 1000);
1167  }
1168 
1169  if (mCurrentMap != nullptr)
1171 
1172  delete mCurrentMap;
1173  mCurrentMap = newMap;
1174 
1175  if (questsWindow != nullptr)
1177 
1178 #ifdef USE_MUMBLE
1179  if (mumbleManager)
1180  mumbleManager->setMap(mapPath);
1181 #endif // USE_MUMBLE
1182 
1183  if (localPlayer != nullptr)
1185 
1187  Perf::init();
1188  BLOCK_END("Game::changeMap")
1189 }
1190 
1191 void Game::updateHistory(const SDL_Event &event)
1192 {
1193  if ((localPlayer == nullptr) || (settings.attackType == 0u))
1194  return;
1195 
1196  if (CAST_S32(event.key.keysym.sym) != -1)
1197  {
1198  bool old = false;
1199 
1200  const InputActionT key = KeyboardConfig::getKeyIndex(event, 1);
1201  const time_t time = cur_time;
1202  int idx = -1;
1203  for (int f = 0; f < MAX_LASTKEYS; f ++)
1204  {
1205  LastKey &lastKey = mLastKeys[f];
1206  if (lastKey.key == key)
1207  {
1208  idx = f;
1209  old = true;
1210  break;
1211  }
1212  else if (idx >= 0 && lastKey.time < mLastKeys[idx].time)
1213  {
1214  idx = f;
1215  }
1216  }
1217  if (idx < 0)
1218  {
1219  idx = 0;
1220  for (int f = 0; f < MAX_LASTKEYS; f ++)
1221  {
1222  LastKey &lastKey = mLastKeys[f];
1223  if (lastKey.key == InputAction::NO_VALUE ||
1224  lastKey.time < mLastKeys[idx].time)
1225  {
1226  idx = f;
1227  }
1228  }
1229  }
1230 
1231  if (idx < 0)
1232  idx = 0;
1233 
1234  LastKey &keyIdx = mLastKeys[idx];
1235  if (!old)
1236  {
1237  keyIdx.time = time;
1238  keyIdx.key = key;
1239  keyIdx.cnt = 0;
1240  }
1241  else
1242  {
1243  keyIdx.cnt++;
1244  }
1245  }
1246 }
1247 
1249 {
1250  const int timeRange = 120;
1251  const int cntInTime = 130;
1252 
1253  if ((localPlayer == nullptr) || (settings.attackType == 0u))
1254  return;
1255 
1256  const time_t time = cur_time;
1257  for (int f = 0; f < MAX_LASTKEYS; f ++)
1258  {
1259  LastKey &lastKey = mLastKeys[f];
1260  if (lastKey.key != InputAction::NO_VALUE)
1261  {
1262  if (lastKey.time + timeRange < time)
1263  {
1264  if (lastKey.cnt > cntInTime)
1265  mValidSpeed = false;
1266  lastKey.key = InputAction::NO_VALUE;
1267  }
1268  }
1269  }
1270 }
1271 
1273 {
1274  clearKeysArray();
1275  mValidSpeed = true;
1276 }
1277 
1279 {
1280  for (int f = 0; f < MAX_LASTKEYS; f ++)
1281  {
1282  mLastKeys[f].time = 0;
1284  mLastKeys[f].cnt = 0;
1285  }
1286 }
1287 
1288 void Game::videoResized(const int width, const int height)
1289 {
1290  if (viewport != nullptr)
1291  viewport->setSize(width, height);
1292  if (windowMenu != nullptr)
1293  windowMenu->setPosition(width - windowMenu->getWidth(), 0);
1294 }
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:42
ChatWindow * chatWindow
Definition: chatwindow.cpp:89
#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:1248
int getWidth() const
Definition: widget.h:220
void updateFrameRate(int fpsLimit)
Definition: game.cpp:1031
void log1(const char *const log_text)
Definition: logger.cpp:233
Font * boldFont
Definition: gui.cpp:111
static bool createScreenshot(const std::string &prefix)
Definition: game.cpp:534
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:1272
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:157
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:830
std::string pathJoin(std::string str1, const std::string &str2)
static void clear()
void handleInput()
Definition: game.cpp:1059
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:346
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
ClanWindow * clanWindow
Definition: clanwindow.cpp:37
void cancelFollow()
bool isInputFocused() const
Definition: chatwindow.cpp:574
StatusWindow * statusWindow
void handleGameEvents() const
static void addWatermark()
Definition: game.cpp:519
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:493
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:117
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:84
DidYouKnowWindow * didYouKnowWindow
bool isLeft() const
Definition: joystick.h:110
WindowMenu * windowMenu
Definition: windowmenu.cpp:50
bool isEnabled() const
void slowLogic()
static void unloadEmptyAtlas()
Definition: mapreader.cpp:1332
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:160
static void setEnableDelay(bool b)
Logger * logger
Definition: logger.cpp:88
void loadFromLogFile(const std::string &name)
Definition: chattab.cpp:509
void slowLogic()
Definition: game.cpp:678
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:662
std::string errorMessage
Definition: client.cpp:115
Settings settings
Definition: settings.cpp:31
virtual void initEngines() const =0
MiniStatusWindow * miniStatusWindow
static void clearPopup()
~Game()
Definition: game.cpp:480
std::string screenshotDir
Definition: settings.h:113
bool getBoolValue(const std::string &key) const
void changeMap(const std::string &mapName)
Definition: game.cpp:1092
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:1288
bool writePNG(SDL_Surface *const surface, const std::string &filename)
Definition: pnglib.cpp:36
#define CAST_S32
Definition: cast.h:29
const Color & getColor(const ThemeColorIdT type, const unsigned int alpha)
Definition: theme.h:135
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:1104
static bool saveScreenshot(SDL_Surface *const screenshot, const std::string &prefix)
Definition: game.cpp:562
Definition: game.h:62
CrazyMoves * crazyMoves
Definition: crazymoves.cpp:46
void handleMove()
Definition: game.cpp:919
static void destroyGuiWindows()
Definition: game.cpp:348
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:715
#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:1191
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:404
static void closeDialogs()
int mHeight
Definition: graphics.h:484
volatile time_t cur_time
Definition: timer.cpp:57
const std::string getMapName(const std::string &name)
Definition: mapdb.cpp:203
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:326
Definition: map.h:71
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:1221
ShortcutWindow * emoteShortcutWindow
static void loadEmptyAtlas()
Definition: mapreader.cpp:1316
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:100
bool disableLoggingInGame
Definition: settings.h:158
ServerTypeT getNetworkType()
Definition: net.cpp:182
int skipPerfFrames
Definition: perfstat.cpp:36
Configuration paths
bool isSafeMode
Definition: client.cpp:122
void init()
Definition: perfstat.cpp:40
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:3431
void setInGame(const bool b)
void adjustPerfomance()
Definition: game.cpp:781
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:166
virtual bool mustPing() const =0
EquipmentWindow * equipmentWindow
Map * mCurrentMap
Definition: game.h:142
Window * disconnectedDialog
Definition: game.cpp:158
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:311
time_t mTime
Definition: game.h:151
void logic()
Definition: joystick.cpp:221
Definition: color.h:74
static void clearCache()
Definition: being.cpp:4719
KeyboardConfig keyboard
int mPing
Definition: game.h:150
SetupWindow * setupWindow
Definition: setupwindow.cpp:63
InputManager inputManager
TouchManager touchManager
static void createGuiWindows()
Definition: game.cpp:194
MailWindow * mailWindow
Definition: mailwindow.cpp:53
void update()
Definition: killstats.cpp:365
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:264
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:1004
void slowLogic()
Net::GameHandler * gameHandler
Definition: net.cpp:87
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:1278
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:5163
void loadData(int num)
static void init()
Definition: beinginfo.cpp:222
ActorManager * actorManager
Viewport * viewport
Definition: viewport.cpp:35
void addExtraLayer()
Definition: map.cpp:1137
CutInWindow * cutInWindow
Definition: cutinwindow.cpp:36
Minimap * minimap
Definition: minimap.cpp:61
void resetAdjustLevel()
Definition: game.cpp:888
const time_t adjustDelay
Definition: game.cpp:161
int cnt
Definition: game.h:55
bool getHalfAway() const
Definition: localplayer.h:238
InputActionT key
Definition: game.h:54