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/pnglib.h"
129 #include "utils/sdlcheckutils.h"
130 #include "utils/timer.h"
131 
132 #ifdef __native_client__
133 #include "utils/naclmessages.h"
134 #endif // __native_client__
135 
137 #include "listeners/errorlistener.h"
138 
139 #ifdef TMWA_SUPPORT
140 #include "net/tmwa/guildmanager.h"
141 #endif // TMWA_SUPPORT
142 
143 #ifdef USE_MUMBLE
144 #include "mumblemanager.h"
145 #endif // USE_MUMBLE
146 
147 #ifdef WIN32
148 #include <sys/time.h>
149 #undef ERROR
150 #endif // WIN32
151 
152 #include <fstream>
153 
154 #include "debug.h"
155 
158 
159 bool mStatsReUpdated = false;
160 const time_t adjustDelay = 10;
161 
165 static void initEngines()
166 {
169 #ifdef TMWA_SUPPORT
171 #endif // TMWA_SUPPORT
172 
173  crazyMoves = new CrazyMoves;
174 
176  particleEngine->setMap(nullptr);
178  BeingInfo::init();
179 
180  if (gameHandler != nullptr)
182 
183  keyboard.update();
184  if (joystick != nullptr)
185  joystick->update();
186 
188 }
189 
193 static void createGuiWindows()
194 {
195  if (setupWindow != nullptr)
197 
198  if (emoteShortcut != nullptr)
199  emoteShortcut->load();
200 
202 
203  // Create dialogs
206  if (chatWindow != nullptr)
207  {
209  chatWindow = nullptr;
210  }
212  "Chat");
216  localPlayer,
217  false);
219  nullptr,
220  nullptr,
221  true);
228  {
231  }
236  if (debugWindow != nullptr)
237  {
239  debugWindow = nullptr;
240  }
242  "Debug");
244  "ItemShortcut", "items.xml", 83, 460);
245 
246  for (unsigned f = 0; f < SHORTCUT_TABS - 1; f ++)
247  {
249  new ItemShortcutContainer(nullptr, f));
250  }
252  {
254  new ItemShortcutContainer(nullptr, SHORTCUT_TABS - 1));
255  }
256  if (config.getBoolValue("showDidYouKnow"))
257  {
260  }
261 
263  "EmoteShortcut",
264  new EmoteShortcutContainer(nullptr),
265  "emotes.xml",
266  130, 480);
269  "DropShortcut",
270  new VirtShortcutContainer(nullptr, dropShortcut),
271  "drops.xml",
272  0, 0);
274  "SpellShortcut",
275  "spells.xml",
276  265, 328);
277  for (unsigned f = 0; f < SPELL_SHORTCUT_TABS; f ++)
278  {
280  new SpellShortcutContainer(nullptr, f));
281  }
282 
290 
291  // TRANSLATORS: chat tab header
292  localChatTab = new ChatTab(chatWindow, _("General"),
293  GENERAL_CHANNEL, "#General", ChatTabType::INPUT);
295  if (config.getBoolValue("showChatHistory"))
296  localChatTab->loadFromLogFile("#General");
297 
298  // TRANSLATORS: chat tab header
299  debugChatTab = new ChatTab(chatWindow, _("Debug"), "",
300  "#Debug", ChatTabType::DEBUG);
302 
303  if (assertListener != nullptr)
304  {
305  const StringVect &messages = assertListener->getMessages();
306  FOR_EACH (StringVectCIter, it, messages)
307  {
308  debugChatTab->chatLog(*it,
312  }
314  }
315  if (config.getBoolValue("enableTradeTab"))
317  else
318  tradeChatTab = nullptr;
319 
320  if (config.getBoolValue("enableBattleTab"))
321  {
324  }
325  else
326  {
327  battleChatTab = nullptr;
328  }
329 
331  if (!isSafeMode)
333 
334  if (setupWindow != nullptr)
336 
337  if (localPlayer != nullptr)
339 
340  if (generalHandler != nullptr)
342 }
343 
347 static void destroyGuiWindows()
348 {
349  if (generalHandler != nullptr)
351 
352  if (whoIsOnline != nullptr)
353  whoIsOnline->setAllowUpdate(false);
354 
355 #ifdef TMWA_SUPPORT
357 #endif // TMWA_SUPPORT
358 
360  delete2(localChatTab) // Need to do this first, so it can remove itself
366 #ifdef TMWA_SUPPORT
367  if (guildManager != nullptr && GuildManager::getEnableGuildBot())
368  guildManager->reload();
369 #endif // TMWA_SUPPORT
370 
371  logger->log("start deleting");
374  logger->log("end deleting");
399 }
400 
401 Game *Game::mInstance = nullptr;
402 
404  mCurrentMap(nullptr),
405  mMapName(""),
406  mValidSpeed(true),
407  mNextAdjustTime(cur_time + adjustDelay),
408  mAdjustLevel(0),
409  mAdjustPerfomance(config.getBoolValue("adjustPerfomance")),
410  mLowerCounter(0),
411  mPing(0),
412  mTime(cur_time + 1),
413  mTime2(cur_time + 10)
414 {
415  touchManager.setInGame(true);
416 
417 // assert(!mInstance);
418  if (mInstance != nullptr)
419  logger->log("error: double game creation");
420  mInstance = this;
421 
422  config.incValue("gamecount");
423 
424  disconnectedDialog = nullptr;
425 
426  // Create the viewport
427  viewport = new Viewport;
430 
432 
433  BasicContainer2 *const top = static_cast<BasicContainer2*>(gui->getTop());
434  if (top != nullptr)
435  top->add(viewport);
437 
440  config.getBoolValue("enableDelayedAnimations"));
441 
443  config.getBoolValue("enableCompoundSpriteDelay"));
444 
446  windowMenu = new WindowMenu(nullptr);
447 
448  if (windowContainer != nullptr)
450 
451 #ifdef USE_OPENGL
453 #endif // USE_OPENGL
454 
455  initEngines();
456 
459 
460  // Initialize beings
461  if (actorManager != nullptr)
463 
465 
466  if (setupWindow != nullptr)
467  setupWindow->setInGame(true);
468  clearKeysArray();
469 
470 #ifdef TMWA_SUPPORT
471  if (guildManager != nullptr && GuildManager::getEnableGuildBot())
473 #endif // TMWA_SUPPORT
474 
476  "disableLoggingInGame");
477 }
478 
480 {
481 #ifdef USE_OPENGL
483 #endif // USE_OPENGL
484 
486  touchManager.setInGame(false);
487  config.write();
491 
493 
497  if (effectManager != nullptr)
498  effectManager->clear();
503 #ifdef TMWA_SUPPORT
505 #endif // TMWA_SUPPORT
506 #ifdef USE_MUMBLE
507  delete2(mumbleManager)
508 #endif // USE_MUMBLE
509 
512 
514  mInstance = nullptr;
516 }
517 
519 {
520  if ((boldFont == nullptr) || !config.getBoolValue("addwatermark"))
521  return;
522 
523  const Color &color1 = theme->getColor(ThemeColorId::TEXT, 255);
524  const Color &color2 = theme->getColor(ThemeColorId::TEXT_OUTLINE, 255);
525 
527  color1,
528  color2,
530  100, 50);
531 }
532 
533 bool Game::createScreenshot(const std::string &prefix)
534 {
535  if ((mainGraphics == nullptr) || (screenshortHelper == nullptr))
536  return false;
537 
538  SDL_Surface *screenshot = nullptr;
539 
540  if (!config.getBoolValue("showip") && (gui != nullptr))
541  {
542  mainGraphics->setSecure(true);
544  gui->draw();
545  addWatermark();
546  screenshot = screenshortHelper->getScreenshot();
547  mainGraphics->setSecure(false);
548  }
549  else
550  {
551  addWatermark();
552  screenshot = screenshortHelper->getScreenshot();
553  }
554 
555  if (screenshot == nullptr)
556  return false;
557 
558  return saveScreenshot(screenshot, prefix);
559 }
560 
561 bool Game::saveScreenshot(SDL_Surface *const screenshot,
562  const std::string &prefix)
563 {
564  std::string screenshotDirectory = settings.screenshotDir;
565  if (mkdir_r(screenshotDirectory.c_str()) != 0)
566  {
567  logger->log("Directory %s doesn't exist and can't be created! "
568  "Setting screenshot directory to home.",
569  screenshotDirectory.c_str());
570  screenshotDirectory = std::string(VirtFs::getUserDir());
571  }
572 
573  // Search for an unused screenshot name
574  std::stringstream filename;
575  std::fstream testExists;
576 
577  time_t rawtime;
578  char buffer [100];
579  time(&rawtime);
580  struct tm *const timeinfo = localtime(&rawtime);
581  strftime(buffer, 99, "%Y-%m-%d_%H-%M-%S", timeinfo);
582 
583  const std::string serverName = settings.serverName;
584  std::string screenShortStr;
585  if (prefix.empty())
586  {
587  if (serverName.empty())
588  {
589  screenShortStr = strprintf("%s_Screenshot_%s_",
590  branding.getValue("appName", "ManaPlus").c_str(),
591  buffer);
592  }
593  else
594  {
595  screenShortStr = strprintf("%s_Screenshot_%s_%s_",
596  branding.getValue("appName", "ManaPlus").c_str(),
597  serverName.c_str(), buffer);
598  }
599 
600  bool found = false;
601  static unsigned int screenshotCount = 0;
602  do
603  {
604  screenshotCount++;
605  filename.str("");
606  filename << screenshotDirectory << "/";
607  filename << screenShortStr << screenshotCount << ".png";
608  testExists.open(filename.str().c_str(), std::ios::in);
609  found = !testExists.is_open();
610  testExists.close();
611  }
612  while (!found);
613  }
614  else
615  {
616  screenShortStr = prefix;
617  filename.str("");
618  filename << screenshotDirectory << "/";
619  filename << screenShortStr;
620  }
621 
622  const std::string fileNameStr = filename.str();
623  const bool success = PngLib::writePNG(screenshot, fileNameStr);
624 #ifdef __native_client__
625  std::string nacScreenshotlDir = fileNameStr;
626  cutFirst(nacScreenshotlDir, "/persistent");
627  naclPostMessage("copy-from-persistent", nacScreenshotlDir);
628  logger->log("nacl screenshot path: " + nacScreenshotlDir);
629 #endif // __native_client__
630 
631  if (success)
632  {
633  if (localChatTab != nullptr)
634  {
635  // TRANSLATORS: save file message
636  std::string str = strprintf(_("Screenshot saved as %s"),
637  fileNameStr.c_str());
638  localChatTab->chatLog(str,
642  }
643  }
644  else
645  {
646  if (localChatTab != nullptr)
647  {
648  // TRANSLATORS: save file message
649  localChatTab->chatLog(_("Saving screenshot failed!"),
653  }
654  logger->log1("Error: could not save screenshot.");
655  }
656 
657  MSDL_FreeSurface(screenshot);
658  return success;
659 }
660 
662 {
663  BLOCK_START("Game::logic")
664  handleInput();
665 
666  // Handle all necessary game logic
667  if (actorManager != nullptr)
668  actorManager->logic();
669  if (particleEngine != nullptr)
671  if (mCurrentMap != nullptr)
672  mCurrentMap->update(1);
673 
674  BLOCK_END("Game::logic")
675 }
676 
678 {
679  BLOCK_START("Game::slowLogic")
680  if (localPlayer != nullptr)
682  const time_t time = cur_time;
683  if (mTime != time)
684  {
685  if (valTest(Updated))
686  mValidSpeed = false;
687 
688  mTime = time + 1;
689  if (debugWindow != nullptr)
691  if (killStats != nullptr)
692  killStats->update();
693  if (socialWindow != nullptr)
695  if (whoIsOnline != nullptr)
698  if (killStats != nullptr)
700 
701  if (time > mTime2 || mTime2 - time > 10)
702  {
703  mTime2 = time + 10;
706  }
707  if (effectManager != nullptr)
708  effectManager->logic();
709  }
710 
713 
714 #ifdef TMWA_SUPPORT
715  if (shopWindow != nullptr)
717  if (guildManager != nullptr)
719 #endif // TMWA_SUPPORT
720 
721  if (skillDialog != nullptr)
723 
725 
726  // Handle network stuff
727  if (!gameHandler->isConnected())
728  {
730  return; // Not a problem here
731 
732  if (client->getState() != State::ERROR)
733  {
734  if (disconnectedDialog == nullptr)
735  {
736  // TRANSLATORS: error message text
737  errorMessage = _("The connection to the server was lost.");
738  disconnectedDialog = DialogsManager::openErrorDialog(
739  // TRANSLATORS: error message header
740  _("Network Error"),
741  errorMessage,
742  Modal_false);
743  disconnectedDialog->addActionListener(&errorListener);
744  disconnectedDialog->requestMoveToTop();
745  }
746  }
747 
748  if ((viewport != nullptr) && !errorMessage.empty())
749  {
750  const Map *const map = viewport->getMap();
751  if (map != nullptr)
752  map->saveExtraLayer();
753  }
757  if (client->getState() != State::ERROR)
758  errorMessage.clear();
759  }
760  else
761  {
762  if (gameHandler->mustPing()
763  && get_elapsed_time1(mPing) > 3000)
764  {
765  mPing = tick_time;
767  }
768 
769  if (mAdjustPerfomance)
771  if (disconnectedDialog != nullptr)
772  {
773  disconnectedDialog->scheduleDelete();
774  disconnectedDialog = nullptr;
775  }
776  }
777  BLOCK_END("Game::slowLogic")
778 }
779 
781 {
782  FUNC_BLOCK("Game::adjustPerfomance", 1)
783  const time_t time = cur_time;
785  {
786  mNextAdjustTime = time + adjustDelay;
787  }
788  else if (mNextAdjustTime < time)
789  {
790  mNextAdjustTime = time + adjustDelay;
791 
792  if (mAdjustLevel > 3 ||
793  localPlayer == nullptr ||
796  {
797  return;
798  }
799 
800  int maxFps = WindowManager::getFramerate();
801  if (maxFps != config.getIntValue("fpslimit"))
802  return;
803 
804  if (maxFps == 0)
805  maxFps = 30;
806  else if (maxFps < 10)
807  return;
808 
809  if (fps < maxFps - 10)
810  {
811  if (mLowerCounter < 2)
812  {
813  mLowerCounter ++;
815  return;
816  }
817  mLowerCounter = 0;
818  mAdjustLevel ++;
819  switch (mAdjustLevel)
820  {
821  case 1:
822  {
823  if (config.getBoolValue("beingopacity"))
824  {
825  config.setValue("beingopacity", false);
826  config.setSilent("beingopacity", true);
827  if (localChatTab != nullptr)
828  {
830  // TRANSLATORS: auto adjust settings message
831  _("Auto disable Show beings transparency"),
835  }
836  }
837  else
838  {
839  mNextAdjustTime = time + 1;
840  mLowerCounter = 2;
841  }
842  break;
843  }
844  case 2:
846  {
848  if (localChatTab != nullptr)
849  {
851  // TRANSLATORS: auto adjust settings message
852  _("Auto lower Particle effects"),
856  }
857  }
858  else
859  {
860  mNextAdjustTime = time + 1;
861  mLowerCounter = 2;
862  }
863  break;
864  case 3:
865  if (!config.getBoolValue("alphaCache"))
866  {
867  config.setValue("alphaCache", true);
868  config.setSilent("alphaCache", false);
869  if (localChatTab != nullptr)
870  {
872  // TRANSLATORS: auto adjust settings message
873  _("Auto enable opacity cache"),
877  }
878  }
879  break;
880  default:
881  break;
882  }
883  }
884  }
885 }
886 
888 {
889  if (!mAdjustPerfomance)
890  return;
891 
893  switch (mAdjustLevel)
894  {
895  case 1:
896  config.setValue("beingopacity",
897  config.getBoolValue("beingopacity"));
898  break;
899  case 2:
900  config.setValue("beingopacity",
901  config.getBoolValue("beingopacity"));
903  "particleEmitterSkip") + 1;
904  break;
905  default:
906  case 3:
907  config.setValue("beingopacity",
908  config.getBoolValue("beingopacity"));
910  "particleEmitterSkip") + 1;
911  config.setValue("alphaCache",
912  config.getBoolValue("alphaCache"));
913  break;
914  }
915  mAdjustLevel = 0;
916 }
917 
919 {
920  BLOCK_START("Game::handleMove")
921  if (localPlayer == nullptr)
922  {
923  BLOCK_END("Game::handleMove")
924  return;
925  }
926 
927  // Moving player around
928  if ((chatWindow != nullptr) &&
929  (quitDialog == nullptr) &&
930  localPlayer->canMove() &&
934  {
935  NpcDialog *const dialog = NpcDialog::getActive();
936  if (dialog != nullptr)
937  {
938  BLOCK_END("Game::handleMove")
939  return;
940  }
941 
942  // Ignore input if either "ignore" key is pressed
943  // Stops the character moving about if the user's window manager
944  // uses "ignore+arrow key" to switch virtual desktops.
947  {
948  BLOCK_END("Game::handleMove")
949  return;
950  }
951 
952  unsigned char direction = 0;
953 
954  // Translate pressed keys to movement and direction
956  ((joystick != nullptr) && joystick->isUp()))
957  {
958  direction |= BeingDirection::UP;
959  setValidSpeed();
961  }
963  ((joystick != nullptr) && joystick->isDown()))
964  {
965  direction |= BeingDirection::DOWN;
966  setValidSpeed();
968  }
969 
971  ((joystick != nullptr) && joystick->isLeft()))
972  {
973  direction |= BeingDirection::LEFT;
974  setValidSpeed();
976  }
978  ((joystick != nullptr) && joystick->isRight()))
979  {
980  direction |= BeingDirection::RIGHT;
981  setValidSpeed();
983  }
985  {
986  direction = localPlayer->getDirection();
987  setValidSpeed();
989  }
990 
995  || direction == 0)
996  {
997  moveInDirection(direction);
998  }
999  }
1000  BLOCK_END("Game::handleMove")
1001 }
1002 
1003 void Game::moveInDirection(const unsigned char direction)
1004 {
1005  if (viewport == nullptr)
1006  return;
1007 
1008  if (settings.cameraMode == 0u)
1009  {
1010  if (localPlayer != nullptr)
1011  localPlayer->specialMove(direction);
1012  }
1013  else
1014  {
1015  int dx = 0;
1016  int dy = 0;
1017  if ((direction & BeingDirection::LEFT) != 0)
1018  dx = -5;
1019  else if ((direction & BeingDirection::RIGHT) != 0)
1020  dx = 5;
1021 
1022  if ((direction & BeingDirection::UP) != 0)
1023  dy = -5;
1024  else if ((direction & BeingDirection::DOWN) != 0)
1025  dy = 5;
1026  viewport->moveCamera(dx, dy);
1027  }
1028 }
1029 
1030 void Game::updateFrameRate(int fpsLimit)
1031 {
1032  if (fpsLimit == 0)
1033  {
1034  if (settings.awayMode)
1035  {
1038  {
1039  fpsLimit = config.getIntValue("fpslimit");
1040  }
1041  else
1042  {
1043  fpsLimit = config.getIntValue("altfpslimit");
1044  }
1045  }
1046  else
1047  {
1048  fpsLimit = config.getIntValue("fpslimit");
1049  }
1050  }
1051  WindowManager::setFramerate(fpsLimit);
1053 }
1054 
1059 {
1060  BLOCK_START("Game::handleInput 1")
1061  if (joystick != nullptr)
1062  joystick->logic();
1063 
1065 
1066  // If the user is configuring the keys then don't respond.
1067  if (!keyboard.isEnabled() || settings.awayMode)
1068  {
1069  BLOCK_END("Game::handleInput 1")
1070  return;
1071  }
1072 
1073  // If pressed outfits keys, stop processing keys.
1076  || ((setupWindow != nullptr) && setupWindow->isWindowVisible()))
1077  {
1078  BLOCK_END("Game::handleInput 1")
1079  return;
1080  }
1081 
1082  handleMove();
1084  BLOCK_END("Game::handleInput 1")
1085 }
1086 
1091 void Game::changeMap(const std::string &mapPath)
1092 {
1093  BLOCK_START("Game::changeMap")
1094 
1095  resetAdjustLevel();
1097 
1100 
1101  // Clean up floor items, beings and particles
1102  if (actorManager != nullptr)
1103  actorManager->clear();
1104 
1105  // Close the popup menu on map change so that invalid options can't be
1106  // executed.
1107  if (viewport != nullptr)
1109 
1110  // Unset the map of the player so that its particles are cleared before
1111  // being deleted in the next step
1112  if (localPlayer != nullptr)
1113  localPlayer->setMap(nullptr);
1114 
1115  if (particleEngine != nullptr)
1116  particleEngine->clear();
1117 
1118  mMapName = mapPath;
1119 
1120  std::string fullMap = pathJoin(paths.getValue("maps", "maps/"),
1121  mMapName).append(".tmx");
1122  std::string realFullMap = pathJoin(paths.getValue("maps", "maps/"),
1123  MapDB::getMapName(mMapName)).append(".tmx");
1124 
1125  if (!VirtFs::exists(realFullMap))
1126  realFullMap.append(".gz");
1127 
1128  // Attempt to load the new map
1129  Map *const newMap = MapReader::readMap(fullMap, realFullMap);
1130 
1131  if (mCurrentMap != nullptr)
1133 
1134  if (newMap != nullptr)
1135  newMap->addExtraLayer();
1136 
1137  if (socialWindow != nullptr)
1138  socialWindow->setMap(newMap);
1139 
1140  // Notify the minimap and actorManager about the map change
1141  if (minimap != nullptr)
1142  minimap->setMap(newMap);
1143  if (actorManager != nullptr)
1144  actorManager->setMap(newMap);
1145  if (particleEngine != nullptr)
1146  particleEngine->setMap(newMap);
1147  if (viewport != nullptr)
1148  viewport->setMap(newMap);
1149 
1150  // Initialize map-based particle effects
1151  if (newMap != nullptr)
1152  newMap->initializeParticleEffects();
1153 
1154  // Start playing new music file when necessary
1155  const std::string oldMusic = mCurrentMap != nullptr
1156  ? mCurrentMap->getMusicFile() : "";
1157  const std::string newMusic = newMap != nullptr ?
1158  newMap->getMusicFile() : "";
1159  if (newMusic != oldMusic)
1160  {
1161  if (newMusic.empty())
1162  soundManager.fadeOutMusic(1000);
1163  else
1164  soundManager.fadeOutAndPlayMusic(newMusic, 1000);
1165  }
1166 
1167  if (mCurrentMap != nullptr)
1169 
1170  delete mCurrentMap;
1171  mCurrentMap = newMap;
1172 
1173  if (questsWindow != nullptr)
1175 
1176 #ifdef USE_MUMBLE
1177  if (mumbleManager)
1178  mumbleManager->setMap(mapPath);
1179 #endif // USE_MUMBLE
1180 
1181  if (localPlayer != nullptr)
1183 
1185  BLOCK_END("Game::changeMap")
1186 }
1187 
1188 void Game::updateHistory(const SDL_Event &event)
1189 {
1190  if ((localPlayer == nullptr) || (settings.attackType == 0u))
1191  return;
1192 
1193  if (CAST_S32(event.key.keysym.sym) != -1)
1194  {
1195  bool old = false;
1196 
1197  const InputActionT key = KeyboardConfig::getKeyIndex(event, 1);
1198  const time_t time = cur_time;
1199  int idx = -1;
1200  for (int f = 0; f < MAX_LASTKEYS; f ++)
1201  {
1202  LastKey &lastKey = mLastKeys[f];
1203  if (lastKey.key == key)
1204  {
1205  idx = f;
1206  old = true;
1207  break;
1208  }
1209  else if (idx >= 0 && lastKey.time < mLastKeys[idx].time)
1210  {
1211  idx = f;
1212  }
1213  }
1214  if (idx < 0)
1215  {
1216  idx = 0;
1217  for (int f = 0; f < MAX_LASTKEYS; f ++)
1218  {
1219  LastKey &lastKey = mLastKeys[f];
1220  if (lastKey.key == InputAction::NO_VALUE ||
1221  lastKey.time < mLastKeys[idx].time)
1222  {
1223  idx = f;
1224  }
1225  }
1226  }
1227 
1228  if (idx < 0)
1229  idx = 0;
1230 
1231  LastKey &keyIdx = mLastKeys[idx];
1232  if (!old)
1233  {
1234  keyIdx.time = time;
1235  keyIdx.key = key;
1236  keyIdx.cnt = 0;
1237  }
1238  else
1239  {
1240  keyIdx.cnt++;
1241  }
1242  }
1243 }
1244 
1246 {
1247  const int timeRange = 120;
1248  const int cntInTime = 130;
1249 
1250  if ((localPlayer == nullptr) || (settings.attackType == 0u))
1251  return;
1252 
1253  const time_t time = cur_time;
1254  for (int f = 0; f < MAX_LASTKEYS; f ++)
1255  {
1256  LastKey &lastKey = mLastKeys[f];
1257  if (lastKey.key != InputAction::NO_VALUE)
1258  {
1259  if (lastKey.time + timeRange < time)
1260  {
1261  if (lastKey.cnt > cntInTime)
1262  mValidSpeed = false;
1263  lastKey.key = InputAction::NO_VALUE;
1264  }
1265  }
1266  }
1267 }
1268 
1270 {
1271  clearKeysArray();
1272  mValidSpeed = true;
1273 }
1274 
1276 {
1277  for (int f = 0; f < MAX_LASTKEYS; f ++)
1278  {
1279  mLastKeys[f].time = 0;
1281  mLastKeys[f].cnt = 0;
1282  }
1283 }
1284 
1285 void Game::videoResized(const int width, const int height)
1286 {
1287  if (viewport != nullptr)
1288  viewport->setSize(width, height);
1289  if (windowMenu != nullptr)
1290  windowMenu->setPosition(width - windowMenu->getWidth(), 0);
1291 }
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: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:1245
int getWidth() const
Definition: widget.h:220
void updateFrameRate(int fpsLimit)
Definition: game.cpp:1030
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:533
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:1269
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:156
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:1058
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:518
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()
Definition: debugwindow.cpp:94
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:159
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:677
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:661
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:479
std::string screenshotDir
Definition: settings.h:113
bool getBoolValue(const std::string &key) const
void changeMap(const std::string &mapName)
Definition: game.cpp:1091
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:1285
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:561
Definition: game.h:62
CrazyMoves * crazyMoves
Definition: crazymoves.cpp:46
void handleMove()
Definition: game.cpp:918
static void destroyGuiWindows()
Definition: game.cpp:347
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:1188
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:403
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
Configuration paths
bool isSafeMode
Definition: client.cpp:122
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:780
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:165
virtual bool mustPing() const =0
EquipmentWindow * equipmentWindow
Map * mCurrentMap
Definition: game.h:142
Window * disconnectedDialog
Definition: game.cpp:157
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:193
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:1003
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:1275
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:887
const time_t adjustDelay
Definition: game.cpp:160
int cnt
Definition: game.h:55
bool getHalfAway() const
Definition: localplayer.h:238
InputActionT key
Definition: game.h:54