From 95ff7091a9bc5e45d851e7e6648311351efc325f Mon Sep 17 00:00:00 2001 From: Lwmte <3331699+Lwmte@users.noreply.github.com> Date: Sat, 17 Jun 2023 14:02:51 +0300 Subject: [PATCH] Sound engine enhancements (#1141) * Finalize features * Add descriptions * Amplify loudness output * fix compile error * Add subtitle parser for voice track * Update bass.lib * Return nil instead of empty string if no subtitle is found * Allow to use newlines in subtitles * Additionally try to load subtitles from /subtitles subdirectory * Don't stop ambience when Lara dies * Add option for turning subtitles on or off * Update TombEngine.vcxproj * Parse newlines correctly in subtitles * Add millisecond constant * Align menu * Minor formatting; remove newlines preventing tooltips --------- Co-authored-by: Kubsy Co-authored-by: Sezz --- Documentation/Changes.txt | 9 + Libs/bass/x86/bass.lib | Bin 25182 -> 25944 bytes Libs/srtparser/srtparser.h | 657 ++++ Scripts/Strings.lua | 1 + TombEngine/Game/Lara/lara.cpp | 2 +- TombEngine/Game/gui.cpp | 8 +- TombEngine/Game/savegame.cpp | 5 + TombEngine/Renderer/Renderer11DrawMenu.cpp | 23 +- .../Scripting/Internal/LanguageScript.h | 1 + .../Scripting/Internal/ReservedScriptNames.h | 4 + .../Scripting/Internal/TEN/Misc/CameraTypes.h | 12 +- .../Internal/TEN/Misc/Miscellaneous.cpp | 60 +- .../Internal/TEN/Misc/SoundTrackTypes.h | 30 + TombEngine/Sound/sound.cpp | 160 +- TombEngine/Sound/sound.h | 50 +- TombEngine/Specific/Input/Input.cpp | 3 +- TombEngine/Specific/configuration.cpp | 17 +- TombEngine/Specific/configuration.h | 2 + .../flatbuffers/ten_savegame_generated.h | 68 +- .../Specific/savegame/schema/ten_savegame.fbs | 2 + TombEngine/Specific/trutils.cpp | 16 +- TombEngine/Specific/trutils.h | 1 + TombEngine/TombEngine.vcxproj | 2983 +++++++++-------- 23 files changed, 2511 insertions(+), 1603 deletions(-) create mode 100644 Libs/srtparser/srtparser.h create mode 100644 TombEngine/Scripting/Internal/TEN/Misc/SoundTrackTypes.h diff --git a/Documentation/Changes.txt b/Documentation/Changes.txt index 9644ab7a9..9bf035ec4 100644 --- a/Documentation/Changes.txt +++ b/Documentation/Changes.txt @@ -4,6 +4,7 @@ Version 1.1.0 * Fix enemies shooting Lara through static meshes and moveables. * Fix skeletons and mummies not affected by explosive weapons. * Fix crash on loading if static meshes with IDs above maximum are present. +* Fix random crashes when playing audio tracks with names longer than 15 symbols. * Fix sprint value going below zero. * Fix fog bulb density formula. * Fix electricity effect crashing 64-bit version of the engine. @@ -12,6 +13,8 @@ Version 1.1.0 * Fix default ambience overlapping current one when loading a savegame. * Fix doppelganger being limited to be in a single room. * Add multiple doppelgangers by using the same OCB for the origin nullmesh and doppelganger. +* Implement separate audio track channel for playing voiceovers with subtitles. +* Don't stop ambience when Lara dies. * Pause all sounds when entering inventory or pause menu. * Improve deflection against slopes. * Move and rotate Lara together with dynamic bridge objects. @@ -19,6 +22,12 @@ Version 1.1.0 * Add TR1 skateboard kid. * Add TR1 Kold. +Lua API changes: +* Add soundtrack functions: + - Misc::GetAudioTrackLoudness() for getting current loudness of a given track type. + - Misc::IsAudioTrackPlaying() for checking if a given track type is playing. + - Misc::GetCurrentSubtitle() for getting current subtitle string for the voice track. + Version 1.0.9 ============= diff --git a/Libs/bass/x86/bass.lib b/Libs/bass/x86/bass.lib index 5a07fc47e94be6589e7704ef0026acee0deb7e1c..c69024ab53aa77394984519beea8c6bd4f084700 100644 GIT binary patch literal 25944 zcmY$iNi0gvu;bEKKm~?oW~PRwCWaOUsNyiLnX#EML?(fYfq~%~1A~zZ1A|Et1B2-_ z28NVB3=DB~5bV2xfdPc$UNJC$u%8G60|*CLF))Cz=Q#!j5cW@CU;yDjAqEBz_Ws4d z0K)MR3=AOb_l1E0g#9ltFo1A^0RsaV&tPCkn8Cmhv=4#APA0TVPF8`5(b9o5(b8tLl7J#$G`x_ z6BrnxCNMC>8bNTvKL!R6PRwIq0O6!41_lsLe8j*2!bxWs7(h7Lf`I{yH!v_HZ(v|Z zQGno}AO;2y4t&PI0K%cW7#Kh}yoG@QghTEyFo1CQ2L=WZ4)tJQ0O2qL1_lrg7hqrj z;fN##1`rNgz`y{)5my)(K-j{AfdPb_IT#o~*!lwl0|>ibU|;}Ydp-sR5VlETU;tse zc?=97Y;k~r0fg;8F))Czr2zv22s@l(U;tr{CI$vD{=mTC@qvNCApwFt;}{q~*rkYp z0fen4Fff3y2Nwea2-`O>Fo3Yj3kC)dwq|2s0Ac3_1_lteoX5Zb!p^@K7(m!cf`I{q zZ7wk|fUvs~0|N-#X)!Q>u&oON0~l{(V6ffBz+hbm!R|8{7(m!*3IhWOyKQ1%0AVKu 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 GodEz`TSs&N literal 25182 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 diff --git a/Libs/srtparser/srtparser.h b/Libs/srtparser/srtparser.h new file mode 100644 index 000000000..e1d9ffb65 --- /dev/null +++ b/Libs/srtparser/srtparser.h @@ -0,0 +1,657 @@ +/* + * Author : Saurabh Shrivastava + * Email : saurabh.shrivastava54@gmail.com + * Link : https://github.com/saurabhshri + * + * Based on subtitle-parser by Oleksii Maryshchenko. + * Email : young_developer@mail.ru + * Link : https://github.com/young-developer/subtitle-parser + */ + +#ifndef SRTPARSER_H +#define SRTPARSER_H + +#include +#include +#include +#include +#include +#include + +//function for splitting sentences based on supplied delimiter +inline std::vector &split(const std::string &s, char delim, std::vector &elems) { + std::stringstream ss(s); + std::string item; + + while (getline(ss, item, delim)) { + elems.push_back(item); + } + return elems; +} + +/**** Class definitions ****/ + + +class SubtitleWord +{ +private: + std::string _text; +public: + SubtitleWord(void); + SubtitleWord(std::string text); + virtual std::string getText() const; + ~SubtitleWord(void); +}; + +class SubtitleItem +{ +private: + long int _startTime; //in milliseconds + long int _endTime; + std::string _text; //actual line, as present in subtitle file + long int timeMSec(std::string value); //converts time string into ms + + int _subNo; //subtitle number + std::string _startTimeString; //time as in srt format + std::string _endTimeString; + bool _ignore; //should subtitle be ignore; used when the subtitle is empty after processing + std::string _justDialogue; //contains processed subtitle - stripped style, non dialogue text removal etc. + int _speakerCount; //count of number of speakers + std::vector _speaker; //list of speakers in a single subtitle + int _nonDialogueCount; //count of non spoken words in a subtitle + std::vector _nonDialogue; //list of non dialogue words, e.g. (applause) + int _wordCount; //number of words in _justDialogue + std::vector _word; //list of words in dialogue + std::vector _wordStartTime; //start time of each word in dialogue + std::vector _wordEndTime; //end time of each word in dialogue + std::vector _wordDuration; //actual duration of each word without silence + int _styleTagCount; //count of style tags in a single subtitle + std::vector _styleTag; //list of style tags in that subtitle + void extractInfo(bool keepHTML = 0, bool doNotIgnoreNonDialogues = 0, bool doNotRemoveSpeakerNames = 0); //process subtitle +public: + long int getStartTime() const; //returns starting time in ms + long int getEndTime() const; //returns ending time in ms + std::string getText() const; //returns subtitle text as present in .srt file + + int getSubNo() const; //returns subtitle number + std::string getStartTimeString() const; //returns sarting time as present in .srt file + std::string getEndTimeString() const; //returns ending time as present in .srt file + bool getIgnoreStatus() const; //returns status, whether the subtitle is ignorable or not after processing + std::string getDialogue(bool keepHTML = 0, bool doNotIgnoreNonDialogues = 0, bool doNotRemoveSpeakerNames = 0); //returns processed subtitle + int getSpeakerCount() const; //return speaker count + int getNonDialogueCount() const; //return non dialogue words count + int getStyleTagCount() const; //return style tags count + int getWordCount() const; //return words count + std::vector getIndividualWords(); //return string vector of individual words + std::string getWordByIndex(int index); //return word stored at 'index' + std::vector getWordStartTimes(); //return long int vector of start time of individual words + std::vector getWordEndTimes(); //return long int vector of end time of individual words + long int getWordStartTimeByIndex(int index); //return the start time of a word based on index + long int getWordEndTimeByIndex (int index); //return the end time of a word based on index + std::vector getSpeakerNames(); //return string vector of speaker names + std::vector getNonDialogueWords(); //return string vector of non dialogue words + std::vector getStyleTags(); //return string vector of style tags + + + void setStartTime(long int startTime); //set starting time + void setEndTime(long int endTime); //set ending time + void setText(std::string text); //set subtitle text + void setWordTimes(std::vector wordStartTime, std::vector wordEndTime, std::vector wordDuration); //assign time to individual words + + SubtitleItem(void); + SubtitleItem(int subNo, std::string startTime,std::string endTime, std::string text, bool ignore = false, + std::string justDialogue = "" , int speakerCount = 0, int nonDialogueCount = 0, + int styleTagCount = 0, int wordCount = 0, std::vector speaker = std::vector(), + std::vector nonDialogue = std::vector(), + std::vector styleTags = std::vector(), + std::vector word = std::vector()); //default constructor + ~SubtitleItem(void); +}; + +class SubtitleParser +{ +protected: + std::vector _subtitles; //stores subtitles + std::string _fileName; //supplied filename + virtual void parse(std::string fileName) = 0; +public: + virtual std::vector getSubtitles(); //returns subtitles + std::string getFileData(); + SubtitleParser(void); + virtual ~SubtitleParser(void); +}; + +class SubtitleParserFactory +{ +private: + std::string _fileName; +public: + SubtitleParser* getParser(); + SubtitleParserFactory(std::string fileName); + ~SubtitleParserFactory(void); +}; + +class SubRipParser : public SubtitleParser +{ + void parse(std::string fileName); +public: + SubRipParser(void); + SubRipParser(std::string fileName); + ~SubRipParser(void); +}; + + +/**** Function definitions ****/ + +//1. SubtitleParserFactory class + +inline SubtitleParserFactory::SubtitleParserFactory(std::string fileName) +{ + _fileName = fileName; +} + +inline SubtitleParser* SubtitleParserFactory::getParser() +{ + return new SubRipParser(_fileName); //creates and returns SubRipParser obj +} + +inline SubtitleParserFactory::~SubtitleParserFactory(void) +{ +} + +//2. SubtitleParser class + +inline std::vector SubtitleParser::getSubtitles() +{ + return _subtitles; +} + +inline std::string SubtitleParser::getFileData() //returns whole read file i.e. contents of input.srt +{ + std::ifstream infile(_fileName); + std::string allData = ""; + std::string line; + while (std::getline(infile, line)) + { + std::istringstream iss(line); + allData += line + "\n"; + } + return allData; + +} + +inline SubtitleParser::SubtitleParser(void) +{ + +} + +inline SubtitleParser::~SubtitleParser(void) +{ +} + +//3. SubRipParser class + +inline SubRipParser::SubRipParser(void) +{ +} + +inline void SubRipParser::parse(std::string fileName) //srt parser +{ + + std::ifstream infile(fileName); + std::string line, start, end, completeLine = "", timeLine = ""; + int subNo, turn = 0; + + /* + * turn = 0 -> Add subtitle number + * turn = 1 -> Add string to timeLine + * turn > 1 -> Add string to completeLine + */ + + while (std::getline(infile, line)) + { + line.erase(remove(line.begin(), line.end(), '\r'), line.end()); + + if (line.compare("")) + { + if(!turn) + { + subNo=atoi(line.c_str()); + turn++; + continue; + } + + if (line.find("-->") != std::string::npos) + { + timeLine += line; + + std::vector srtTime; + srtTime = split(timeLine, ' ', srtTime); + start = srtTime[0]; + end = srtTime[2]; + + } + else + { + if (completeLine != "") + completeLine += "\n"; + + completeLine += line; + } + + turn++; + } + + else + { + turn = 0; + _subtitles.push_back(new SubtitleItem(subNo,start,end,completeLine)); + completeLine = timeLine = ""; + } + + if(infile.eof()) //insert last remaining subtitle + { + _subtitles.push_back(new SubtitleItem(subNo,start,end,completeLine)); + } + } +} + +inline SubRipParser::SubRipParser(std::string fileName) +{ + _fileName = fileName; + parse(fileName); +} + +inline SubRipParser::~SubRipParser(void) +{ + for(int i=0;i != _subtitles.size();++i) + { + if(_subtitles[i]) + delete _subtitles[i]; + } +} + +//4. SubtitleItem class + +inline SubtitleItem::SubtitleItem(void) +{ +} + +inline SubtitleItem::SubtitleItem(int subNo, std::string startTime,std::string endTime, std::string text, bool ignore, + std::string justDialogue, int speakerCount, int nonDialogueCount, + int styleTagCount, int wordCount, std::vector speaker, std::vector nonDialogue, + std::vector styleTags, std::vector word) +{ + _startTime = timeMSec(startTime); + _endTime = timeMSec(endTime); + _text = text; + + _subNo = subNo; + _startTimeString = startTime; + _endTimeString = endTime; + _ignore = ignore; + _justDialogue = justDialogue; + _speakerCount = speakerCount; + _nonDialogueCount = nonDialogueCount; + _wordCount = wordCount; + _speaker = speaker; + _styleTagCount = styleTagCount; + _styleTag = styleTags; + _nonDialogue = nonDialogue; + _word = word; + + extractInfo(); +} + +inline long int SubtitleItem::timeMSec(std::string value) +{ + std::vector t, secs; + int hours, mins, seconds, milliseconds; + + t = split(value, ':', t); + hours = atoi(t[0].c_str()); + mins = atoi(t[1].c_str()); + + secs = split(t[2], ',', secs); + seconds = atoi(secs[0].c_str()); + milliseconds = atoi(secs[1].c_str()); + + return hours * 3600000 + mins * 60000 + seconds * 1000 + milliseconds; +} + +inline long int SubtitleItem::getStartTime() const +{ + return _startTime; +} +inline long int SubtitleItem::getEndTime() const +{ + return _endTime; +} + +inline std::string SubtitleItem::getText() const +{ + return _text; +} + +inline void SubtitleItem::setStartTime(long int startTime) +{ + _startTime = startTime; +} +inline void SubtitleItem::setEndTime(long int endTime) +{ + _endTime = endTime; +} +inline void SubtitleItem::setText(std::string text) +{ + _text = text; +} +inline void SubtitleItem::setWordTimes(std::vector wordStartTime, std::vector wordEndTime, std::vector wordDuration) +{ + _wordStartTime = wordStartTime; + _wordEndTime = wordEndTime; + _wordDuration = wordDuration; +} +inline int SubtitleItem::getSubNo() const +{ + return _subNo; +} +inline std::string SubtitleItem::getStartTimeString() const +{ + return _startTimeString; +} + +inline std::string SubtitleItem::getEndTimeString() const +{ + return _endTimeString; +} + +inline bool SubtitleItem::getIgnoreStatus() const +{ + if(_ignore) + return true; + + else + return false; + +} + +inline void SubtitleItem::extractInfo(bool keepHTML, bool doNotIgnoreNonDialogues, bool doNotRemoveSpeakerNames) //process subtitle +{ + std::string output = _text; + + //stripping HTML tags + if(!keepHTML) + { + /* + * TODO : Before erasing, extract the words. + * std::vector getStyleTags(); + * int getStyleTagCount() const; + * std::vector _styleTag; + * int _styleTagCount; + */ + + int countP = 0; + for(char& c : output) // replacing <...> with ~~~~ + { + if(c=='<') + { + countP++; + c = '~'; + } + + else + { + if(countP!=0) + { + if(c != '>') + c = '~'; + + else if(c == '>') + { + c = '~'; + countP--; + } + } + } + } + } + + //stripping non dialogue data e.g. (applause) + + if(!doNotIgnoreNonDialogues) + { + /* + * TODO : Before erasing, extract the words. + * std::vector getNonDialogueWords(); + * int getNonDialogueCount() const; + * std::vector _nonDialogue; + * int _nonDialogueCount; + */ + + int countP = 0; + for(char& c : output) // replacing (...) with ~~~~ + { + if(c=='(') + { + countP++; + c = '~'; + } + + else + { + if(countP!=0) + { + if(c != ')') + c = '~'; + + else if(c == ')') + { + c = '~'; + countP--; + } + } + } + } + } + + output.erase(std::remove(output.begin(), output.end(), '~'), output.end()); // deleting all ~ + + //Extracting speaker names + if(!doNotRemoveSpeakerNames) + { + for(int i=0; output[i]!='\0';i++) + { + int colonIndex = 0, nameBeginIndex = 0; + if(output[i]==':') //speaker found; travel back + { + _speakerCount++; + colonIndex = i; + + int tempIndex = 0, foundEvilColon = 0, continueFlag = 0, spaceBeforeColon = 0; + + if(output[i-1] == ' ') + spaceBeforeColon = 2; + + /* + Possible Cases : + + Elon Musk: Hey Saurabh, you are pretty smart. // First and Last Name + Saurabh: *_* What? Elon Musk: Yes! // Two names in single line + Saurabh : OMG OMG! // Space before colon + Elon: LOL World: LAMAO + Saurabh: ._. // normal + + */ + + for(int j=i - spaceBeforeColon; j>=0;j--) + { + if(output[j] == '.' || output[j] == '!' || output[j] == ',' || output[j] == '?' || output[j] == '\n' + || output[j] == ' ' || j== 0) + { + + if(output[j] == '.' || output[j] == '!' || output[j] == ',' || output[j] == '?' || j == 0) + { + if((continueFlag && j == 0)) + { + if(!isupper(output[j])) + { + nameBeginIndex = tempIndex; + break; + } + + else + tempIndex = j; + + } + + else if(j!=0) + tempIndex = j + 1; + } + + else if(output[j] == ' ' && isupper(output[j+1])) + { + tempIndex = j; + continueFlag = 1; + + continue; + } + + else if(output[j] == ' ' && !isupper(output[j+1] && tempIndex == 0)) + { + _speakerCount--; + foundEvilColon = 1; + break; + } + + nameBeginIndex = tempIndex; + break; + } + } + + if(foundEvilColon) + continue; + + i = nameBeginIndex; //compensating the removal and changes in index + + //check if there's a space after colon i.e. A: Hello vs A:Hello + int removeSpace = 0; + if(output[colonIndex + 1]==' ') + removeSpace = 1; + + _speaker.push_back(output.substr(nameBeginIndex, colonIndex - nameBeginIndex)); + output.erase(nameBeginIndex, colonIndex - nameBeginIndex + removeSpace); + } + + } + + } + + // removing more than one whitespaces with one space + unique_copy (output.begin(), output.end(), std::back_insert_iterator(_justDialogue), + [](char a,char b) + { + return isspace(a) && isspace(b); + }); + + // trimming whitespaces + const char* whiteSpaces = " \t\n\r\f\v"; + _justDialogue.erase(0, _justDialogue.find_first_not_of(whiteSpaces)); + _justDialogue.erase(_justDialogue.find_last_not_of(whiteSpaces) + 1); + + if(_justDialogue.empty() || _justDialogue == " ") + _ignore = true; + + else + { + _word = split(_justDialogue, ' ', _word); //extracting individual words + _wordCount = (int)_word.size(); + } +} + +inline std::string SubtitleItem::getDialogue(bool keepHTML, bool doNotIgnoreNonDialogues, bool doNotRemoveSpeakerNames) +{ + if(_justDialogue.empty()) + extractInfo(keepHTML, doNotIgnoreNonDialogues, doNotRemoveSpeakerNames); + + return _justDialogue; +} +inline int SubtitleItem::getSpeakerCount() const +{ + return _speakerCount; +} +inline int SubtitleItem::getNonDialogueCount() const +{ + return _nonDialogueCount; +} +inline int SubtitleItem::getStyleTagCount() const +{ + return _styleTagCount; +} +inline int SubtitleItem::getWordCount() const +{ + return _wordCount; +} +inline std::vector SubtitleItem::getSpeakerNames() +{ + return _speaker; +} +inline std::vector SubtitleItem::getNonDialogueWords() +{ + return _nonDialogue; +} +inline std::vector SubtitleItem::getIndividualWords() +{ + return _word; +} +inline std::string SubtitleItem::getWordByIndex(int index) +{ + return _word[index]; +} +inline std::vector SubtitleItem::getWordStartTimes() +{ + return _wordStartTime; +} +inline std::vector SubtitleItem::getWordEndTimes() +{ + return _wordEndTime; +} +inline long int SubtitleItem::getWordStartTimeByIndex(int index) +{ + return _wordStartTime[index]; +} +inline long int SubtitleItem::getWordEndTimeByIndex(int index) +{ + return _wordEndTime[index]; +} +inline std::vector SubtitleItem::getStyleTags() +{ + return _styleTag; +} +inline SubtitleItem::~SubtitleItem(void) +{ + +} + +//5. SubtitleWordclass + +inline SubtitleWord::SubtitleWord(void) +{ + _text = ""; +} + +inline SubtitleWord::SubtitleWord(std::string text) +{ + _text = text; +} + +inline std::string SubtitleWord::getText() const +{ + return _text; +} + +inline SubtitleWord::~SubtitleWord(void) +{ +} + + +#endif //SRTPARSER_H \ No newline at end of file diff --git a/Scripts/Strings.lua b/Scripts/Strings.lua index 78f1bc822..6f660c499 100644 --- a/Scripts/Strings.lua +++ b/Scripts/Strings.lua @@ -90,6 +90,7 @@ local strings = rocket_launcher_ammo = { "Rocket Launcher Ammo" }, rocket_launcher = { "Rocket Launcher" }, rumble = { "Rumble" }, + subtitles = { "Subtitles" }, save_game = { "Save Game" }, savegame_timestamp = { "%02d Days %02d:%02d:%02d" }, screen_resolution = { "Screen Resolution" }, diff --git a/TombEngine/Game/Lara/lara.cpp b/TombEngine/Game/Lara/lara.cpp index 4a7edad13..f388b208b 100644 --- a/TombEngine/Game/Lara/lara.cpp +++ b/TombEngine/Game/Lara/lara.cpp @@ -716,7 +716,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll) item->HitPoints = -1; if (lara->Control.Count.Death == 0) - StopSoundTracks(); + StopSoundTracks(true); lara->Control.Count.Death++; if ((item->Flags & IFLAG_INVISIBLE)) diff --git a/TombEngine/Game/gui.cpp b/TombEngine/Game/gui.cpp index 5f09e09a0..ee2a39c3a 100644 --- a/TombEngine/Game/gui.cpp +++ b/TombEngine/Game/gui.cpp @@ -726,6 +726,7 @@ namespace TEN::Gui Reverb, MusicVolume, SfxVolume, + Subtitles, AutoTarget, ToggleRumble, ThumbstickCameraControl, @@ -733,7 +734,7 @@ namespace TEN::Gui Cancel }; - static const int numOtherSettingsOptions = 7; + static const int numOtherSettingsOptions = 8; OptionCount = numOtherSettingsOptions; @@ -772,6 +773,11 @@ namespace TEN::Gui SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); CurrentSettings.Configuration.EnableThumbstickCameraControl = !CurrentSettings.Configuration.EnableThumbstickCameraControl; break; + + case OtherSettingsOption::Subtitles: + SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); + CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles; + break; } } diff --git a/TombEngine/Game/savegame.cpp b/TombEngine/Game/savegame.cpp index f3b1d5c61..698a564dd 100644 --- a/TombEngine/Game/savegame.cpp +++ b/TombEngine/Game/savegame.cpp @@ -806,8 +806,10 @@ bool SaveGame::Save(int slot) // Soundtrack playheads auto bgmTrackData = GetSoundTrackNameAndPosition(SoundTrackType::BGM); auto oneshotTrackData = GetSoundTrackNameAndPosition(SoundTrackType::OneShot); + auto voiceTrackData = GetSoundTrackNameAndPosition(SoundTrackType::Voice); auto bgmTrackOffset = fbb.CreateString(bgmTrackData.first); auto oneshotTrackOffset = fbb.CreateString(oneshotTrackData.first); + auto voiceTrackOffset = fbb.CreateString(voiceTrackData.first); // Legacy soundtrack map std::vector soundTrackMap; @@ -1272,6 +1274,8 @@ bool SaveGame::Save(int slot) sgb.add_ambient_position(bgmTrackData.second); sgb.add_oneshot_track(oneshotTrackOffset); sgb.add_oneshot_position(oneshotTrackData.second); + sgb.add_voice_track(voiceTrackOffset); + sgb.add_voice_position(voiceTrackData.second); sgb.add_cd_flags(soundtrackMapOffset); sgb.add_action_queue(actionQueueOffset); sgb.add_flip_maps(flipMapsOffset); @@ -1456,6 +1460,7 @@ bool SaveGame::Load(int slot) // Restore soundtracks PlaySoundTrack(s->ambient_track()->str(), SoundTrackType::BGM, s->ambient_position()); PlaySoundTrack(s->oneshot_track()->str(), SoundTrackType::OneShot, s->oneshot_position()); + PlaySoundTrack(s->voice_track()->str(), SoundTrackType::Voice, s->voice_position()); // Legacy soundtrack map for (int i = 0; i < s->cd_flags()->size(); i++) diff --git a/TombEngine/Renderer/Renderer11DrawMenu.cpp b/TombEngine/Renderer/Renderer11DrawMenu.cpp index 417dedae1..c4e9a0a07 100644 --- a/TombEngine/Renderer/Renderer11DrawMenu.cpp +++ b/TombEngine/Renderer/Renderer11DrawMenu.cpp @@ -42,7 +42,7 @@ namespace TEN::Renderer // Vertical menu positioning templates constexpr auto MenuVerticalTop = 11; constexpr auto MenuVerticalDisplaySettings = 200; - constexpr auto MenuVerticalOtherSettings = 150; + constexpr auto MenuVerticalOtherSettings = 130; constexpr auto MenuVerticalBottomCenter = 400; constexpr auto MenuVerticalStatisticsTitle = 150; constexpr auto MenuVerticalOptionsTitle = 350; @@ -219,29 +219,32 @@ namespace TEN::Renderer DrawBar(g_Gui.GetCurrentSettings().Configuration.SfxVolume / 100.0f, *g_SFXVolumeBar, ID_SFX_BAR_TEXTURE, 0, false); GetNextBlockPosition(&y); + // Subtitles + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_SUBTITLES), PRINTSTRING_COLOR_ORANGE, SF(title_option == 3)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableSubtitles), PRINTSTRING_COLOR_WHITE, SF(title_option == 3)); + GetNextLinePosition(&y); // Auto targeting - AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_TARGET), PRINTSTRING_COLOR_ORANGE, SF(title_option == 3)); - AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.AutoTarget), PRINTSTRING_COLOR_WHITE, SF(title_option == 3)); + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_TARGET), PRINTSTRING_COLOR_ORANGE, SF(title_option == 4)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.AutoTarget), PRINTSTRING_COLOR_WHITE, SF(title_option == 4)); GetNextLinePosition(&y); // Vibration - AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, SF(title_option == 4)); - AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(title_option == 4)); + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, SF(title_option == 5)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(title_option == 5)); GetNextLinePosition(&y); // Thumbstick camera - AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_THUMBSTICK_CAMERA), PRINTSTRING_COLOR_ORANGE, SF(title_option == 5)); - AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableThumbstickCameraControl), PRINTSTRING_COLOR_WHITE, SF(title_option == 5)); + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_THUMBSTICK_CAMERA), PRINTSTRING_COLOR_ORANGE, SF(title_option == 6)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableThumbstickCameraControl), PRINTSTRING_COLOR_WHITE, SF(title_option == 6)); GetNextBlockPosition(&y); - // Apply - AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_APPLY), PRINTSTRING_COLOR_ORANGE, SF_Center(title_option == 6)); + AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_APPLY), PRINTSTRING_COLOR_ORANGE, SF_Center(title_option == 7)); GetNextLinePosition(&y); // Cancel - AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_CANCEL), PRINTSTRING_COLOR_ORANGE, SF_Center(title_option == 7)); + AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_CANCEL), PRINTSTRING_COLOR_ORANGE, SF_Center(title_option == 8)); break; case Menu::Controls: diff --git a/TombEngine/Scripting/Internal/LanguageScript.h b/TombEngine/Scripting/Internal/LanguageScript.h index 03a20e9a1..5b0871604 100644 --- a/TombEngine/Scripting/Internal/LanguageScript.h +++ b/TombEngine/Scripting/Internal/LanguageScript.h @@ -81,6 +81,7 @@ #define STRING_AUTO_TARGET "auto_target" #define STRING_RUMBLE "rumble" #define STRING_THUMBSTICK_CAMERA "thumbstick_camera" +#define STRING_SUBTITLES "subtitles" #define STRING_CONTROLS_MOVE_FORWARD "controls_move_forward" #define STRING_CONTROLS_MOVE_BACKWARD "controls_move_backward" #define STRING_CONTROLS_MOVE_LEFT "controls_move_left" diff --git a/TombEngine/Scripting/Internal/ReservedScriptNames.h b/TombEngine/Scripting/Internal/ReservedScriptNames.h index d5c54e906..a0a4a5532 100644 --- a/TombEngine/Scripting/Internal/ReservedScriptNames.h +++ b/TombEngine/Scripting/Internal/ReservedScriptNames.h @@ -196,8 +196,11 @@ static constexpr char ScriptReserved_SetAmbientTrack[] = "SetAmbientTrack"; static constexpr char ScriptReserved_PlayAudioTrack[] = "PlayAudioTrack"; static constexpr char ScriptReserved_StopAudioTrack[] = "StopAudioTrack"; static constexpr char ScriptReserved_StopAudioTracks[] = "StopAudioTracks"; +static constexpr char ScriptReserved_GetAudioTrackLoudness[] = "GetAudioTrackLoudness"; +static constexpr char ScriptReserved_GetCurrentSubtitle[] = "GetCurrentSubtitle"; static constexpr char ScriptReserved_PlaySound[] = "PlaySound"; static constexpr char ScriptReserved_IsSoundPlaying[] = "IsSoundPlaying"; +static constexpr char ScriptReserved_IsAudioTrackPlaying[] = "IsAudioTrackPlaying"; static constexpr char ScriptReserved_GiveInvItem[] = "GiveItem"; static constexpr char ScriptReserved_TakeInvItem[] = "TakeItem"; static constexpr char ScriptReserved_GetInvItemCount[] = "GetItemCount"; @@ -264,6 +267,7 @@ static constexpr char ScriptReserved_BlendID[] = "BlendID"; static constexpr char ScriptReserved_EffectID[] = "EffectID"; static constexpr char ScriptReserved_ActionID[] = "ActionID"; static constexpr char ScriptReserved_CameraType[] = "CameraType"; +static constexpr char ScriptReserved_SoundTrackType[] = "SoundTrackType"; static constexpr char ScriptReserved_LogLevel[] = "LogLevel"; static constexpr char ScriptReserved_RoomFlagID[] = "RoomFlagID"; static constexpr char ScriptReserved_RoomReverb[] = "RoomReverb"; diff --git a/TombEngine/Scripting/Internal/TEN/Misc/CameraTypes.h b/TombEngine/Scripting/Internal/TEN/Misc/CameraTypes.h index 9f4846539..7a939f5f3 100644 --- a/TombEngine/Scripting/Internal/TEN/Misc/CameraTypes.h +++ b/TombEngine/Scripting/Internal/TEN/Misc/CameraTypes.h @@ -27,10 +27,10 @@ The following constants are inside CameraType. static const std::unordered_map CAMERA_TYPE { - { "Chase", CameraType::Chase }, - { "Fixed", CameraType::Fixed }, - { "Look", CameraType::Look }, - { "Combat", CameraType::Combat }, - { "Heavy", CameraType::Heavy }, - { "Object", CameraType::Object } + { "CHASE", CameraType::Chase }, + { "FIXED", CameraType::Fixed }, + { "LOOK", CameraType::Look }, + { "COMBAT", CameraType::Combat }, + { "HEAVY", CameraType::Heavy }, + { "OBJECT", CameraType::Object } }; diff --git a/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp b/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp index 8d573e52f..7ad3e6a7f 100644 --- a/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp +++ b/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp @@ -17,6 +17,7 @@ #include "Scripting/Internal/TEN/Misc/ActionIDs.h" #include "Scripting/Internal/TEN/Misc/CameraTypes.h" #include "Scripting/Internal/TEN/Misc/LevelLog.h" +#include "Scripting/Internal/TEN/Misc/SoundTrackTypes.h" #include "Scripting/Internal/TEN/Vec3/Vec3.h" #include "Sound/sound.h" #include "Specific/clock.h" @@ -144,11 +145,11 @@ namespace Misc /// Play an audio track //@function PlayAudioTrack //@tparam string name of track (without file extension) to play - //@tparam bool loop if true, the track will loop; if false, it won't (default: false) - static void PlayAudioTrack(const std::string& trackName, TypeOrNil looped) + //@tparam Misc.SoundTrackType type of the audio track to play + static void PlayAudioTrack(const std::string& trackName, TypeOrNil mode) { - auto mode = USE_IF_HAVE(bool, looped, false) ? SoundTrackType::BGM : SoundTrackType::OneShot; - PlaySoundTrack(trackName, mode); + auto playMode = USE_IF_HAVE(SoundTrackType, mode, SoundTrackType::OneShot); + PlaySoundTrack(trackName, playMode); } ///Set and play an ambient track @@ -168,11 +169,40 @@ namespace Misc ///Stop audio track that is currently playing //@function StopAudioTrack - //@tparam bool looped if set, stop looped audio track, if not, stop one-shot audio track - static void StopAudioTrack(TypeOrNil looped) + //@tparam Misc.SoundTrackType type of the audio track + static void StopAudioTrack(TypeOrNil mode) { - auto mode = USE_IF_HAVE(bool, looped, false) ? SoundTrackType::BGM : SoundTrackType::OneShot; - StopSoundTrack(mode, SOUND_XFADETIME_ONESHOT); + auto playMode = USE_IF_HAVE(SoundTrackType, mode, SoundTrackType::OneShot); + StopSoundTrack(playMode, SOUND_XFADETIME_ONESHOT); + } + + ///Get current loudness level for specified track type + //@function GetAudioTrackLoudness + //@tparam Misc.SoundTrackType type of the audio track + //@treturn float current loudness of a specified audio track + static float GetAudioTrackLoudness(TypeOrNil mode) + { + auto playMode = USE_IF_HAVE(SoundTrackType, mode, SoundTrackType::OneShot); + return GetSoundTrackLoudness(playMode); + } + + ///Get current subtitle string for a voice track currently playing. + //Subtitle file must be in .srt format, have same filename as voice track, and be placed in same directory as voice track. + //Returns nil if no voice track is playing or no subtitle present. + //@function GetCurrentSubtitle + //@treturn string current subtitle string + static TypeOrNil GetCurrentVoiceTrackSubtitle() + { + auto& result = GetCurrentSubtitle(); + + if (result.has_value()) + { + return result.value(); + } + else + { + return sol::nil; + } } /// Play sound effect @@ -189,7 +219,15 @@ namespace Misc //@tparam int Sound ID to check. Corresponds to the value in the sound XML file or Tomb Editor's "Sound Infos" window. static bool IsSoundPlaying(int effectID) { - return IsSoundEffectPlaying(effectID); + return (Sound_EffectIsPlaying(effectID, nullptr) != SOUND_NO_CHANNEL); + } + + /// Check if the audio track is playing + //@function IsAudioTrackPlaying + //@tparam string Track filename to check. Should be without extension and without full directory path. + static bool IsAudioTrackPlaying(const std::string& trackName) + { + return Sound_TrackIsPlaying(trackName); } static bool CheckInput(int actionIndex) @@ -382,9 +420,12 @@ namespace Misc tableMisc.set_function(ScriptReserved_PlayAudioTrack, &PlayAudioTrack); tableMisc.set_function(ScriptReserved_StopAudioTrack, &StopAudioTrack); tableMisc.set_function(ScriptReserved_StopAudioTracks, &StopAudioTracks); + tableMisc.set_function(ScriptReserved_GetAudioTrackLoudness, &GetAudioTrackLoudness); + tableMisc.set_function(ScriptReserved_GetCurrentSubtitle, &GetCurrentVoiceTrackSubtitle); tableMisc.set_function(ScriptReserved_PlaySound, &PlaySoundEffect); tableMisc.set_function(ScriptReserved_IsSoundPlaying, &IsSoundPlaying); + tableMisc.set_function(ScriptReserved_IsAudioTrackPlaying, &IsAudioTrackPlaying); /// Check if particular action key is held //@function KeyIsHeld @@ -421,6 +462,7 @@ namespace Misc LuaHandler handler{ state }; handler.MakeReadOnlyTable(tableMisc, ScriptReserved_ActionID, ACTION_IDS); handler.MakeReadOnlyTable(tableMisc, ScriptReserved_CameraType, CAMERA_TYPE); + handler.MakeReadOnlyTable(tableMisc, ScriptReserved_SoundTrackType, SOUNDTRACK_TYPE); handler.MakeReadOnlyTable(tableMisc, ScriptReserved_LogLevel, LOG_LEVEL); } } diff --git a/TombEngine/Scripting/Internal/TEN/Misc/SoundTrackTypes.h b/TombEngine/Scripting/Internal/TEN/Misc/SoundTrackTypes.h new file mode 100644 index 000000000..e218da9b6 --- /dev/null +++ b/TombEngine/Scripting/Internal/TEN/Misc/SoundTrackTypes.h @@ -0,0 +1,30 @@ +#pragma once +#include "Sound/sound.h" + +/*** +Constants for the type of the audio tracks. +@enum Misc.SoundTrackType +@pragma nostrip +*/ + +/*** Misc.SoundTrackType constants. + +The following constants are inside SoundTrackType. + + ONESHOT + LOOPED + VOICE + +@section Misc.SoundTrackType +*/ + +/*** Table of sound track type constants (for use with sound track functions). +@table CONSTANT_STRING_HERE +*/ + +static const std::unordered_map SOUNDTRACK_TYPE +{ + { "ONESHOT", SoundTrackType::OneShot }, + { "LOOPED", SoundTrackType::BGM }, + { "VOICE", SoundTrackType::Voice } +}; diff --git a/TombEngine/Sound/sound.cpp b/TombEngine/Sound/sound.cpp index ff4695e6c..262125766 100644 --- a/TombEngine/Sound/sound.cpp +++ b/TombEngine/Sound/sound.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "Game/camera.h" #include "Game/collision/collide_room.h" @@ -11,6 +12,7 @@ #include "Game/Setup.h" #include "Specific/configuration.h" #include "Specific/level.h" +#include "Specific/trutils.h" #include "Specific/winmain.h" HSAMPLE BASS_SamplePointer[SOUND_MAX_SAMPLES]; @@ -35,7 +37,9 @@ static std::string FullAudioDirectory; std::map SoundTrackMap; std::unordered_map SoundTracks; -int SecretSoundIndex = 5; +std::vector Subtitles; + +static int SecretSoundIndex = 5; constexpr int LegacyLoopingTrackMin = 98; constexpr int LegacyLoopingTrackMax = 111; @@ -231,17 +235,17 @@ bool SoundEffect(int effectID, Pose* position, SoundEnvironment condition, float break; case SoundPlayMode::Wait: - if (existingChannel != -1) // Don't play until stopped + if (existingChannel != SOUND_NO_CHANNEL) // Don't play until stopped return false; break; case SoundPlayMode::Restart: - if (existingChannel != -1) // Stop existing and continue + if (existingChannel != SOUND_NO_CHANNEL) // Stop existing and continue Sound_FreeSlot(existingChannel, SOUND_XFADETIME_CUTSOUND); break; case SoundPlayMode::Looped: - if (existingChannel != -1) // Just update parameters and return, if already playing + if (existingChannel != SOUND_NO_CHANNEL) // Just update parameters and return, if already playing { Sound_UpdateEffectPosition(existingChannel, position); Sound_UpdateEffectAttributes(existingChannel, pitch, volume); @@ -261,7 +265,7 @@ bool SoundEffect(int effectID, Pose* position, SoundEnvironment condition, float // Get free channel to play sample int freeSlot = Sound_GetFreeSlot(); - if (freeSlot == -1) + if (freeSlot == SOUND_NO_CHANNEL) { TENLog("No free channel slot available!", LogLevel::Warning); return false; @@ -312,17 +316,18 @@ void PauseAllSounds(SoundPauseMode mode) return; } - for (auto& slot : SoundSlot) + for (const auto& slot : SoundSlot) { if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PLAYING)) BASS_ChannelPause(slot.Channel); } - if (mode == SoundPauseMode::Inventory) - return; - - for (auto& slot : SoundtrackSlot) + for (int i = 0; i < (int)SoundTrackType::Count; i++) { + if (mode == SoundPauseMode::Inventory && (SoundTrackType)i != SoundTrackType::Voice) + continue; + + const auto& slot = SoundtrackSlot[i]; if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PLAYING)) BASS_ChannelPause(slot.Channel); } @@ -333,7 +338,7 @@ void ResumeAllSounds(SoundPauseMode mode) if (mode == SoundPauseMode::Global) BASS_Start(); - for (auto& slot : SoundtrackSlot) + for (const auto& slot : SoundtrackSlot) { if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PAUSED)) BASS_ChannelStart(slot.Channel); @@ -342,7 +347,7 @@ void ResumeAllSounds(SoundPauseMode mode) if (mode == SoundPauseMode::Global) return; - for (auto& slot : SoundSlot) + for (const auto& slot : SoundSlot) { if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PAUSED)) BASS_ChannelStart(slot.Channel); @@ -418,7 +423,45 @@ void EnumerateLegacyTracks() } -void PlaySoundTrack(std::string track, SoundTrackType mode, QWORD position) +float GetSoundTrackLoudness(SoundTrackType mode) +{ + float result = 0.0f; + + if (!g_Configuration.EnableSound) + return result; + + if (!BASS_ChannelIsActive(SoundtrackSlot[(int)mode].Channel)) + return result; + + BASS_ChannelGetLevelEx(SoundtrackSlot[(int)mode].Channel, &result, 0.1f, BASS_LEVEL_MONO | BASS_LEVEL_RMS); + return std::clamp(result * 2.0f, 0.0f, 1.0f); +} + +std::optional GetCurrentSubtitle() +{ + if (!g_Configuration.EnableSound || !g_Configuration.EnableSubtitles) + return std::nullopt; + + auto channel = SoundtrackSlot[(int)SoundTrackType::Voice].Channel; + + if (!BASS_ChannelIsActive(channel)) + return std::nullopt; + + if (Subtitles.empty()) + return std::nullopt; + + long time = long(BASS_ChannelBytes2Seconds(channel, BASS_ChannelGetPosition(channel, BASS_POS_BYTE)) * SOUND_MILLISECONDS_IN_SECOND); + + for (auto* stringPtr : Subtitles) + { + if (time >= stringPtr->getStartTime() && time <= stringPtr->getEndTime()) + return stringPtr->getText(); + } + + return std::nullopt; +} + +void PlaySoundTrack(const std::string& track, SoundTrackType mode, QWORD position) { if (!g_Configuration.EnableSound) return; @@ -443,6 +486,7 @@ void PlaySoundTrack(std::string track, SoundTrackType mode, QWORD position) switch (mode) { case SoundTrackType::OneShot: + case SoundTrackType::Voice: crossfadeTime = SOUND_XFADETIME_ONESHOT; break; @@ -518,9 +562,34 @@ void PlaySoundTrack(std::string track, SoundTrackType mode, QWORD position) SoundtrackSlot[(int)mode].Channel = stream; SoundtrackSlot[(int)mode].Track = track; + + // Additionally attempt to load subtitle file, if exists. + if (mode == SoundTrackType::Voice) + LoadSubtitles(track); } -void PlaySoundTrack(std::string track, short mask) +void LoadSubtitles(const std::string& name) +{ + Subtitles.clear(); + + auto subtitleName = FullAudioDirectory + name + ".srt"; + + if (!std::filesystem::is_regular_file(subtitleName)) + subtitleName = FullAudioDirectory + "/subtitles/" + name + ".srt"; + + if (!std::filesystem::is_regular_file(subtitleName)) + return; + + auto factory = new SubtitleParserFactory(subtitleName); + auto parser = factory->getParser(); + Subtitles = parser->getSubtitles(); + delete factory; + + for (auto& sub : Subtitles) + sub->setText(ReplaceNewLineSymbols(sub->getText())); +} + +void PlaySoundTrack(const std::string& track, short mask) { // If track name was included in script, play it as registered track and take mask into account. // Otherwise, play it once without registering anywhere. @@ -559,10 +628,16 @@ void PlaySoundTrack(int index, short mask) PlaySoundTrack(SoundTracks[index].Name, SoundTracks[index].Mode); } -void StopSoundTracks() +void StopSoundTracks(bool excludeAmbience) { - StopSoundTrack(SoundTrackType::OneShot, SOUND_XFADETIME_ONESHOT); - StopSoundTrack(SoundTrackType::BGM, SOUND_XFADETIME_ONESHOT); + for (int i = 0; i < (int)SoundTrackType::Count; i++) + { + auto mode = (SoundTrackType)i; + if (excludeAmbience && mode == SoundTrackType::BGM) + continue; + + StopSoundTrack((SoundTrackType)i, SOUND_XFADETIME_ONESHOT); + } } void StopSoundTrack(SoundTrackType mode, int fadeoutTime) @@ -581,7 +656,6 @@ void ClearSoundTrackMasks() // Returns specified soundtrack type's stem name and playhead position. // To be used with savegames. To restore soundtrack, use PlaySoundtrack function with playhead position passed as 3rd argument. - std::pair GetSoundTrackNameAndPosition(SoundTrackType type) { auto track = SoundtrackSlot[(int)type]; @@ -610,7 +684,6 @@ void Sound_FreeSample(int index) // Get first free (non-playing) sound slot. // If no free slots found, now try to hijack slot which is as far from listener as possible - int Sound_GetFreeSlot() { for (int i = 0; i < SOUND_MAX_CHANNELS; i++) @@ -622,7 +695,7 @@ int Sound_GetFreeSlot() // No free slots, hijack now. float minDistance = 0; - int farSlot = -1; + int farSlot = SOUND_NO_CHANNEL; for (int i = 0; i < SOUND_MAX_CHANNELS; i++) { @@ -639,6 +712,25 @@ int Sound_GetFreeSlot() return farSlot; } +int Sound_TrackIsPlaying(const std::string& fileName) +{ + for (int i = 0; i < (int)SoundTrackType::Count; i++) + { + const auto& slot = SoundtrackSlot[i]; + + if (!BASS_ChannelIsActive(slot.Channel)) + continue; + + auto name1 = TEN::Utils::ToLower(slot.Track); + auto name2 = TEN::Utils::ToLower(fileName); + + if (name1.compare(name2) == 0) + return true; + } + + return false; +} + // Returns slot ID in which effect is playing, if found. If not found, returns -1. // We use origin position as a reference, because in original TRs it's not possible to clearly // identify what's the source of the producing effect. @@ -649,7 +741,8 @@ int Sound_EffectIsPlaying(int effectID, Pose *position) { if (SoundSlot[i].EffectID == effectID) { - if (SoundSlot[i].Channel == NULL) // Free channel + // Free channel. + if (SoundSlot[i].Channel == NULL) continue; if (BASS_ChannelIsActive(SoundSlot[i].Channel)) @@ -663,29 +756,21 @@ int Sound_EffectIsPlaying(int effectID, Pose *position) // Check if effect origin is equal OR in nearest possible hearing range. - Vector3 origin = Vector3(position->Position.x, position->Position.y, position->Position.z); + auto origin = Vector3(position->Position.x, position->Position.y, position->Position.z); if (Vector3::Distance(origin, SoundSlot[i].Origin) < SOUND_MAXVOL_RADIUS) return i; } else + { SoundSlot[i].Channel = NULL; // WTF, let's clean this up + } } } - return -1; -} -bool IsSoundEffectPlaying(int effectID) -{ - int channelIndex = Sound_EffectIsPlaying(effectID, nullptr); - - if (channelIndex == -1) - return false; - - return (SoundSlot[channelIndex].EffectID == effectID); + return SOUND_NO_CHANNEL; } // Gets the distance to the source. - float Sound_DistanceToListener(Pose *position) { // Assume sound is 2D menu sound. @@ -700,7 +785,6 @@ float Sound_DistanceToListener(Vector3 position) } // Calculate attenuated volume. - float Sound_Attenuate(float gain, float distance, float radius) { float result = gain * (1.0f - (distance / radius)); @@ -709,7 +793,6 @@ float Sound_Attenuate(float gain, float distance, float radius) } // Stop and free desired sound slot. - void Sound_FreeSlot(int index, unsigned int fadeout) { if (index >= SOUND_MAX_CHANNELS || index < 0) @@ -725,11 +808,10 @@ void Sound_FreeSlot(int index, unsigned int fadeout) SoundSlot[index].Channel = NULL; SoundSlot[index].State = SoundState::Idle; - SoundSlot[index].EffectID = -1; + SoundSlot[index].EffectID = SOUND_NO_CHANNEL; } // Update sound position in a level. - bool Sound_UpdateEffectPosition(int index, Pose *position, bool force) { if (index >= SOUND_MAX_CHANNELS || index < 0) @@ -773,7 +855,6 @@ bool Sound_UpdateEffectAttributes(int index, float pitch, float gain) // Update whole sound scene in a level. // Must be called every frame to update camera position and 3D parameters. - void Sound_UpdateScene() { if (!g_Configuration.EnableSound) @@ -851,7 +932,6 @@ void Sound_UpdateScene() // Initialize BASS engine and also prepare all sound data. // Called once on engine start-up. - void Sound_Init(const std::string& gameDirectory) { // Initialize and collect soundtrack paths. @@ -893,7 +973,6 @@ void Sound_Init(const std::string& gameDirectory) return; // Initialize channels and tracks array - ZeroMemory(SoundtrackSlot, (sizeof(HSTREAM) * (int)SoundTrackType::Count)); ZeroMemory(SoundSlot, (sizeof(SoundEffectSlot) * SOUND_MAX_CHANNELS)); // Attach reverb effect to 3D channel @@ -916,7 +995,6 @@ void Sound_Init(const std::string& gameDirectory) // Stop all sounds and streams, if any, unplug all channels from the mixer and unload BASS engine. // Must be called on engine quit. - void Sound_DeInit() { if (g_Configuration.EnableSound) diff --git a/TombEngine/Sound/sound.h b/TombEngine/Sound/sound.h index f5f45c423..de5913331 100644 --- a/TombEngine/Sound/sound.h +++ b/TombEngine/Sound/sound.h @@ -5,13 +5,12 @@ #include "Game/control/control.h" #include "Sound/sound_effects.h" -using std::string; - +constexpr auto SOUND_NO_CHANNEL = -1; constexpr auto SOUND_BASS_UNITS = 1.0f / 1024.0f; // TR->BASS distance unit coefficient constexpr auto SOUND_MAXVOL_RADIUS = 1024.0f; // Max. volume hearing distance constexpr auto SOUND_OMNIPRESENT_ORIGIN = Vector3(1.17549e-038f, 1.17549e-038f, 1.17549e-038f); -constexpr auto SOUND_MAX_SAMPLES = 8192; // Original was 1024, reallocate original 3-dword DX handle struct to just 1-dword memory pointer -constexpr auto SOUND_MAX_CHANNELS = 32; // Original was 24, reallocate original 36-byte struct with 24-byte SoundEffectSlot struct +constexpr auto SOUND_MAX_SAMPLES = 8192; +constexpr auto SOUND_MAX_CHANNELS = 32; constexpr auto SOUND_LEGACY_SOUNDMAP_SIZE = 450; constexpr auto SOUND_NEW_SOUNDMAP_MAX_SIZE = 4096; constexpr auto SOUND_LEGACY_TRACKTABLE_SIZE = 136; @@ -22,6 +21,7 @@ constexpr auto SOUND_MAX_PITCH_CHANGE = 0.09f; constexpr auto SOUND_MAX_GAIN_CHANGE = 0.0625f; constexpr auto SOUND_32BIT_SILENCE_LEVEL = 4.9e-04f; constexpr auto SOUND_SAMPLE_FLAGS = (BASS_SAMPLE_MONO | BASS_SAMPLE_FLOAT); +constexpr auto SOUND_MILLISECONDS_IN_SECOND = 1000.0f; constexpr auto SOUND_XFADETIME_BGM = 5000; constexpr auto SOUND_XFADETIME_BGM_START = 1500; constexpr auto SOUND_XFADETIME_ONESHOT = 200; @@ -42,6 +42,7 @@ enum class SoundTrackType { OneShot, BGM, + Voice, Count }; @@ -96,8 +97,8 @@ struct SoundEffectSlot struct SoundTrackSlot { - HSTREAM Channel; - std::string Track; + HSTREAM Channel { 0 }; + std::string Track {}; }; struct SampleInfo @@ -112,17 +113,17 @@ struct SampleInfo struct SoundTrackInfo { - std::string Name{}; - SoundTrackType Mode{ SoundTrackType::OneShot }; - int Mask{ 0 }; + std::string Name {}; + SoundTrackType Mode { SoundTrackType::OneShot }; + int Mask { 0 }; }; struct SoundSourceInfo { - Vector3i Position = Vector3i::Zero; - int SoundID = 0; - int Flags = 0; - string Name = ""; + Vector3i Position = Vector3i::Zero; + int SoundID = 0; + int Flags = 0; + std::string Name {}; SoundSourceInfo() { @@ -158,19 +159,21 @@ void FreeSamples(); void StopAllSounds(); void PauseAllSounds(SoundPauseMode mode); void ResumeAllSounds(SoundPauseMode mode); - -void PlaySoundTrack(std::string trackName, SoundTrackType mode, QWORD position = 0); -void PlaySoundTrack(std::string trackName, short mask = 0); -void PlaySoundTrack(int index, short mask = 0); -void StopSoundTrack(SoundTrackType mode, int fadeoutTime); -void StopSoundTracks(); -void ClearSoundTrackMasks(); -void PlaySecretTrack(); void SayNo(); void PlaySoundSources(); int GetShatterSound(int shatterID); -void EnumerateLegacyTracks(); +void PlaySoundTrack(const std::string& trackName, SoundTrackType mode, QWORD position = 0); +void PlaySoundTrack(const std::string& trackName, short mask = 0); +void PlaySoundTrack(int index, short mask = 0); +void StopSoundTrack(SoundTrackType mode, int fadeoutTime); +void StopSoundTracks(bool excludeAmbience = false); +void ClearSoundTrackMasks(); +void PlaySecretTrack(); +void EnumerateLegacyTracks(); +void LoadSubtitles(const std::string& path); +float GetSoundTrackLoudness(SoundTrackType mode); +std::optional GetCurrentSubtitle(); std::pair GetSoundTrackNameAndPosition(SoundTrackType type); static void CALLBACK Sound_FinishOneshotTrack(HSYNC handle, DWORD channel, DWORD data, void* userData); @@ -186,10 +189,9 @@ void Sound_FreeSample(int index); int Sound_GetFreeSlot(); void Sound_FreeSlot(int index, unsigned int fadeout = 0); int Sound_EffectIsPlaying(int effectID, Pose *position); +int Sound_TrackIsPlaying(const std::string& fileName); float Sound_DistanceToListener(Pose *position); float Sound_DistanceToListener(Vector3 position); float Sound_Attenuate(float gain, float distance, float radius); bool Sound_UpdateEffectPosition(int index, Pose *position, bool force = false); bool Sound_UpdateEffectAttributes(int index, float pitch, float gain); - -bool IsSoundEffectPlaying(int effectID); diff --git a/TombEngine/Specific/Input/Input.cpp b/TombEngine/Specific/Input/Input.cpp index e453cd6fb..bb0460a3e 100644 --- a/TombEngine/Specific/Input/Input.cpp +++ b/TombEngine/Specific/Input/Input.cpp @@ -777,7 +777,8 @@ namespace TEN::Input } auto vendor = TEN::Utils::ToLower(OisGamepad->vendor()); - if (vendor.find("xbox") != string::npos || vendor.find("xinput") != string::npos) + + if (vendor.find("xbox") != std::string::npos || vendor.find("xinput") != std::string::npos) { ApplyBindings(XInputBindings); diff --git a/TombEngine/Specific/configuration.cpp b/TombEngine/Specific/configuration.cpp index 3bef09741..c32725bfc 100644 --- a/TombEngine/Specific/configuration.cpp +++ b/TombEngine/Specific/configuration.cpp @@ -259,6 +259,12 @@ bool SaveConfiguration() return false; } + if (SetBoolRegKey(rootKey, REGKEY_ENABLE_SUBTITLES, g_Configuration.EnableSubtitles) != ERROR_SUCCESS) + { + RegCloseKey(rootKey); + return false; + } + if (SetBoolRegKey(rootKey, REGKEY_AUTOTARGET, g_Configuration.AutoTarget) != ERROR_SUCCESS) { RegCloseKey(rootKey); @@ -293,6 +299,7 @@ void InitDefaultConfiguration() auto currentScreenResolution = GetScreenResolution(); + g_Configuration.EnableSubtitles = true; g_Configuration.AutoTarget = true; g_Configuration.SoundDevice = 1; g_Configuration.EnableReverb = true; @@ -422,13 +429,20 @@ bool LoadConfiguration() return false; } - bool autoTarget = false; + bool autoTarget = true; if (GetBoolRegKey(rootKey, REGKEY_AUTOTARGET, &autoTarget, true) != ERROR_SUCCESS) { RegCloseKey(rootKey); return false; } + bool enableSubtitles = true; + if (GetBoolRegKey(rootKey, REGKEY_ENABLE_SUBTITLES, &enableSubtitles, true) != ERROR_SUCCESS) + { + RegCloseKey(rootKey); + return false; + } + for (int i = 0; i < KEY_COUNT; i++) { DWORD tempKey; @@ -464,6 +478,7 @@ bool LoadConfiguration() g_Configuration.AutoTarget = autoTarget; g_Configuration.EnableRumble = enableRumble; g_Configuration.EnableThumbstickCameraControl = enableThumbstickCamera; + g_Configuration.EnableSubtitles = enableSubtitles; // Set legacy variables SetVolumeMusic(musicVolume); diff --git a/TombEngine/Specific/configuration.h b/TombEngine/Specific/configuration.h index 67c0d5157..09d0954d8 100644 --- a/TombEngine/Specific/configuration.h +++ b/TombEngine/Specific/configuration.h @@ -24,6 +24,7 @@ using namespace TEN::Math; #define REGKEY_ENABLE_RUMBLE "EnableRumble" #define REGKEY_ENABLE_THUMBSTICK_CAMERA "EnableThumbstickCamera" +#define REGKEY_ENABLE_SUBTITLES "EnableSubtitles" #define REGKEY_AUTOTARGET "AutoTarget" @@ -45,6 +46,7 @@ struct GameConfiguration int ShadowMapSize = 1024; int ShadowMaxBlobs = 16; + bool EnableSubtitles; bool AutoTarget; bool EnableRumble; bool EnableThumbstickCameraControl; diff --git a/TombEngine/Specific/savegame/flatbuffers/ten_savegame_generated.h b/TombEngine/Specific/savegame/flatbuffers/ten_savegame_generated.h index 363470bef..0ab087cea 100644 --- a/TombEngine/Specific/savegame/flatbuffers/ten_savegame_generated.h +++ b/TombEngine/Specific/savegame/flatbuffers/ten_savegame_generated.h @@ -6775,6 +6775,8 @@ struct SaveGameT : public flatbuffers::NativeTable { uint64_t ambient_position = 0; std::string oneshot_track{}; uint64_t oneshot_position = 0; + std::string voice_track{}; + uint64_t voice_position = 0; std::vector cd_flags{}; std::unique_ptr rope{}; std::unique_ptr pendulum{}; @@ -6831,23 +6833,25 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_AMBIENT_POSITION = 62, VT_ONESHOT_TRACK = 64, VT_ONESHOT_POSITION = 66, - VT_CD_FLAGS = 68, - VT_ROPE = 70, - VT_PENDULUM = 72, - VT_ALTERNATE_PENDULUM = 74, - VT_VOLUMES = 76, - VT_CALL_COUNTERS = 78, - VT_SCRIPT_VARS = 80, - VT_CALLBACKS_PRE_START = 82, - VT_CALLBACKS_POST_START = 84, - VT_CALLBACKS_PRE_END = 86, - VT_CALLBACKS_POST_END = 88, - VT_CALLBACKS_PRE_SAVE = 90, - VT_CALLBACKS_POST_SAVE = 92, - VT_CALLBACKS_PRE_LOAD = 94, - VT_CALLBACKS_POST_LOAD = 96, - VT_CALLBACKS_PRE_CONTROL = 98, - VT_CALLBACKS_POST_CONTROL = 100 + VT_VOICE_TRACK = 68, + VT_VOICE_POSITION = 70, + VT_CD_FLAGS = 72, + VT_ROPE = 74, + VT_PENDULUM = 76, + VT_ALTERNATE_PENDULUM = 78, + VT_VOLUMES = 80, + VT_CALL_COUNTERS = 82, + VT_SCRIPT_VARS = 84, + VT_CALLBACKS_PRE_START = 86, + VT_CALLBACKS_POST_START = 88, + VT_CALLBACKS_PRE_END = 90, + VT_CALLBACKS_POST_END = 92, + VT_CALLBACKS_PRE_SAVE = 94, + VT_CALLBACKS_POST_SAVE = 96, + VT_CALLBACKS_PRE_LOAD = 98, + VT_CALLBACKS_POST_LOAD = 100, + VT_CALLBACKS_PRE_CONTROL = 102, + VT_CALLBACKS_POST_CONTROL = 104 }; const TEN::Save::SaveGameHeader *header() const { return GetPointer(VT_HEADER); @@ -6945,6 +6949,12 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { uint64_t oneshot_position() const { return GetField(VT_ONESHOT_POSITION, 0); } + const flatbuffers::String *voice_track() const { + return GetPointer(VT_VOICE_TRACK); + } + uint64_t voice_position() const { + return GetField(VT_VOICE_POSITION, 0); + } const flatbuffers::Vector *cd_flags() const { return GetPointer *>(VT_CD_FLAGS); } @@ -7064,6 +7074,9 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyOffset(verifier, VT_ONESHOT_TRACK) && verifier.VerifyString(oneshot_track()) && VerifyField(verifier, VT_ONESHOT_POSITION) && + VerifyOffset(verifier, VT_VOICE_TRACK) && + verifier.VerifyString(voice_track()) && + VerifyField(verifier, VT_VOICE_POSITION) && VerifyOffset(verifier, VT_CD_FLAGS) && verifier.VerifyVector(cd_flags()) && VerifyOffset(verifier, VT_ROPE) && @@ -7217,6 +7230,12 @@ struct SaveGameBuilder { void add_oneshot_position(uint64_t oneshot_position) { fbb_.AddElement(SaveGame::VT_ONESHOT_POSITION, oneshot_position, 0); } + void add_voice_track(flatbuffers::Offset voice_track) { + fbb_.AddOffset(SaveGame::VT_VOICE_TRACK, voice_track); + } + void add_voice_position(uint64_t voice_position) { + fbb_.AddElement(SaveGame::VT_VOICE_POSITION, voice_position, 0); + } void add_cd_flags(flatbuffers::Offset> cd_flags) { fbb_.AddOffset(SaveGame::VT_CD_FLAGS, cd_flags); } @@ -7313,6 +7332,8 @@ inline flatbuffers::Offset CreateSaveGame( uint64_t ambient_position = 0, flatbuffers::Offset oneshot_track = 0, uint64_t oneshot_position = 0, + flatbuffers::Offset voice_track = 0, + uint64_t voice_position = 0, flatbuffers::Offset> cd_flags = 0, flatbuffers::Offset rope = 0, flatbuffers::Offset pendulum = 0, @@ -7331,6 +7352,7 @@ inline flatbuffers::Offset CreateSaveGame( flatbuffers::Offset>> callbacks_pre_control = 0, flatbuffers::Offset>> callbacks_post_control = 0) { SaveGameBuilder builder_(_fbb); + builder_.add_voice_position(voice_position); builder_.add_oneshot_position(oneshot_position); builder_.add_ambient_position(ambient_position); builder_.add_callbacks_post_control(callbacks_post_control); @@ -7350,6 +7372,7 @@ inline flatbuffers::Offset CreateSaveGame( builder_.add_pendulum(pendulum); builder_.add_rope(rope); builder_.add_cd_flags(cd_flags); + builder_.add_voice_track(voice_track); builder_.add_oneshot_track(oneshot_track); builder_.add_ambient_track(ambient_track); builder_.add_action_queue(action_queue); @@ -7422,6 +7445,8 @@ inline flatbuffers::Offset CreateSaveGameDirect( uint64_t ambient_position = 0, const char *oneshot_track = nullptr, uint64_t oneshot_position = 0, + const char *voice_track = nullptr, + uint64_t voice_position = 0, const std::vector *cd_flags = nullptr, flatbuffers::Offset rope = 0, flatbuffers::Offset pendulum = 0, @@ -7457,6 +7482,7 @@ inline flatbuffers::Offset CreateSaveGameDirect( auto action_queue__ = action_queue ? _fbb.CreateVector(*action_queue) : 0; auto ambient_track__ = ambient_track ? _fbb.CreateString(ambient_track) : 0; auto oneshot_track__ = oneshot_track ? _fbb.CreateString(oneshot_track) : 0; + auto voice_track__ = voice_track ? _fbb.CreateString(voice_track) : 0; auto cd_flags__ = cd_flags ? _fbb.CreateVector(*cd_flags) : 0; auto volumes__ = volumes ? _fbb.CreateVector>(*volumes) : 0; auto call_counters__ = call_counters ? _fbb.CreateVector>(*call_counters) : 0; @@ -7504,6 +7530,8 @@ inline flatbuffers::Offset CreateSaveGameDirect( ambient_position, oneshot_track__, oneshot_position, + voice_track__, + voice_position, cd_flags__, rope, pendulum, @@ -9532,6 +9560,8 @@ inline void SaveGame::UnPackTo(SaveGameT *_o, const flatbuffers::resolver_functi { auto _e = ambient_position(); _o->ambient_position = _e; } { auto _e = oneshot_track(); if (_e) _o->oneshot_track = _e->str(); } { auto _e = oneshot_position(); _o->oneshot_position = _e; } + { auto _e = voice_track(); if (_e) _o->voice_track = _e->str(); } + { auto _e = voice_position(); _o->voice_position = _e; } { auto _e = cd_flags(); if (_e) { _o->cd_flags.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->cd_flags[_i] = _e->Get(_i); } } } { auto _e = rope(); if (_e) _o->rope = std::unique_ptr(_e->UnPack(_resolver)); } { auto _e = pendulum(); if (_e) _o->pendulum = std::unique_ptr(_e->UnPack(_resolver)); } @@ -9591,6 +9621,8 @@ inline flatbuffers::Offset CreateSaveGame(flatbuffers::FlatBufferBuild auto _ambient_position = _o->ambient_position; auto _oneshot_track = _o->oneshot_track.empty() ? _fbb.CreateSharedString("") : _fbb.CreateString(_o->oneshot_track); auto _oneshot_position = _o->oneshot_position; + auto _voice_track = _o->voice_track.empty() ? _fbb.CreateSharedString("") : _fbb.CreateString(_o->voice_track); + auto _voice_position = _o->voice_position; auto _cd_flags = _fbb.CreateVector(_o->cd_flags); auto _rope = _o->rope ? CreateRope(_fbb, _o->rope.get(), _rehasher) : 0; auto _pendulum = _o->pendulum ? CreatePendulum(_fbb, _o->pendulum.get(), _rehasher) : 0; @@ -9642,6 +9674,8 @@ inline flatbuffers::Offset CreateSaveGame(flatbuffers::FlatBufferBuild _ambient_position, _oneshot_track, _oneshot_position, + _voice_track, + _voice_position, _cd_flags, _rope, _pendulum, diff --git a/TombEngine/Specific/savegame/schema/ten_savegame.fbs b/TombEngine/Specific/savegame/schema/ten_savegame.fbs index c2fa9df2a..82f9d3bae 100644 --- a/TombEngine/Specific/savegame/schema/ten_savegame.fbs +++ b/TombEngine/Specific/savegame/schema/ten_savegame.fbs @@ -515,6 +515,8 @@ table SaveGame { ambient_position: uint64; oneshot_track: string; oneshot_position: uint64; + voice_track: string; + voice_position: uint64; cd_flags: [int32]; rope: Rope; pendulum: Pendulum; diff --git a/TombEngine/Specific/trutils.cpp b/TombEngine/Specific/trutils.cpp index d804a3cb7..407f98164 100644 --- a/TombEngine/Specific/trutils.cpp +++ b/TombEngine/Specific/trutils.cpp @@ -1,11 +1,11 @@ #include "framework.h" -#include "Specific/trutils.h" #include #include #include "Renderer/Renderer11.h" #include "Renderer/Renderer11Enums.h" +#include "Specific/trutils.h" using TEN::Renderer::g_Renderer; @@ -118,6 +118,20 @@ namespace TEN::Utils return std::wstring(buffer); } + std::string ReplaceNewLineSymbols(const std::string& string) + { + auto result = string; + std::string::size_type index = 0; + + while ((index = result.find("\\n", index)) != std::string::npos) + { + result.replace(index, 2, "\n"); + ++index; + } + + return result; + } + std::vector SplitString(const std::string& string) { auto strings = std::vector{}; diff --git a/TombEngine/Specific/trutils.h b/TombEngine/Specific/trutils.h index dfcc32750..83922b78c 100644 --- a/TombEngine/Specific/trutils.h +++ b/TombEngine/Specific/trutils.h @@ -4,6 +4,7 @@ namespace TEN::Utils { // String utilities std::string ConstructAssetDirectory(std::string customDirectory); + std::string ReplaceNewLineSymbols(const std::string& string); std::string ToUpper(std::string string); std::string ToLower(std::string string); std::string ToString(const std::wstring& wString); diff --git a/TombEngine/TombEngine.vcxproj b/TombEngine/TombEngine.vcxproj index 618aa61ac..f85f5219a 100644 --- a/TombEngine/TombEngine.vcxproj +++ b/TombEngine/TombEngine.vcxproj @@ -1,1492 +1,1493 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - 15.0 - {15AB0220-541C-4DA1-94EB-ED3C47E4582E} - Win32Proj - TombEngine - 10.0 - TombEngine - - - - Application - true - MultiByte - v143 - - - Application - true - MultiByte - v143 - - - Application - false - MultiByte - v143 - - - Application - false - MultiByte - v143 - - - - - - - - - - - - - - - - - - - - - true - $(SolutionDir)Build\$(Configuration)\Bin\x86\ - $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x86 - $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(IncludePath) - $(LibraryPath);$(DXSDK_DIR)Lib\x86;$(SolutionDir)Libs\spdlog\x86;$(SolutionDir)Libs\lua\x86;$(SolutionDir)Libs\zlib\x86;$(SolutionDir)Libs\bass\x86;$(SolutionDir)Libs\ois\x86 - .exe - - - $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x64 - $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(IncludePath) - $(LibraryPath);$(DXSDK_DIR)Lib\x64;$(SolutionDir)Libs\spdlog\x64;$(SolutionDir)Libs\lua\x64;$(SolutionDir)Libs\zlib\x64;$(SolutionDir)Libs\bass\x64;$(SolutionDir)Libs\ois\x64 - .exe - true - $(ProjectName) - $(SolutionDir)Build\$(Configuration)\Bin\x64\ - $(Configuration)\ - - - true - $(SolutionDir)Build\$(Configuration)\Bin\x86\ - $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x86 - $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\bass;$(IncludePath) - $(LibraryPath);$(DXSDK_DIR)Lib\x86;$(SolutionDir)Libs\spdlog\x86;$(SolutionDir)Libs\lua\x86;$(SolutionDir)Libs\zlib\x86;$(SolutionDir)Libs\bass\x86;$(SolutionDir)Libs\ois\x86 - .exe - - - $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x64 - $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(IncludePath) - $(LibraryPath);$(DXSDK_DIR)Lib\x64;$(SolutionDir)Libs\spdlog\x64;$(SolutionDir)Libs\lua\x64;$(SolutionDir)Libs\zlib\x64;$(SolutionDir)Libs\bass\x64;$(SolutionDir)Libs\ois\x64 - .exe - true - $(SolutionDir)Build\$(Configuration)\Bin\x64\ - $(Configuration)\ - $(ProjectName) - - - - Use - Level3 - _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;%(PreprocessorDefinitions) - false - $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) - MultiThreadedDebugDLL - false - true - false - stdcpp17 - framework.h - EditAndContinue - false - /Zc:__cplusplus /experimental:external /external:anglebrackets - 4018;4244;4996;%(DisableSpecificWarnings) - true - - - Console - true - $(OutDir)$(TargetName)$(TargetExt) - comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlogd.lib;OIS_d.lib;%(AdditionalDependencies) - false - true - Default - - - - - - - CD $(ProjectDir)Specific\savegame\schema\ -CALL gen.bat - -md "$(SolutionDir)Build\$(Configuration)\Shaders" -xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" -xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" - -xcopy /Y "$(SolutionDir)Libs\bass\x86\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\lua\x86\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\ois\x86\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\zlib\x86\*.dll" "$(TargetDir)" - Generating savegame flatbuffer and copying needed files... - - - - - Use - Level3 - _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;%(PreprocessorDefinitions) - false - $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) - MultiThreadedDebugDLL - false - true - false - stdcpp17 - framework.h - EditAndContinue - false - /Zc:__cplusplus /experimental:external /external:anglebrackets - 4018;4244;4996;%(DisableSpecificWarnings) - true - - - Console - true - $(OutDir)$(TargetName)$(TargetExt) - comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlogd.lib;OIS_d.lib;%(AdditionalDependencies) - false - true - Default - - - - - - - CD $(ProjectDir)Specific\savegame\schema\ -CALL gen.bat - -md "$(SolutionDir)Build\$(Configuration)\Shaders" -xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" -xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" - -xcopy /Y "$(SolutionDir)Libs\bass\x64\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\lua\x64\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\ois\x64\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" - Generating savegame flatbuffer and copying needed files... - - - - - Use - Level3 - _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;SOL_SAFE_FUNCTION_CALLS;%(PreprocessorDefinitions) - false - $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) - MultiThreadedDLL - false - true - false - stdcpp17 - framework.h - ProgramDatabase - Disabled - Default - AnySuitable - true - Speed - true - true - false - true - Fast - true - /Zc:__cplusplus /experimental:external /external:anglebrackets - 4018;4244;4996;%(DisableSpecificWarnings) - true - - - Console - false - $(OutDir)$(TargetName)$(TargetExt) - comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlog.lib;OIS.lib;%(AdditionalDependencies) - false - true - MachineX86 - Default - - - del "$(TargetDir)*.pdb" /q -del "$(TargetDir)*.lib" /q -del "$(TargetDir)*.exp" /q -del "$(TargetDir)OIS_d.dll" /q - - - CD $(ProjectDir)Specific\savegame\schema\ -CALL gen.bat - -md "$(SolutionDir)Build\$(Configuration)\Shaders" -xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" -xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" - -xcopy /Y "$(SolutionDir)Libs\bass\x86\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\lua\x86\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\ois\x86\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\zlib\x86\*.dll" "$(TargetDir)" - - - Generating savegame flatbuffer and copying needed files... - - - - - Use - Level3 - _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;SOL_SAFE_FUNCTION_CALLS;%(PreprocessorDefinitions) - false - $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) - MultiThreadedDLL - false - true - false - stdcpp17 - framework.h - ProgramDatabase - Disabled - Default - AnySuitable - true - Speed - true - true - false - true - Fast - true - /Zc:__cplusplus /experimental:external /external:anglebrackets - 4018;4244;4996;%(DisableSpecificWarnings) - true - - - Console - false - $(OutDir)$(TargetName)$(TargetExt) - comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlog.lib;OIS.lib;%(AdditionalDependencies) - false - true - Default - - - del "$(TargetDir)*.pdb" /q -del "$(TargetDir)*.lib" /q -del "$(TargetDir)*.exp" /q -del "$(TargetDir)OIS_d.dll" /q - - - CD $(ProjectDir)Specific\savegame\schema\ -CALL gen.bat - -md "$(SolutionDir)Build\$(Configuration)\Shaders" -xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" -xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" - -xcopy /Y "$(SolutionDir)Libs\bass\x64\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\lua\x64\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\ois\x64\*.dll" "$(TargetDir)" -xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" - - - Generating savegame flatbuffer and copying needed files... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Use - Use - Use - Use - - - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - false - false - false - true - true - true - true - Text - - - - true - - - true - - - - - true - - - - - - - - - - - Pixel - Pixel - Pixel - Pixel - false - false - false - false - true - true - true - true - Document - 4.0 - 4.0 - 4.0 - 4.0 - - - false - false - false - false - true - true - true - true - Document - 4.0 - 4.0 - 4.0 - 4.0 - Pixel - Pixel - - - - - Pixel - Pixel - - - - - - - - - Document - false - false - false - false - true - true - true - true - Vertex - Vertex - 4.0 - 4.0 - Vertex - Vertex - 4.0 - 4.0 - - - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - PS - PS - Pixel - Pixel - 4.1 - 4.1 - PS - PS - Pixel - Pixel - 4.1 - 4.1 - - - false - false - false - false - true - true - true - true - Document - PS - PS - Pixel - Pixel - 4.1 - 4.1 - PS - PS - Pixel - Pixel - 4.1 - 4.1 - - - false - false - false - false - true - true - true - true - Document - PS - PS - Pixel - Pixel - 4.1 - 4.1 - PS - PS - Pixel - Pixel - 4.1 - 4.1 - - - false - false - false - false - true - true - true - true - Document - PS - PS - Pixel - Pixel - 4.1 - 4.1 - SHADOW_MAP_SIZE=512 - SHADOW_MAP_SIZE=512 - PS - PS - Pixel - Pixel - 4.1 - 4.1 - SHADOW_MAP_SIZE=512 - SHADOW_MAP_SIZE=512 - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - false - false - false - false - true - true - true - true - Document - - - - - false - false - false - false - true - true - true - true - Document - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 15.0 + {15AB0220-541C-4DA1-94EB-ED3C47E4582E} + Win32Proj + TombEngine + 10.0 + TombEngine + + + + Application + true + MultiByte + v143 + + + Application + true + MultiByte + v143 + + + Application + false + MultiByte + v143 + + + Application + false + MultiByte + v143 + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)Build\$(Configuration)\Bin\x86\ + $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x86 + $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(SolutionDir)Libs\srtparser;$(IncludePath) + $(LibraryPath);$(DXSDK_DIR)Lib\x86;$(SolutionDir)Libs\spdlog\x86;$(SolutionDir)Libs\lua\x86;$(SolutionDir)Libs\zlib\x86;$(SolutionDir)Libs\bass\x86;$(SolutionDir)Libs\ois\x86 + .exe + + + $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x64 + $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(SolutionDir)Libs\srtparser;$(IncludePath) + $(LibraryPath);$(DXSDK_DIR)Lib\x64;$(SolutionDir)Libs\spdlog\x64;$(SolutionDir)Libs\lua\x64;$(SolutionDir)Libs\zlib\x64;$(SolutionDir)Libs\bass\x64;$(SolutionDir)Libs\ois\x64 + .exe + true + $(ProjectName) + $(SolutionDir)Build\$(Configuration)\Bin\x64\ + $(Configuration)\ + + + true + $(SolutionDir)Build\$(Configuration)\Bin\x86\ + $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x86 + $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(SolutionDir)Libs\srtparser;$(IncludePath) + $(LibraryPath);$(DXSDK_DIR)Lib\x86;$(SolutionDir)Libs\spdlog\x86;$(SolutionDir)Libs\lua\x86;$(SolutionDir)Libs\zlib\x86;$(SolutionDir)Libs\bass\x86;$(SolutionDir)Libs\ois\x86 + .exe + + + $(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x64 + $(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(SolutionDir)Libs\srtparser;$(IncludePath) + $(LibraryPath);$(DXSDK_DIR)Lib\x64;$(SolutionDir)Libs\spdlog\x64;$(SolutionDir)Libs\lua\x64;$(SolutionDir)Libs\zlib\x64;$(SolutionDir)Libs\bass\x64;$(SolutionDir)Libs\ois\x64 + .exe + true + $(SolutionDir)Build\$(Configuration)\Bin\x64\ + $(Configuration)\ + $(ProjectName) + + + + Use + Level3 + _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;%(PreprocessorDefinitions) + false + $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + false + true + false + stdcpp17 + framework.h + EditAndContinue + false + /Zc:__cplusplus /experimental:external /external:anglebrackets + 4018;4244;4996;%(DisableSpecificWarnings) + true + + + Console + true + $(OutDir)$(TargetName)$(TargetExt) + comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlogd.lib;OIS_d.lib;%(AdditionalDependencies) + false + true + Default + + + + + + + CD $(ProjectDir)Specific\savegame\schema\ +CALL gen.bat + +md "$(SolutionDir)Build\$(Configuration)\Shaders" +xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" +xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" + +xcopy /Y "$(SolutionDir)Libs\bass\x86\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\lua\x86\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\ois\x86\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\zlib\x86\*.dll" "$(TargetDir)" + Generating savegame flatbuffer and copying needed files... + + + + + Use + Level3 + _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;%(PreprocessorDefinitions) + false + $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) + MultiThreadedDebugDLL + false + true + false + stdcpp17 + framework.h + EditAndContinue + false + /Zc:__cplusplus /experimental:external /external:anglebrackets + 4018;4244;4996;%(DisableSpecificWarnings) + true + + + Console + true + $(OutDir)$(TargetName)$(TargetExt) + comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlogd.lib;OIS_d.lib;%(AdditionalDependencies) + false + true + Default + + + + + + + CD $(ProjectDir)Specific\savegame\schema\ +CALL gen.bat + +md "$(SolutionDir)Build\$(Configuration)\Shaders" +xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" +xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" + +xcopy /Y "$(SolutionDir)Libs\bass\x64\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\lua\x64\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\ois\x64\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + Generating savegame flatbuffer and copying needed files... + + + + + Use + Level3 + _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;SOL_SAFE_FUNCTION_CALLS;%(PreprocessorDefinitions) + false + $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) + MultiThreadedDLL + false + true + false + stdcpp17 + framework.h + ProgramDatabase + Disabled + Default + AnySuitable + true + Speed + true + true + false + true + Fast + true + /Zc:__cplusplus /experimental:external /external:anglebrackets + 4018;4244;4996;%(DisableSpecificWarnings) + true + + + Console + false + $(OutDir)$(TargetName)$(TargetExt) + comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlog.lib;OIS.lib;%(AdditionalDependencies) + false + true + MachineX86 + Default + + + del "$(TargetDir)*.pdb" /q +del "$(TargetDir)*.lib" /q +del "$(TargetDir)*.exp" /q +del "$(TargetDir)OIS_d.dll" /q + + + CD $(ProjectDir)Specific\savegame\schema\ +CALL gen.bat + +md "$(SolutionDir)Build\$(Configuration)\Shaders" +xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" +xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" + +xcopy /Y "$(SolutionDir)Libs\bass\x86\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\lua\x86\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\ois\x86\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\zlib\x86\*.dll" "$(TargetDir)" + + + Generating savegame flatbuffer and copying needed files... + + + + + Use + Level3 + _CRT_SECURE_NO_WARNINGS;WIN32;TombEngine_EXPORTS;_WINDOWS;_USRDLL;NOMINMAX;CREATURE_AI_PRIORITY_OPTIMIZATION;SPDLOG_COMPILED_LIB;SOL_SAFE_USERTYPE;SOL_SAFE_FUNCTION_CALLS;%(PreprocessorDefinitions) + false + $(SolutionDir)TombEngine;%(AdditionalIncludeDirectories) + MultiThreadedDLL + false + true + false + stdcpp17 + framework.h + ProgramDatabase + Disabled + Default + AnySuitable + true + Speed + true + true + false + true + Fast + true + /Zc:__cplusplus /experimental:external /external:anglebrackets + 4018;4244;4996;%(DisableSpecificWarnings) + true + + + Console + false + $(OutDir)$(TargetName)$(TargetExt) + comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;version.lib;zlib.lib;spdlog.lib;OIS.lib;%(AdditionalDependencies) + false + true + Default + + + del "$(TargetDir)*.pdb" /q +del "$(TargetDir)*.lib" /q +del "$(TargetDir)*.exp" /q +del "$(TargetDir)OIS_d.dll" /q + + + CD $(ProjectDir)Specific\savegame\schema\ +CALL gen.bat + +md "$(SolutionDir)Build\$(Configuration)\Shaders" +xcopy /Y /D "$(ProjectDir)Shaders\*.*" "$(SolutionDir)Build\$(Configuration)\Shaders\" +xcopy /Y /D "$(ProjectDir)Shaders\HUD\*.hlsl" "$(SolutionDir)Build\$(Configuration)\Shaders\HUD\" + +xcopy /Y "$(SolutionDir)Libs\bass\x64\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\lua\x64\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\ois\x64\*.dll" "$(TargetDir)" +xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + + + Generating savegame flatbuffer and copying needed files... + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use + Use + Use + Use + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + false + false + false + true + true + true + true + Text + + + + true + + + true + + + + + true + + + + + + + + + + + Pixel + Pixel + Pixel + Pixel + false + false + false + false + true + true + true + true + Document + 4.0 + 4.0 + 4.0 + 4.0 + + + false + false + false + false + true + true + true + true + Document + 4.0 + 4.0 + 4.0 + 4.0 + Pixel + Pixel + + + + + Pixel + Pixel + + + + + + + + + Document + false + false + false + false + true + true + true + true + Vertex + Vertex + 4.0 + 4.0 + Vertex + Vertex + 4.0 + 4.0 + + + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + PS + PS + Pixel + Pixel + 4.1 + 4.1 + PS + PS + Pixel + Pixel + 4.1 + 4.1 + + + false + false + false + false + true + true + true + true + Document + PS + PS + Pixel + Pixel + 4.1 + 4.1 + PS + PS + Pixel + Pixel + 4.1 + 4.1 + + + false + false + false + false + true + true + true + true + Document + PS + PS + Pixel + Pixel + 4.1 + 4.1 + PS + PS + Pixel + Pixel + 4.1 + 4.1 + + + false + false + false + false + true + true + true + true + Document + PS + PS + Pixel + Pixel + 4.1 + 4.1 + SHADOW_MAP_SIZE=512 + SHADOW_MAP_SIZE=512 + PS + PS + Pixel + Pixel + 4.1 + 4.1 + SHADOW_MAP_SIZE=512 + SHADOW_MAP_SIZE=512 + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + false + false + false + false + true + true + true + true + Document + + + + + false + false + false + false + true + true + true + true + Document + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file