summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net/ea/beinghandler.cpp8
-rw-r--r--src/net/ea/charserverhandler.cpp28
-rw-r--r--src/net/ea/chathandler.cpp4
-rw-r--r--src/net/ea/generalhandler.cpp21
-rw-r--r--src/net/ea/loginhandler.cpp8
-rw-r--r--src/net/ea/maphandler.cpp6
-rw-r--r--src/net/ea/playerhandler.cpp20
-rw-r--r--src/net/ea/protocol.h47
-rw-r--r--src/net/tmwserv/generalhandler.cpp21
-rw-r--r--src/resources/itemdb.cpp24
-rw-r--r--src/resources/itemdb.h8
-rw-r--r--src/resources/resourcemanager.cpp30
-rw-r--r--src/resources/resourcemanager.h11
-rw-r--r--src/sound.cpp18
14 files changed, 205 insertions, 49 deletions
diff --git a/src/net/ea/beinghandler.cpp b/src/net/ea/beinghandler.cpp
index 6ab73b4c..4b61ec61 100644
--- a/src/net/ea/beinghandler.cpp
+++ b/src/net/ea/beinghandler.cpp
@@ -65,8 +65,8 @@ BeingHandler::BeingHandler(bool enableSync):
SMSG_PLAYER_MOVE,
SMSG_PLAYER_STOP,
SMSG_PLAYER_MOVE_TO_ATTACK,
- 0x0119,
- 0x0196,
+ SMSG_PLAYER_STATUS_CHANGE,
+ SMSG_BEING_STATUS_CHANGE,
0
};
handledMessages = _messages;
@@ -574,7 +574,7 @@ void BeingHandler::handleMessage(MessageIn &msg)
*/
break;
- case 0x0119:
+ case SMSG_PLAYER_STATUS_CHANGE:
// Change in players' flags
id = msg.readInt32();
dstBeing = beingManager->findBeing(id);
@@ -590,7 +590,7 @@ void BeingHandler::handleMessage(MessageIn &msg)
}
break;
- case 0x0196:
+ case SMSG_BEING_STATUS_CHANGE:
// Status change
status = msg.readInt16();
id = msg.readInt32();
diff --git a/src/net/ea/charserverhandler.cpp b/src/net/ea/charserverhandler.cpp
index 3402b5fc..fab1ffe3 100644
--- a/src/net/ea/charserverhandler.cpp
+++ b/src/net/ea/charserverhandler.cpp
@@ -46,13 +46,13 @@ CharServerHandler::CharServerHandler():
mCharCreateDialog(0)
{
static const Uint16 _messages[] = {
- 0x006b,
- 0x006c,
- 0x006d,
- 0x006e,
- 0x006f,
- 0x0070,
- 0x0071,
+ SMSG_CHAR_LOGIN,
+ SMSG_CHAR_LOGIN_ERROR,
+ SMSG_CHAR_CREATE_SUCCEEDED,
+ SMSG_CHAR_CREATE_FAILED,
+ SMSG_CHAR_DELETE_SUCCEEDED,
+ SMSG_CHAR_DELETE_FAILED,
+ SMSG_CHAR_MAP_INFO,
0
};
handledMessages = _messages;
@@ -89,7 +89,7 @@ void CharServerHandler::handleMessage(MessageIn &msg)
state = STATE_CHAR_SELECT;
break;
- case 0x006c:
+ case SMSG_CHAR_LOGIN_ERROR:
switch (msg.readInt8()) {
case 0:
errorMessage = _("Access denied");
@@ -104,7 +104,7 @@ void CharServerHandler::handleMessage(MessageIn &msg)
mCharInfo->unlock();
break;
- case 0x006d:
+ case SMSG_CHAR_CREATE_SUCCEEDED:
tempPlayer = readPlayerData(msg, slot);
mCharInfo->unlock();
mCharInfo->select(slot);
@@ -119,7 +119,7 @@ void CharServerHandler::handleMessage(MessageIn &msg)
}
break;
- case 0x006e:
+ case SMSG_CHAR_CREATE_FAILED:
new OkDialog(_("Error"), _("Failed to create character. Most likely"
" the name is already taken."));
@@ -127,7 +127,7 @@ void CharServerHandler::handleMessage(MessageIn &msg)
mCharCreateDialog->unlock();
break;
- case 0x006f:
+ case SMSG_CHAR_DELETE_SUCCEEDED:
delete mCharInfo->getEntry();
mCharInfo->setEntry(0);
mCharInfo->unlock();
@@ -135,12 +135,12 @@ void CharServerHandler::handleMessage(MessageIn &msg)
new OkDialog(_("Info"), _("Player deleted"));
break;
- case 0x0070:
+ case SMSG_CHAR_DELETE_FAILED:
mCharInfo->unlock();
new OkDialog(_("Error"), _("Failed to delete character."));
break;
- case 0x0071:
+ case SMSG_CHAR_MAP_INFO:
player_node = mCharInfo->getEntry();
slot = mCharInfo->getPos();
msg.skip(4); // CharID, must be the same as player_node->charID
@@ -236,7 +236,7 @@ void CharServerHandler::connect(LoginData *loginData)
{
mLoginData = loginData;
- MessageOut outMsg(0x0065);
+ MessageOut outMsg(CMSG_CHAR_SERVER_CONNECT);
outMsg.writeInt32(loginData->account_ID);
outMsg.writeInt32(loginData->session_ID1);
outMsg.writeInt32(loginData->session_ID2);
diff --git a/src/net/ea/chathandler.cpp b/src/net/ea/chathandler.cpp
index 626f1048..2e8df374 100644
--- a/src/net/ea/chathandler.cpp
+++ b/src/net/ea/chathandler.cpp
@@ -54,7 +54,7 @@ ChatHandler::ChatHandler()
SMSG_WHISPER,
SMSG_WHISPER_RESPONSE,
SMSG_GM_CHAT,
- 0x10c, // MVP
+ SMSG_MVP, // MVP
0
};
handledMessages = _messages;
@@ -164,7 +164,7 @@ void ChatHandler::handleMessage(MessageIn &msg)
break;
}
- case 0x010c:
+ case SMSG_MVP:
// Display MVP player
msg.readInt32(); // id
localChatTab->chatLog("MVP player", BY_SERVER);
diff --git a/src/net/ea/generalhandler.cpp b/src/net/ea/generalhandler.cpp
index 7d5a7d40..1084c138 100644
--- a/src/net/ea/generalhandler.cpp
+++ b/src/net/ea/generalhandler.cpp
@@ -46,12 +46,16 @@
#include "net/messagein.h"
#include "net/messageout.h"
+#include "resources/itemdb.h"
+
#include "configuration.h"
#include "log.h"
#include "main.h"
#include "utils/gettext.h"
+#include <list>
+
Net::GeneralHandler *generalHandler;
namespace EAthena {
@@ -80,6 +84,23 @@ GeneralHandler::GeneralHandler():
};
handledMessages = _messages;
generalHandler = this;
+
+ std::list<ItemDB::Stat*> stats;
+ ItemDB::Stat stat;
+ stat.tag = "str"; stat.format = N_("Strength: %d");
+ stats.push_back(&stat);
+ stat.tag = "agi"; stat.format = N_("Agility: %d");
+ stats.push_back(&stat);
+ stat.tag = "vit"; stat.format = N_("Vitality: %d");
+ stats.push_back(&stat);
+ stat.tag = "int"; stat.format = N_("Intelligence: %d");
+ stats.push_back(&stat);
+ stat.tag = "dex"; stat.format = N_("Dexterity: %d");
+ stats.push_back(&stat);
+ stat.tag = "luck"; stat.format = N_("Luck: %d");
+ stats.push_back(&stat);
+
+ ItemDB::setStatsList(stats);
}
GeneralHandler::~GeneralHandler()
diff --git a/src/net/ea/loginhandler.cpp b/src/net/ea/loginhandler.cpp
index 9c34c4cd..d9093e16 100644
--- a/src/net/ea/loginhandler.cpp
+++ b/src/net/ea/loginhandler.cpp
@@ -45,8 +45,8 @@ LoginHandler::LoginHandler()
{
static const Uint16 _messages[] = {
SMSG_UPDATE_HOST,
- 0x0069,
- 0x006a,
+ SMSG_LOGIN_DATA,
+ SMSG_LOGIN_ERROR,
0
};
handledMessages = _messages;
@@ -69,7 +69,7 @@ void LoginHandler::handleMessage(MessageIn &msg)
mUpdateHost.c_str());
break;
- case 0x0069:
+ case SMSG_LOGIN_DATA:
// Skip the length word
msg.skip(2);
@@ -102,7 +102,7 @@ void LoginHandler::handleMessage(MessageIn &msg)
state = STATE_CHAR_SERVER;
break;
- case 0x006a:
+ case SMSG_LOGIN_ERROR:
code = msg.readInt8();
logger->log("Login::error code: %i", code);
diff --git a/src/net/ea/maphandler.cpp b/src/net/ea/maphandler.cpp
index 6b061798..79e41914 100644
--- a/src/net/ea/maphandler.cpp
+++ b/src/net/ea/maphandler.cpp
@@ -43,7 +43,7 @@ namespace EAthena {
MapHandler::MapHandler()
{
static const Uint16 _messages[] = {
- SMSG_LOGIN_SUCCESS,
+ SMSG_MAP_LOGIN_SUCCESS,
SMSG_SERVER_PING,
SMSG_WHO_ANSWER,
0
@@ -58,7 +58,7 @@ void MapHandler::handleMessage(MessageIn &msg)
switch (msg.getId())
{
- case SMSG_LOGIN_SUCCESS:
+ case SMSG_MAP_LOGIN_SUCCESS:
msg.readInt32(); // server tick
msg.readCoordinates(player_node->mX, player_node->mY, direction);
msg.skip(2); // unknown
@@ -100,7 +100,7 @@ void MapHandler::mapLoaded(const std::string &mapName)
void MapHandler::who()
{
- MessageOut outMsg(0x00c1);
+ MessageOut outMsg(CMSG_WHO_REQUEST);
}
void MapHandler::quit()
diff --git a/src/net/ea/playerhandler.cpp b/src/net/ea/playerhandler.cpp
index 5d2a4829..c0c0fe20 100644
--- a/src/net/ea/playerhandler.cpp
+++ b/src/net/ea/playerhandler.cpp
@@ -435,14 +435,14 @@ void PlayerHandler::handleMessage(MessageIn &msg)
void PlayerHandler::attack(Being *being)
{
- MessageOut outMsg(0x0089);
+ MessageOut outMsg(CMSG_PLAYER_ATTACK);
outMsg.writeInt32(being->getId());
outMsg.writeInt8(0);
}
void PlayerHandler::emote(int emoteId)
{
- MessageOut outMsg(0x00bf);
+ MessageOut outMsg(CMSG_PLAYER_EMOTE);
outMsg.writeInt8(emoteId);
}
@@ -501,20 +501,28 @@ void PlayerHandler::setDestination(int x, int y, int direction)
{
char temp[4] = "";
set_coordinates(temp, x, y, direction);
- MessageOut outMsg(0x0085);
+ MessageOut outMsg(CMSG_PLAYER_CHANGE_DEST);
outMsg.writeString(temp, 3);
}
void PlayerHandler::changeAction(Being::Action action)
{
- MessageOut outMsg(0x0089);
+ char type;
+ switch (action)
+ {
+ case Being::SIT: type = 2; break;
+ case Being::STAND: type = 3; break;
+ default: return;
+ }
+
+ MessageOut outMsg(CMSG_PLAYER_CHANGE_ACT);
outMsg.writeInt32(0);
- outMsg.writeInt8((action == Being::SIT) ? 2 : 3);
+ outMsg.writeInt8(type);
}
void PlayerHandler::respawn()
{
- MessageOut outMsg(0x00b2);
+ MessageOut outMsg(CMSG_PLAYER_RESPAWN);
outMsg.writeInt8(0);
}
diff --git a/src/net/ea/protocol.h b/src/net/ea/protocol.h
index a9028f7e..d34a635f 100644
--- a/src/net/ea/protocol.h
+++ b/src/net/ea/protocol.h
@@ -28,10 +28,22 @@ static const int STORAGE_OFFSET = 1;
/*********************************
* Packets from server to client *
*********************************/
-#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */
#define SMSG_SERVER_PING 0x007f /**< Contains server tick */
#define SMSG_CONNECTION_PROBLEM 0x0081
+
#define SMSG_UPDATE_HOST 0x0063 /**< Custom update host packet */
+#define SMSG_LOGIN_DATA 0x0069
+#define SMSG_LOGIN_ERROR 0x006a
+
+#define SMSG_CHAR_LOGIN 0x006b
+#define SMSG_CHAR_LOGIN_ERROR 0x006c
+#define SMSG_CHAR_CREATE_SUCCEEDED 0x006d
+#define SMSG_CHAR_CREATE_FAILED 0x007e
+#define SMSG_CHAR_DELETE_SUCCEEDED 0x006f
+#define SMSG_CHAR_DELETE_FAILED 0x0070
+#define SMSG_CHAR_MAP_INFO 0x0071
+
+#define SMSG_MAP_LOGIN_SUCCESS 0x0073 /**< Contains starting location */
#define SMSG_PLAYER_UPDATE_1 0x01d8
#define SMSG_PLAYER_UPDATE_2 0x01d9
#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */
@@ -75,6 +87,9 @@ static const int STORAGE_OFFSET = 1;
#define SMSG_BEING_NAME_RESPONSE 0x0095 /**< Has to be requested */
#define SMSG_BEING_CHANGE_DIRECTION 0x009c
+#define SMSG_PLAYER_STATUS_CHANGE 0x0119
+#define SMSG_BEING_STATUS_CHANGE 0x0196
+
#define SMSG_NPC_MESSAGE 0x00b4
#define SMSG_NPC_NEXT 0x00b5
#define SMSG_NPC_CLOSE 0x00b6
@@ -120,35 +135,42 @@ static const int STORAGE_OFFSET = 1;
#define SMSG_ADMIN_KICK_ACK 0x00cd
+#define SMSG_MVP 0x010c
+
/**********************************
* Packets from client to server *
**********************************/
+#define CMSG_CHAR_SERVER_CONNECT 0x0065
#define CMSG_CHAR_SELECT 0x0066
#define CMSG_CHAR_CREATE 0x0067
#define CMSG_CHAR_DELETE 0x0068
#define CMSG_MAP_SERVER_CONNECT 0x0072
#define CMSG_CLIENT_PING 0x007e /**< Send to server with tick */
-#define CMSG_CLIENT_QUIT 0x018A
-#define CMSG_TRADE_RESPONSE 0x00e6
-#define CMSG_ITEM_PICKUP 0x009f
#define CMSG_MAP_LOADED 0x007d
+#define CMSG_CLIENT_QUIT 0x018A
+
#define CMSG_CHAT_MESSAGE 0x008c
#define CMSG_CHAT_WHISPER 0x0096
#define CMSG_CHAT_ANNOUNCE 0x0099
#define CMSG_CHAT_WHO 0x00c1
+
#define CMSG_SKILL_LEVELUP_REQUEST 0x0112
#define CMSG_STAT_UPDATE_REQUEST 0x00bb
-#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8
-#define CMSG_TRADE_CANCEL_REQUEST 0x00ed
-#define CMSG_TRADE_ADD_COMPLETE 0x00eb
-#define CMSG_TRADE_OK 0x00ef
-#define CMSG_TRADE_REQUEST 0x00e4
+
#define CMSG_PLAYER_INVENTORY_USE 0x00a7
#define CMSG_PLAYER_INVENTORY_DROP 0x00a2
#define CMSG_PLAYER_EQUIP 0x00a9
#define CMSG_PLAYER_UNEQUIP 0x00ab
+
+#define CMSG_ITEM_PICKUP 0x009f
#define CMSG_PLAYER_CHANGE_DIR 0x009b
+#define CMSG_PLAYER_CHANGE_DEST 0x0085
+#define CMSG_PLAYER_CHANGE_ACT 0x0089
+#define CMSG_PLAYER_RESPAWN 0x00b2
+#define CMSG_PLAYER_EMOTE 0x00bf
+#define CMSG_PLAYER_ATTACK 0x0089
+#define CMSG_WHO_REQUEST 0x00c1
#define CMSG_NPC_TALK 0x0090
#define CMSG_NPC_NEXT_REQUEST 0x00b9
@@ -160,6 +182,13 @@ static const int STORAGE_OFFSET = 1;
#define CMSG_NPC_BUY_REQUEST 0x00c8
#define CMSG_NPC_SELL_REQUEST 0x00c9
+#define CMSG_TRADE_REQUEST 0x00e4
+#define CMSG_TRADE_RESPONSE 0x00e6
+#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8
+#define CMSG_TRADE_CANCEL_REQUEST 0x00ed
+#define CMSG_TRADE_ADD_COMPLETE 0x00eb
+#define CMSG_TRADE_OK 0x00ef
+
#define CMSG_PARTY_CREATE 0x00f9
#define CMSG_PARTY_INVITE 0x00fc
#define CMSG_PARTY_INVITED 0x00ff
diff --git a/src/net/tmwserv/generalhandler.cpp b/src/net/tmwserv/generalhandler.cpp
index 98c764c5..cd9b2f15 100644
--- a/src/net/tmwserv/generalhandler.cpp
+++ b/src/net/tmwserv/generalhandler.cpp
@@ -40,6 +40,10 @@
#include "net/tmwserv/playerhandler.h"
#include "net/tmwserv/tradehandler.h"
+#include "utils/gettext.h"
+
+#include <list>
+
Net::GeneralHandler *generalHandler;
Net::Connection *gameServerConnection = 0;
@@ -70,6 +74,23 @@ GeneralHandler::GeneralHandler():
chatServerConnection = Net::getConnection();
generalHandler = this;
+
+ std::list<ItemDB::Stat*> stats;
+ ItemDB::Stat stat;
+ stat.tag = "str"; stat.format = N_("Strength: %d");
+ stats.push_back(&stat);
+ stat.tag = "agi"; stat.format = N_("Agility: %d");
+ stats.push_back(&stat);
+ stat.tag = "dex"; stat.format = N_("Dexterity: %d");
+ stats.push_back(&stat);
+ stat.tag = "vit"; stat.format = N_("Vitality: %d");
+ stats.push_back(&stat);
+ stat.tag = "int"; stat.format = N_("Intelligence: %d");
+ stats.push_back(&stat);
+ stat.tag = "will"; stat.format = N_("Willpower: %d");
+ stats.push_back(&stat);
+
+ ItemDB::setStatsList(stats);
}
void GeneralHandler::load()
diff --git a/src/resources/itemdb.cpp b/src/resources/itemdb.cpp
index 50eba33d..807fa0a4 100644
--- a/src/resources/itemdb.cpp
+++ b/src/resources/itemdb.cpp
@@ -56,6 +56,13 @@ static char const *const fields[][2] =
{ "mp", N_("MP %+d") }
};
+static std::list<ItemDB::Stat*> extraStats;
+
+void ItemDB::setStatsList(std::list<ItemDB::Stat*> stats)
+{
+ extraStats = stats;
+}
+
static ItemType itemTypeFromString(const std::string &name, int id = 0)
{
if (name=="generic") return ITEM_UNUSABLE;
@@ -149,7 +156,6 @@ void ItemDB::load()
itemInfo->setWeaponType(weaponType);
itemInfo->setAttackRange(attackRange);
-#ifdef TMWSERV_SUPPORT
std::string effect;
for (int i = 0; i < int(sizeof(fields) / sizeof(fields[0])); ++i)
{
@@ -158,12 +164,20 @@ void ItemDB::load()
if (!effect.empty()) effect += " / ";
effect += strprintf(gettext(fields[i][1]), value);
}
-#else
- std::string effect = XML::getProperty(node, "effect", "");
-#endif
+ for (std::list<Stat*>::iterator it = extraStats.begin();
+ it != extraStats.end(); it++)
+ {
+ int value = XML::getProperty(node, (*it)->tag.c_str(), 0);
+ if (!value) continue;
+ if (!effect.empty()) effect += " / ";
+ effect += strprintf((*it)->format.c_str(), value);
+ }
+ std::string temp = XML::getProperty(node, "effect", "");
+ if (!effect.empty() && !temp.empty())
+ effect += " / ";
+ effect += temp;
itemInfo->setEffect(effect);
-
for_each_xml_child_node(itemChild, node)
{
if (xmlStrEqual(itemChild->name, BAD_CAST "sprite"))
diff --git a/src/resources/itemdb.h b/src/resources/itemdb.h
index 770f32dd..2bb8fd5e 100644
--- a/src/resources/itemdb.h
+++ b/src/resources/itemdb.h
@@ -22,6 +22,7 @@
#ifndef ITEM_MANAGER_H
#define ITEM_MANAGER_H
+#include <list>
#include <map>
#include <string>
@@ -45,6 +46,13 @@ namespace ItemDB
const ItemInfo &get(int id);
const ItemInfo &get(const std::string &name);
+ struct Stat {
+ std::string tag;
+ std::string format;
+ };
+
+ void setStatsList(std::list<Stat*> stats);
+
// Items database
typedef std::map<int, ItemInfo*> ItemInfos;
typedef std::map<std::string, ItemInfo*> NamedItemInfos;
diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cpp
index 33d5e3e5..0b8d6c35 100644
--- a/src/resources/resourcemanager.cpp
+++ b/src/resources/resourcemanager.cpp
@@ -419,7 +419,35 @@ void *ResourceManager::loadFile(const std::string &fileName, int &fileSize)
return buffer;
}
-std::vector<std::string> ResourceManager::loadTextFile(const std::string &fileName)
+bool ResourceManager::copyFile(const std::string &src, const std::string &dst)
+{
+ PHYSFS_file *srcFile = PHYSFS_openRead(src.c_str());
+ if (!srcFile)
+ {
+ logger->log("Read error: %s", PHYSFS_getLastError());
+ return false;
+ }
+ PHYSFS_file *dstFile = PHYSFS_openWrite(dst.c_str());
+ if (!dstFile)
+ {
+ logger->log("Write error: %s", PHYSFS_getLastError());
+ PHYSFS_close(srcFile);
+ return false;
+ }
+
+ int fileSize = PHYSFS_fileLength(srcFile);
+ void *buf = malloc(fileSize);
+ PHYSFS_read(srcFile, buf, 1, fileSize);
+ PHYSFS_write(dstFile, buf, 1, fileSize);
+
+ PHYSFS_close(srcFile);
+ PHYSFS_close(dstFile);
+ free(buf);
+ return true;
+}
+
+std::vector<std::string> ResourceManager::loadTextFile(
+ const std::string &fileName)
{
int contentsLength;
char *fileContents = (char*)loadFile(fileName, contentsLength);
diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.h
index ec60fa9a..b2ad3069 100644
--- a/src/resources/resourcemanager.h
+++ b/src/resources/resourcemanager.h
@@ -125,6 +125,17 @@ class ResourceManager
Resource *load(const std::string &path, loader fun);
/**
+ * Copies a file from one place to another (useful for extracting
+ * raw files from a zip archive, for example)
+ *
+ * @param src Source file name
+ * @param dst Destination file name
+ * @return true on success, false on failure. An error message should be
+ * in the log file.
+ */
+ bool copyFile(const std::string &src, const std::string &dst);
+
+ /**
* Convenience wrapper around ResourceManager::get for loading
* images.
*/
diff --git a/src/sound.cpp b/src/sound.cpp
index a366f28d..4a9a6f39 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -141,7 +141,23 @@ static Mix_Music *loadMusic(const std::string &filename)
ResourceManager *resman = ResourceManager::getInstance();
std::string path = resman->getPath("music/" + filename);
- logger->log("Loading music \"%s\"", path.c_str());
+ if (path.find(".zip/") != std::string::npos ||
+ path.find(".zip\\") != std::string::npos)
+ {
+ // Music file is a virtual file inside a zip archive - we have to copy
+ // it to a temporary physical file so that SDL_mixer can stream it.
+ logger->log("Loading music \"%s\" from temporary file tempMusic.ogg",
+ path.c_str());
+ bool success = resman->copyFile("music/" + filename, "tempMusic.ogg");
+ if (success)
+ {
+ path = resman->getPath("tempMusic.ogg");
+ } else {
+ return NULL;
+ }
+ } else {
+ logger->log("Loading music \"%s\"", path.c_str());
+ }
Mix_Music *music = Mix_LoadMUS(path.c_str());