mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 07:47:57 +03:00
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 <kubadd475@gmail.com> Co-authored-by: Sezz <sezzary@outlook.com>
This commit is contained in:
parent
35304ce84a
commit
95ff7091a9
23 changed files with 2511 additions and 1603 deletions
|
@ -4,6 +4,7 @@ Version 1.1.0
|
||||||
* Fix enemies shooting Lara through static meshes and moveables.
|
* Fix enemies shooting Lara through static meshes and moveables.
|
||||||
* Fix skeletons and mummies not affected by explosive weapons.
|
* Fix skeletons and mummies not affected by explosive weapons.
|
||||||
* Fix crash on loading if static meshes with IDs above maximum are present.
|
* 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 sprint value going below zero.
|
||||||
* Fix fog bulb density formula.
|
* Fix fog bulb density formula.
|
||||||
* Fix electricity effect crashing 64-bit version of the engine.
|
* 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 default ambience overlapping current one when loading a savegame.
|
||||||
* Fix doppelganger being limited to be in a single room.
|
* Fix doppelganger being limited to be in a single room.
|
||||||
* Add multiple doppelgangers by using the same OCB for the origin nullmesh and doppelganger.
|
* 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.
|
* Pause all sounds when entering inventory or pause menu.
|
||||||
* Improve deflection against slopes.
|
* Improve deflection against slopes.
|
||||||
* Move and rotate Lara together with dynamic bridge objects.
|
* Move and rotate Lara together with dynamic bridge objects.
|
||||||
|
@ -19,6 +22,12 @@ Version 1.1.0
|
||||||
* Add TR1 skateboard kid.
|
* Add TR1 skateboard kid.
|
||||||
* Add TR1 Kold.
|
* 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
|
Version 1.0.9
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
Binary file not shown.
657
Libs/srtparser/srtparser.h
Normal file
657
Libs/srtparser/srtparser.h
Normal file
|
@ -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 <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
//function for splitting sentences based on supplied delimiter
|
||||||
|
inline std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &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<std::string> _speaker; //list of speakers in a single subtitle
|
||||||
|
int _nonDialogueCount; //count of non spoken words in a subtitle
|
||||||
|
std::vector<std::string> _nonDialogue; //list of non dialogue words, e.g. (applause)
|
||||||
|
int _wordCount; //number of words in _justDialogue
|
||||||
|
std::vector<std::string> _word; //list of words in dialogue
|
||||||
|
std::vector<long int> _wordStartTime; //start time of each word in dialogue
|
||||||
|
std::vector<long int> _wordEndTime; //end time of each word in dialogue
|
||||||
|
std::vector<long int> _wordDuration; //actual duration of each word without silence
|
||||||
|
int _styleTagCount; //count of style tags in a single subtitle
|
||||||
|
std::vector<std::string> _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<std::string> getIndividualWords(); //return string vector of individual words
|
||||||
|
std::string getWordByIndex(int index); //return word stored at 'index'
|
||||||
|
std::vector<long int> getWordStartTimes(); //return long int vector of start time of individual words
|
||||||
|
std::vector<long int> 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<std::string> getSpeakerNames(); //return string vector of speaker names
|
||||||
|
std::vector<std::string> getNonDialogueWords(); //return string vector of non dialogue words
|
||||||
|
std::vector<std::string> 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<long int> wordStartTime, std::vector<long int> wordEndTime, std::vector<long int> 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<std::string> speaker = std::vector<std::string>(),
|
||||||
|
std::vector<std::string> nonDialogue = std::vector<std::string>(),
|
||||||
|
std::vector<std::string> styleTags = std::vector<std::string>(),
|
||||||
|
std::vector<std::string> word = std::vector<std::string>()); //default constructor
|
||||||
|
~SubtitleItem(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SubtitleParser
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
std::vector<SubtitleItem*> _subtitles; //stores subtitles
|
||||||
|
std::string _fileName; //supplied filename
|
||||||
|
virtual void parse(std::string fileName) = 0;
|
||||||
|
public:
|
||||||
|
virtual std::vector<SubtitleItem*> 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<SubtitleItem*> 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<std::string> 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<std::string> speaker, std::vector<std::string> nonDialogue,
|
||||||
|
std::vector<std::string> styleTags, std::vector<std::string> 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<std::string> 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<long int> wordStartTime, std::vector<long int> wordEndTime, std::vector<long int> 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<std::string> getStyleTags();
|
||||||
|
* int getStyleTagCount() const;
|
||||||
|
* std::vector<std::string> _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<std::string> getNonDialogueWords();
|
||||||
|
* int getNonDialogueCount() const;
|
||||||
|
* std::vector<std::string> _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<std::string>(_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<std::string> SubtitleItem::getSpeakerNames()
|
||||||
|
{
|
||||||
|
return _speaker;
|
||||||
|
}
|
||||||
|
inline std::vector<std::string> SubtitleItem::getNonDialogueWords()
|
||||||
|
{
|
||||||
|
return _nonDialogue;
|
||||||
|
}
|
||||||
|
inline std::vector<std::string> SubtitleItem::getIndividualWords()
|
||||||
|
{
|
||||||
|
return _word;
|
||||||
|
}
|
||||||
|
inline std::string SubtitleItem::getWordByIndex(int index)
|
||||||
|
{
|
||||||
|
return _word[index];
|
||||||
|
}
|
||||||
|
inline std::vector<long int> SubtitleItem::getWordStartTimes()
|
||||||
|
{
|
||||||
|
return _wordStartTime;
|
||||||
|
}
|
||||||
|
inline std::vector<long int> 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<std::string> 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
|
|
@ -90,6 +90,7 @@ local strings =
|
||||||
rocket_launcher_ammo = { "Rocket Launcher Ammo" },
|
rocket_launcher_ammo = { "Rocket Launcher Ammo" },
|
||||||
rocket_launcher = { "Rocket Launcher" },
|
rocket_launcher = { "Rocket Launcher" },
|
||||||
rumble = { "Rumble" },
|
rumble = { "Rumble" },
|
||||||
|
subtitles = { "Subtitles" },
|
||||||
save_game = { "Save Game" },
|
save_game = { "Save Game" },
|
||||||
savegame_timestamp = { "%02d Days %02d:%02d:%02d" },
|
savegame_timestamp = { "%02d Days %02d:%02d:%02d" },
|
||||||
screen_resolution = { "Screen Resolution" },
|
screen_resolution = { "Screen Resolution" },
|
||||||
|
|
|
@ -716,7 +716,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
item->HitPoints = -1;
|
item->HitPoints = -1;
|
||||||
|
|
||||||
if (lara->Control.Count.Death == 0)
|
if (lara->Control.Count.Death == 0)
|
||||||
StopSoundTracks();
|
StopSoundTracks(true);
|
||||||
|
|
||||||
lara->Control.Count.Death++;
|
lara->Control.Count.Death++;
|
||||||
if ((item->Flags & IFLAG_INVISIBLE))
|
if ((item->Flags & IFLAG_INVISIBLE))
|
||||||
|
|
|
@ -726,6 +726,7 @@ namespace TEN::Gui
|
||||||
Reverb,
|
Reverb,
|
||||||
MusicVolume,
|
MusicVolume,
|
||||||
SfxVolume,
|
SfxVolume,
|
||||||
|
Subtitles,
|
||||||
AutoTarget,
|
AutoTarget,
|
||||||
ToggleRumble,
|
ToggleRumble,
|
||||||
ThumbstickCameraControl,
|
ThumbstickCameraControl,
|
||||||
|
@ -733,7 +734,7 @@ namespace TEN::Gui
|
||||||
Cancel
|
Cancel
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int numOtherSettingsOptions = 7;
|
static const int numOtherSettingsOptions = 8;
|
||||||
|
|
||||||
OptionCount = numOtherSettingsOptions;
|
OptionCount = numOtherSettingsOptions;
|
||||||
|
|
||||||
|
@ -772,6 +773,11 @@ namespace TEN::Gui
|
||||||
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
CurrentSettings.Configuration.EnableThumbstickCameraControl = !CurrentSettings.Configuration.EnableThumbstickCameraControl;
|
CurrentSettings.Configuration.EnableThumbstickCameraControl = !CurrentSettings.Configuration.EnableThumbstickCameraControl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OtherSettingsOption::Subtitles:
|
||||||
|
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
|
||||||
|
CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -806,8 +806,10 @@ bool SaveGame::Save(int slot)
|
||||||
// Soundtrack playheads
|
// Soundtrack playheads
|
||||||
auto bgmTrackData = GetSoundTrackNameAndPosition(SoundTrackType::BGM);
|
auto bgmTrackData = GetSoundTrackNameAndPosition(SoundTrackType::BGM);
|
||||||
auto oneshotTrackData = GetSoundTrackNameAndPosition(SoundTrackType::OneShot);
|
auto oneshotTrackData = GetSoundTrackNameAndPosition(SoundTrackType::OneShot);
|
||||||
|
auto voiceTrackData = GetSoundTrackNameAndPosition(SoundTrackType::Voice);
|
||||||
auto bgmTrackOffset = fbb.CreateString(bgmTrackData.first);
|
auto bgmTrackOffset = fbb.CreateString(bgmTrackData.first);
|
||||||
auto oneshotTrackOffset = fbb.CreateString(oneshotTrackData.first);
|
auto oneshotTrackOffset = fbb.CreateString(oneshotTrackData.first);
|
||||||
|
auto voiceTrackOffset = fbb.CreateString(voiceTrackData.first);
|
||||||
|
|
||||||
// Legacy soundtrack map
|
// Legacy soundtrack map
|
||||||
std::vector<int> soundTrackMap;
|
std::vector<int> soundTrackMap;
|
||||||
|
@ -1272,6 +1274,8 @@ bool SaveGame::Save(int slot)
|
||||||
sgb.add_ambient_position(bgmTrackData.second);
|
sgb.add_ambient_position(bgmTrackData.second);
|
||||||
sgb.add_oneshot_track(oneshotTrackOffset);
|
sgb.add_oneshot_track(oneshotTrackOffset);
|
||||||
sgb.add_oneshot_position(oneshotTrackData.second);
|
sgb.add_oneshot_position(oneshotTrackData.second);
|
||||||
|
sgb.add_voice_track(voiceTrackOffset);
|
||||||
|
sgb.add_voice_position(voiceTrackData.second);
|
||||||
sgb.add_cd_flags(soundtrackMapOffset);
|
sgb.add_cd_flags(soundtrackMapOffset);
|
||||||
sgb.add_action_queue(actionQueueOffset);
|
sgb.add_action_queue(actionQueueOffset);
|
||||||
sgb.add_flip_maps(flipMapsOffset);
|
sgb.add_flip_maps(flipMapsOffset);
|
||||||
|
@ -1456,6 +1460,7 @@ bool SaveGame::Load(int slot)
|
||||||
// Restore soundtracks
|
// Restore soundtracks
|
||||||
PlaySoundTrack(s->ambient_track()->str(), SoundTrackType::BGM, s->ambient_position());
|
PlaySoundTrack(s->ambient_track()->str(), SoundTrackType::BGM, s->ambient_position());
|
||||||
PlaySoundTrack(s->oneshot_track()->str(), SoundTrackType::OneShot, s->oneshot_position());
|
PlaySoundTrack(s->oneshot_track()->str(), SoundTrackType::OneShot, s->oneshot_position());
|
||||||
|
PlaySoundTrack(s->voice_track()->str(), SoundTrackType::Voice, s->voice_position());
|
||||||
|
|
||||||
// Legacy soundtrack map
|
// Legacy soundtrack map
|
||||||
for (int i = 0; i < s->cd_flags()->size(); i++)
|
for (int i = 0; i < s->cd_flags()->size(); i++)
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace TEN::Renderer
|
||||||
// Vertical menu positioning templates
|
// Vertical menu positioning templates
|
||||||
constexpr auto MenuVerticalTop = 11;
|
constexpr auto MenuVerticalTop = 11;
|
||||||
constexpr auto MenuVerticalDisplaySettings = 200;
|
constexpr auto MenuVerticalDisplaySettings = 200;
|
||||||
constexpr auto MenuVerticalOtherSettings = 150;
|
constexpr auto MenuVerticalOtherSettings = 130;
|
||||||
constexpr auto MenuVerticalBottomCenter = 400;
|
constexpr auto MenuVerticalBottomCenter = 400;
|
||||||
constexpr auto MenuVerticalStatisticsTitle = 150;
|
constexpr auto MenuVerticalStatisticsTitle = 150;
|
||||||
constexpr auto MenuVerticalOptionsTitle = 350;
|
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);
|
DrawBar(g_Gui.GetCurrentSettings().Configuration.SfxVolume / 100.0f, *g_SFXVolumeBar, ID_SFX_BAR_TEXTURE, 0, false);
|
||||||
GetNextBlockPosition(&y);
|
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
|
// Auto targeting
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_TARGET), PRINTSTRING_COLOR_ORANGE, 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 == 3));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.AutoTarget), PRINTSTRING_COLOR_WHITE, SF(title_option == 4));
|
||||||
GetNextLinePosition(&y);
|
GetNextLinePosition(&y);
|
||||||
|
|
||||||
// Vibration
|
// Vibration
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, 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 == 4));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(title_option == 5));
|
||||||
GetNextLinePosition(&y);
|
GetNextLinePosition(&y);
|
||||||
|
|
||||||
// Thumbstick camera
|
// Thumbstick camera
|
||||||
AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_THUMBSTICK_CAMERA), PRINTSTRING_COLOR_ORANGE, 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 == 5));
|
AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableThumbstickCameraControl), PRINTSTRING_COLOR_WHITE, SF(title_option == 6));
|
||||||
GetNextBlockPosition(&y);
|
GetNextBlockPosition(&y);
|
||||||
|
|
||||||
|
|
||||||
// Apply
|
// 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);
|
GetNextLinePosition(&y);
|
||||||
|
|
||||||
// Cancel
|
// 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;
|
break;
|
||||||
|
|
||||||
case Menu::Controls:
|
case Menu::Controls:
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
#define STRING_AUTO_TARGET "auto_target"
|
#define STRING_AUTO_TARGET "auto_target"
|
||||||
#define STRING_RUMBLE "rumble"
|
#define STRING_RUMBLE "rumble"
|
||||||
#define STRING_THUMBSTICK_CAMERA "thumbstick_camera"
|
#define STRING_THUMBSTICK_CAMERA "thumbstick_camera"
|
||||||
|
#define STRING_SUBTITLES "subtitles"
|
||||||
#define STRING_CONTROLS_MOVE_FORWARD "controls_move_forward"
|
#define STRING_CONTROLS_MOVE_FORWARD "controls_move_forward"
|
||||||
#define STRING_CONTROLS_MOVE_BACKWARD "controls_move_backward"
|
#define STRING_CONTROLS_MOVE_BACKWARD "controls_move_backward"
|
||||||
#define STRING_CONTROLS_MOVE_LEFT "controls_move_left"
|
#define STRING_CONTROLS_MOVE_LEFT "controls_move_left"
|
||||||
|
|
|
@ -196,8 +196,11 @@ static constexpr char ScriptReserved_SetAmbientTrack[] = "SetAmbientTrack";
|
||||||
static constexpr char ScriptReserved_PlayAudioTrack[] = "PlayAudioTrack";
|
static constexpr char ScriptReserved_PlayAudioTrack[] = "PlayAudioTrack";
|
||||||
static constexpr char ScriptReserved_StopAudioTrack[] = "StopAudioTrack";
|
static constexpr char ScriptReserved_StopAudioTrack[] = "StopAudioTrack";
|
||||||
static constexpr char ScriptReserved_StopAudioTracks[] = "StopAudioTracks";
|
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_PlaySound[] = "PlaySound";
|
||||||
static constexpr char ScriptReserved_IsSoundPlaying[] = "IsSoundPlaying";
|
static constexpr char ScriptReserved_IsSoundPlaying[] = "IsSoundPlaying";
|
||||||
|
static constexpr char ScriptReserved_IsAudioTrackPlaying[] = "IsAudioTrackPlaying";
|
||||||
static constexpr char ScriptReserved_GiveInvItem[] = "GiveItem";
|
static constexpr char ScriptReserved_GiveInvItem[] = "GiveItem";
|
||||||
static constexpr char ScriptReserved_TakeInvItem[] = "TakeItem";
|
static constexpr char ScriptReserved_TakeInvItem[] = "TakeItem";
|
||||||
static constexpr char ScriptReserved_GetInvItemCount[] = "GetItemCount";
|
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_EffectID[] = "EffectID";
|
||||||
static constexpr char ScriptReserved_ActionID[] = "ActionID";
|
static constexpr char ScriptReserved_ActionID[] = "ActionID";
|
||||||
static constexpr char ScriptReserved_CameraType[] = "CameraType";
|
static constexpr char ScriptReserved_CameraType[] = "CameraType";
|
||||||
|
static constexpr char ScriptReserved_SoundTrackType[] = "SoundTrackType";
|
||||||
static constexpr char ScriptReserved_LogLevel[] = "LogLevel";
|
static constexpr char ScriptReserved_LogLevel[] = "LogLevel";
|
||||||
static constexpr char ScriptReserved_RoomFlagID[] = "RoomFlagID";
|
static constexpr char ScriptReserved_RoomFlagID[] = "RoomFlagID";
|
||||||
static constexpr char ScriptReserved_RoomReverb[] = "RoomReverb";
|
static constexpr char ScriptReserved_RoomReverb[] = "RoomReverb";
|
||||||
|
|
|
@ -27,10 +27,10 @@ The following constants are inside CameraType.
|
||||||
|
|
||||||
static const std::unordered_map<std::string, CameraType> CAMERA_TYPE
|
static const std::unordered_map<std::string, CameraType> CAMERA_TYPE
|
||||||
{
|
{
|
||||||
{ "Chase", CameraType::Chase },
|
{ "CHASE", CameraType::Chase },
|
||||||
{ "Fixed", CameraType::Fixed },
|
{ "FIXED", CameraType::Fixed },
|
||||||
{ "Look", CameraType::Look },
|
{ "LOOK", CameraType::Look },
|
||||||
{ "Combat", CameraType::Combat },
|
{ "COMBAT", CameraType::Combat },
|
||||||
{ "Heavy", CameraType::Heavy },
|
{ "HEAVY", CameraType::Heavy },
|
||||||
{ "Object", CameraType::Object }
|
{ "OBJECT", CameraType::Object }
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "Scripting/Internal/TEN/Misc/ActionIDs.h"
|
#include "Scripting/Internal/TEN/Misc/ActionIDs.h"
|
||||||
#include "Scripting/Internal/TEN/Misc/CameraTypes.h"
|
#include "Scripting/Internal/TEN/Misc/CameraTypes.h"
|
||||||
#include "Scripting/Internal/TEN/Misc/LevelLog.h"
|
#include "Scripting/Internal/TEN/Misc/LevelLog.h"
|
||||||
|
#include "Scripting/Internal/TEN/Misc/SoundTrackTypes.h"
|
||||||
#include "Scripting/Internal/TEN/Vec3/Vec3.h"
|
#include "Scripting/Internal/TEN/Vec3/Vec3.h"
|
||||||
#include "Sound/sound.h"
|
#include "Sound/sound.h"
|
||||||
#include "Specific/clock.h"
|
#include "Specific/clock.h"
|
||||||
|
@ -144,11 +145,11 @@ namespace Misc
|
||||||
/// Play an audio track
|
/// Play an audio track
|
||||||
//@function PlayAudioTrack
|
//@function PlayAudioTrack
|
||||||
//@tparam string name of track (without file extension) to play
|
//@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)
|
//@tparam Misc.SoundTrackType type of the audio track to play
|
||||||
static void PlayAudioTrack(const std::string& trackName, TypeOrNil<bool> looped)
|
static void PlayAudioTrack(const std::string& trackName, TypeOrNil<SoundTrackType> mode)
|
||||||
{
|
{
|
||||||
auto mode = USE_IF_HAVE(bool, looped, false) ? SoundTrackType::BGM : SoundTrackType::OneShot;
|
auto playMode = USE_IF_HAVE(SoundTrackType, mode, SoundTrackType::OneShot);
|
||||||
PlaySoundTrack(trackName, mode);
|
PlaySoundTrack(trackName, playMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
///Set and play an ambient track
|
///Set and play an ambient track
|
||||||
|
@ -168,11 +169,40 @@ namespace Misc
|
||||||
|
|
||||||
///Stop audio track that is currently playing
|
///Stop audio track that is currently playing
|
||||||
//@function StopAudioTrack
|
//@function StopAudioTrack
|
||||||
//@tparam bool looped if set, stop looped audio track, if not, stop one-shot audio track
|
//@tparam Misc.SoundTrackType type of the audio track
|
||||||
static void StopAudioTrack(TypeOrNil<bool> looped)
|
static void StopAudioTrack(TypeOrNil<SoundTrackType> mode)
|
||||||
{
|
{
|
||||||
auto mode = USE_IF_HAVE(bool, looped, false) ? SoundTrackType::BGM : SoundTrackType::OneShot;
|
auto playMode = USE_IF_HAVE(SoundTrackType, mode, SoundTrackType::OneShot);
|
||||||
StopSoundTrack(mode, SOUND_XFADETIME_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<SoundTrackType> 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<std::string> GetCurrentVoiceTrackSubtitle()
|
||||||
|
{
|
||||||
|
auto& result = GetCurrentSubtitle();
|
||||||
|
|
||||||
|
if (result.has_value())
|
||||||
|
{
|
||||||
|
return result.value();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return sol::nil;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Play sound effect
|
/// 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.
|
//@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)
|
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)
|
static bool CheckInput(int actionIndex)
|
||||||
|
@ -382,9 +420,12 @@ namespace Misc
|
||||||
tableMisc.set_function(ScriptReserved_PlayAudioTrack, &PlayAudioTrack);
|
tableMisc.set_function(ScriptReserved_PlayAudioTrack, &PlayAudioTrack);
|
||||||
tableMisc.set_function(ScriptReserved_StopAudioTrack, &StopAudioTrack);
|
tableMisc.set_function(ScriptReserved_StopAudioTrack, &StopAudioTrack);
|
||||||
tableMisc.set_function(ScriptReserved_StopAudioTracks, &StopAudioTracks);
|
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_PlaySound, &PlaySoundEffect);
|
||||||
tableMisc.set_function(ScriptReserved_IsSoundPlaying, &IsSoundPlaying);
|
tableMisc.set_function(ScriptReserved_IsSoundPlaying, &IsSoundPlaying);
|
||||||
|
tableMisc.set_function(ScriptReserved_IsAudioTrackPlaying, &IsAudioTrackPlaying);
|
||||||
|
|
||||||
/// Check if particular action key is held
|
/// Check if particular action key is held
|
||||||
//@function KeyIsHeld
|
//@function KeyIsHeld
|
||||||
|
@ -421,6 +462,7 @@ namespace Misc
|
||||||
LuaHandler handler{ state };
|
LuaHandler handler{ state };
|
||||||
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_ActionID, ACTION_IDS);
|
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_ActionID, ACTION_IDS);
|
||||||
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_CameraType, CAMERA_TYPE);
|
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_CameraType, CAMERA_TYPE);
|
||||||
|
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_SoundTrackType, SOUNDTRACK_TYPE);
|
||||||
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_LogLevel, LOG_LEVEL);
|
handler.MakeReadOnlyTable(tableMisc, ScriptReserved_LogLevel, LOG_LEVEL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
TombEngine/Scripting/Internal/TEN/Misc/SoundTrackTypes.h
Normal file
30
TombEngine/Scripting/Internal/TEN/Misc/SoundTrackTypes.h
Normal file
|
@ -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<std::string, SoundTrackType> SOUNDTRACK_TYPE
|
||||||
|
{
|
||||||
|
{ "ONESHOT", SoundTrackType::OneShot },
|
||||||
|
{ "LOOPED", SoundTrackType::BGM },
|
||||||
|
{ "VOICE", SoundTrackType::Voice }
|
||||||
|
};
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include <srtparser.h>
|
||||||
|
|
||||||
#include "Game/camera.h"
|
#include "Game/camera.h"
|
||||||
#include "Game/collision/collide_room.h"
|
#include "Game/collision/collide_room.h"
|
||||||
|
@ -11,6 +12,7 @@
|
||||||
#include "Game/Setup.h"
|
#include "Game/Setup.h"
|
||||||
#include "Specific/configuration.h"
|
#include "Specific/configuration.h"
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
|
#include "Specific/trutils.h"
|
||||||
#include "Specific/winmain.h"
|
#include "Specific/winmain.h"
|
||||||
|
|
||||||
HSAMPLE BASS_SamplePointer[SOUND_MAX_SAMPLES];
|
HSAMPLE BASS_SamplePointer[SOUND_MAX_SAMPLES];
|
||||||
|
@ -35,7 +37,9 @@ static std::string FullAudioDirectory;
|
||||||
|
|
||||||
std::map<std::string, int> SoundTrackMap;
|
std::map<std::string, int> SoundTrackMap;
|
||||||
std::unordered_map<int, SoundTrackInfo> SoundTracks;
|
std::unordered_map<int, SoundTrackInfo> SoundTracks;
|
||||||
int SecretSoundIndex = 5;
|
std::vector<SubtitleItem*> Subtitles;
|
||||||
|
|
||||||
|
static int SecretSoundIndex = 5;
|
||||||
constexpr int LegacyLoopingTrackMin = 98;
|
constexpr int LegacyLoopingTrackMin = 98;
|
||||||
constexpr int LegacyLoopingTrackMax = 111;
|
constexpr int LegacyLoopingTrackMax = 111;
|
||||||
|
|
||||||
|
@ -231,17 +235,17 @@ bool SoundEffect(int effectID, Pose* position, SoundEnvironment condition, float
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SoundPlayMode::Wait:
|
case SoundPlayMode::Wait:
|
||||||
if (existingChannel != -1) // Don't play until stopped
|
if (existingChannel != SOUND_NO_CHANNEL) // Don't play until stopped
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SoundPlayMode::Restart:
|
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);
|
Sound_FreeSlot(existingChannel, SOUND_XFADETIME_CUTSOUND);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SoundPlayMode::Looped:
|
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_UpdateEffectPosition(existingChannel, position);
|
||||||
Sound_UpdateEffectAttributes(existingChannel, pitch, volume);
|
Sound_UpdateEffectAttributes(existingChannel, pitch, volume);
|
||||||
|
@ -261,7 +265,7 @@ bool SoundEffect(int effectID, Pose* position, SoundEnvironment condition, float
|
||||||
|
|
||||||
// Get free channel to play sample
|
// Get free channel to play sample
|
||||||
int freeSlot = Sound_GetFreeSlot();
|
int freeSlot = Sound_GetFreeSlot();
|
||||||
if (freeSlot == -1)
|
if (freeSlot == SOUND_NO_CHANNEL)
|
||||||
{
|
{
|
||||||
TENLog("No free channel slot available!", LogLevel::Warning);
|
TENLog("No free channel slot available!", LogLevel::Warning);
|
||||||
return false;
|
return false;
|
||||||
|
@ -312,17 +316,18 @@ void PauseAllSounds(SoundPauseMode mode)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& slot : SoundSlot)
|
for (const auto& slot : SoundSlot)
|
||||||
{
|
{
|
||||||
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PLAYING))
|
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PLAYING))
|
||||||
BASS_ChannelPause(slot.Channel);
|
BASS_ChannelPause(slot.Channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == SoundPauseMode::Inventory)
|
for (int i = 0; i < (int)SoundTrackType::Count; i++)
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto& slot : SoundtrackSlot)
|
|
||||||
{
|
{
|
||||||
|
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))
|
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PLAYING))
|
||||||
BASS_ChannelPause(slot.Channel);
|
BASS_ChannelPause(slot.Channel);
|
||||||
}
|
}
|
||||||
|
@ -333,7 +338,7 @@ void ResumeAllSounds(SoundPauseMode mode)
|
||||||
if (mode == SoundPauseMode::Global)
|
if (mode == SoundPauseMode::Global)
|
||||||
BASS_Start();
|
BASS_Start();
|
||||||
|
|
||||||
for (auto& slot : SoundtrackSlot)
|
for (const auto& slot : SoundtrackSlot)
|
||||||
{
|
{
|
||||||
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PAUSED))
|
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PAUSED))
|
||||||
BASS_ChannelStart(slot.Channel);
|
BASS_ChannelStart(slot.Channel);
|
||||||
|
@ -342,7 +347,7 @@ void ResumeAllSounds(SoundPauseMode mode)
|
||||||
if (mode == SoundPauseMode::Global)
|
if (mode == SoundPauseMode::Global)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto& slot : SoundSlot)
|
for (const auto& slot : SoundSlot)
|
||||||
{
|
{
|
||||||
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PAUSED))
|
if ((slot.Channel != NULL) && (BASS_ChannelIsActive(slot.Channel) == BASS_ACTIVE_PAUSED))
|
||||||
BASS_ChannelStart(slot.Channel);
|
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<std::string> 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)
|
if (!g_Configuration.EnableSound)
|
||||||
return;
|
return;
|
||||||
|
@ -443,6 +486,7 @@ void PlaySoundTrack(std::string track, SoundTrackType mode, QWORD position)
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case SoundTrackType::OneShot:
|
case SoundTrackType::OneShot:
|
||||||
|
case SoundTrackType::Voice:
|
||||||
crossfadeTime = SOUND_XFADETIME_ONESHOT;
|
crossfadeTime = SOUND_XFADETIME_ONESHOT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -518,9 +562,34 @@ void PlaySoundTrack(std::string track, SoundTrackType mode, QWORD position)
|
||||||
|
|
||||||
SoundtrackSlot[(int)mode].Channel = stream;
|
SoundtrackSlot[(int)mode].Channel = stream;
|
||||||
SoundtrackSlot[(int)mode].Track = track;
|
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.
|
// If track name was included in script, play it as registered track and take mask into account.
|
||||||
// Otherwise, play it once without registering anywhere.
|
// Otherwise, play it once without registering anywhere.
|
||||||
|
@ -559,10 +628,16 @@ void PlaySoundTrack(int index, short mask)
|
||||||
PlaySoundTrack(SoundTracks[index].Name, SoundTracks[index].Mode);
|
PlaySoundTrack(SoundTracks[index].Name, SoundTracks[index].Mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopSoundTracks()
|
void StopSoundTracks(bool excludeAmbience)
|
||||||
{
|
{
|
||||||
StopSoundTrack(SoundTrackType::OneShot, SOUND_XFADETIME_ONESHOT);
|
for (int i = 0; i < (int)SoundTrackType::Count; i++)
|
||||||
StopSoundTrack(SoundTrackType::BGM, SOUND_XFADETIME_ONESHOT);
|
{
|
||||||
|
auto mode = (SoundTrackType)i;
|
||||||
|
if (excludeAmbience && mode == SoundTrackType::BGM)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
StopSoundTrack((SoundTrackType)i, SOUND_XFADETIME_ONESHOT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopSoundTrack(SoundTrackType mode, int fadeoutTime)
|
void StopSoundTrack(SoundTrackType mode, int fadeoutTime)
|
||||||
|
@ -581,7 +656,6 @@ void ClearSoundTrackMasks()
|
||||||
|
|
||||||
// Returns specified soundtrack type's stem name and playhead position.
|
// 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.
|
// To be used with savegames. To restore soundtrack, use PlaySoundtrack function with playhead position passed as 3rd argument.
|
||||||
|
|
||||||
std::pair<std::string, QWORD> GetSoundTrackNameAndPosition(SoundTrackType type)
|
std::pair<std::string, QWORD> GetSoundTrackNameAndPosition(SoundTrackType type)
|
||||||
{
|
{
|
||||||
auto track = SoundtrackSlot[(int)type];
|
auto track = SoundtrackSlot[(int)type];
|
||||||
|
@ -610,7 +684,6 @@ void Sound_FreeSample(int index)
|
||||||
|
|
||||||
// Get first free (non-playing) sound slot.
|
// 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
|
// If no free slots found, now try to hijack slot which is as far from listener as possible
|
||||||
|
|
||||||
int Sound_GetFreeSlot()
|
int Sound_GetFreeSlot()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
|
for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
|
||||||
|
@ -622,7 +695,7 @@ int Sound_GetFreeSlot()
|
||||||
// No free slots, hijack now.
|
// No free slots, hijack now.
|
||||||
|
|
||||||
float minDistance = 0;
|
float minDistance = 0;
|
||||||
int farSlot = -1;
|
int farSlot = SOUND_NO_CHANNEL;
|
||||||
|
|
||||||
for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
|
for (int i = 0; i < SOUND_MAX_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
|
@ -639,6 +712,25 @@ int Sound_GetFreeSlot()
|
||||||
return farSlot;
|
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.
|
// 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
|
// 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.
|
// 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].EffectID == effectID)
|
||||||
{
|
{
|
||||||
if (SoundSlot[i].Channel == NULL) // Free channel
|
// Free channel.
|
||||||
|
if (SoundSlot[i].Channel == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (BASS_ChannelIsActive(SoundSlot[i].Channel))
|
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.
|
// 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)
|
if (Vector3::Distance(origin, SoundSlot[i].Origin) < SOUND_MAXVOL_RADIUS)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
SoundSlot[i].Channel = NULL; // WTF, let's clean this up
|
SoundSlot[i].Channel = NULL; // WTF, let's clean this up
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSoundEffectPlaying(int effectID)
|
return SOUND_NO_CHANNEL;
|
||||||
{
|
|
||||||
int channelIndex = Sound_EffectIsPlaying(effectID, nullptr);
|
|
||||||
|
|
||||||
if (channelIndex == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (SoundSlot[channelIndex].EffectID == effectID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the distance to the source.
|
// Gets the distance to the source.
|
||||||
|
|
||||||
float Sound_DistanceToListener(Pose *position)
|
float Sound_DistanceToListener(Pose *position)
|
||||||
{
|
{
|
||||||
// Assume sound is 2D menu sound.
|
// Assume sound is 2D menu sound.
|
||||||
|
@ -700,7 +785,6 @@ float Sound_DistanceToListener(Vector3 position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate attenuated volume.
|
// Calculate attenuated volume.
|
||||||
|
|
||||||
float Sound_Attenuate(float gain, float distance, float radius)
|
float Sound_Attenuate(float gain, float distance, float radius)
|
||||||
{
|
{
|
||||||
float result = gain * (1.0f - (distance / 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.
|
// Stop and free desired sound slot.
|
||||||
|
|
||||||
void Sound_FreeSlot(int index, unsigned int fadeout)
|
void Sound_FreeSlot(int index, unsigned int fadeout)
|
||||||
{
|
{
|
||||||
if (index >= SOUND_MAX_CHANNELS || index < 0)
|
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].Channel = NULL;
|
||||||
SoundSlot[index].State = SoundState::Idle;
|
SoundSlot[index].State = SoundState::Idle;
|
||||||
SoundSlot[index].EffectID = -1;
|
SoundSlot[index].EffectID = SOUND_NO_CHANNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update sound position in a level.
|
// Update sound position in a level.
|
||||||
|
|
||||||
bool Sound_UpdateEffectPosition(int index, Pose *position, bool force)
|
bool Sound_UpdateEffectPosition(int index, Pose *position, bool force)
|
||||||
{
|
{
|
||||||
if (index >= SOUND_MAX_CHANNELS || index < 0)
|
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.
|
// Update whole sound scene in a level.
|
||||||
// Must be called every frame to update camera position and 3D parameters.
|
// Must be called every frame to update camera position and 3D parameters.
|
||||||
|
|
||||||
void Sound_UpdateScene()
|
void Sound_UpdateScene()
|
||||||
{
|
{
|
||||||
if (!g_Configuration.EnableSound)
|
if (!g_Configuration.EnableSound)
|
||||||
|
@ -851,7 +932,6 @@ void Sound_UpdateScene()
|
||||||
|
|
||||||
// Initialize BASS engine and also prepare all sound data.
|
// Initialize BASS engine and also prepare all sound data.
|
||||||
// Called once on engine start-up.
|
// Called once on engine start-up.
|
||||||
|
|
||||||
void Sound_Init(const std::string& gameDirectory)
|
void Sound_Init(const std::string& gameDirectory)
|
||||||
{
|
{
|
||||||
// Initialize and collect soundtrack paths.
|
// Initialize and collect soundtrack paths.
|
||||||
|
@ -893,7 +973,6 @@ void Sound_Init(const std::string& gameDirectory)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Initialize channels and tracks array
|
// Initialize channels and tracks array
|
||||||
ZeroMemory(SoundtrackSlot, (sizeof(HSTREAM) * (int)SoundTrackType::Count));
|
|
||||||
ZeroMemory(SoundSlot, (sizeof(SoundEffectSlot) * SOUND_MAX_CHANNELS));
|
ZeroMemory(SoundSlot, (sizeof(SoundEffectSlot) * SOUND_MAX_CHANNELS));
|
||||||
|
|
||||||
// Attach reverb effect to 3D channel
|
// 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.
|
// Stop all sounds and streams, if any, unplug all channels from the mixer and unload BASS engine.
|
||||||
// Must be called on engine quit.
|
// Must be called on engine quit.
|
||||||
|
|
||||||
void Sound_DeInit()
|
void Sound_DeInit()
|
||||||
{
|
{
|
||||||
if (g_Configuration.EnableSound)
|
if (g_Configuration.EnableSound)
|
||||||
|
|
|
@ -5,13 +5,12 @@
|
||||||
#include "Game/control/control.h"
|
#include "Game/control/control.h"
|
||||||
#include "Sound/sound_effects.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_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_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_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_SAMPLES = 8192;
|
||||||
constexpr auto SOUND_MAX_CHANNELS = 32; // Original was 24, reallocate original 36-byte struct with 24-byte SoundEffectSlot struct
|
constexpr auto SOUND_MAX_CHANNELS = 32;
|
||||||
constexpr auto SOUND_LEGACY_SOUNDMAP_SIZE = 450;
|
constexpr auto SOUND_LEGACY_SOUNDMAP_SIZE = 450;
|
||||||
constexpr auto SOUND_NEW_SOUNDMAP_MAX_SIZE = 4096;
|
constexpr auto SOUND_NEW_SOUNDMAP_MAX_SIZE = 4096;
|
||||||
constexpr auto SOUND_LEGACY_TRACKTABLE_SIZE = 136;
|
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_MAX_GAIN_CHANGE = 0.0625f;
|
||||||
constexpr auto SOUND_32BIT_SILENCE_LEVEL = 4.9e-04f;
|
constexpr auto SOUND_32BIT_SILENCE_LEVEL = 4.9e-04f;
|
||||||
constexpr auto SOUND_SAMPLE_FLAGS = (BASS_SAMPLE_MONO | BASS_SAMPLE_FLOAT);
|
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 = 5000;
|
||||||
constexpr auto SOUND_XFADETIME_BGM_START = 1500;
|
constexpr auto SOUND_XFADETIME_BGM_START = 1500;
|
||||||
constexpr auto SOUND_XFADETIME_ONESHOT = 200;
|
constexpr auto SOUND_XFADETIME_ONESHOT = 200;
|
||||||
|
@ -42,6 +42,7 @@ enum class SoundTrackType
|
||||||
{
|
{
|
||||||
OneShot,
|
OneShot,
|
||||||
BGM,
|
BGM,
|
||||||
|
Voice,
|
||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,8 +97,8 @@ struct SoundEffectSlot
|
||||||
|
|
||||||
struct SoundTrackSlot
|
struct SoundTrackSlot
|
||||||
{
|
{
|
||||||
HSTREAM Channel;
|
HSTREAM Channel { 0 };
|
||||||
std::string Track;
|
std::string Track {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SampleInfo
|
struct SampleInfo
|
||||||
|
@ -112,17 +113,17 @@ struct SampleInfo
|
||||||
|
|
||||||
struct SoundTrackInfo
|
struct SoundTrackInfo
|
||||||
{
|
{
|
||||||
std::string Name{};
|
std::string Name {};
|
||||||
SoundTrackType Mode{ SoundTrackType::OneShot };
|
SoundTrackType Mode { SoundTrackType::OneShot };
|
||||||
int Mask{ 0 };
|
int Mask { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SoundSourceInfo
|
struct SoundSourceInfo
|
||||||
{
|
{
|
||||||
Vector3i Position = Vector3i::Zero;
|
Vector3i Position = Vector3i::Zero;
|
||||||
int SoundID = 0;
|
int SoundID = 0;
|
||||||
int Flags = 0;
|
int Flags = 0;
|
||||||
string Name = "";
|
std::string Name {};
|
||||||
|
|
||||||
SoundSourceInfo()
|
SoundSourceInfo()
|
||||||
{
|
{
|
||||||
|
@ -158,19 +159,21 @@ void FreeSamples();
|
||||||
void StopAllSounds();
|
void StopAllSounds();
|
||||||
void PauseAllSounds(SoundPauseMode mode);
|
void PauseAllSounds(SoundPauseMode mode);
|
||||||
void ResumeAllSounds(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 SayNo();
|
||||||
void PlaySoundSources();
|
void PlaySoundSources();
|
||||||
int GetShatterSound(int shatterID);
|
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<std::string> GetCurrentSubtitle();
|
||||||
std::pair<std::string, QWORD> GetSoundTrackNameAndPosition(SoundTrackType type);
|
std::pair<std::string, QWORD> GetSoundTrackNameAndPosition(SoundTrackType type);
|
||||||
|
|
||||||
static void CALLBACK Sound_FinishOneshotTrack(HSYNC handle, DWORD channel, DWORD data, void* userData);
|
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();
|
int Sound_GetFreeSlot();
|
||||||
void Sound_FreeSlot(int index, unsigned int fadeout = 0);
|
void Sound_FreeSlot(int index, unsigned int fadeout = 0);
|
||||||
int Sound_EffectIsPlaying(int effectID, Pose *position);
|
int Sound_EffectIsPlaying(int effectID, Pose *position);
|
||||||
|
int Sound_TrackIsPlaying(const std::string& fileName);
|
||||||
float Sound_DistanceToListener(Pose *position);
|
float Sound_DistanceToListener(Pose *position);
|
||||||
float Sound_DistanceToListener(Vector3 position);
|
float Sound_DistanceToListener(Vector3 position);
|
||||||
float Sound_Attenuate(float gain, float distance, float radius);
|
float Sound_Attenuate(float gain, float distance, float radius);
|
||||||
bool Sound_UpdateEffectPosition(int index, Pose *position, bool force = false);
|
bool Sound_UpdateEffectPosition(int index, Pose *position, bool force = false);
|
||||||
bool Sound_UpdateEffectAttributes(int index, float pitch, float gain);
|
bool Sound_UpdateEffectAttributes(int index, float pitch, float gain);
|
||||||
|
|
||||||
bool IsSoundEffectPlaying(int effectID);
|
|
||||||
|
|
|
@ -777,7 +777,8 @@ namespace TEN::Input
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vendor = TEN::Utils::ToLower(OisGamepad->vendor());
|
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);
|
ApplyBindings(XInputBindings);
|
||||||
|
|
||||||
|
|
|
@ -259,6 +259,12 @@ bool SaveConfiguration()
|
||||||
return false;
|
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)
|
if (SetBoolRegKey(rootKey, REGKEY_AUTOTARGET, g_Configuration.AutoTarget) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
RegCloseKey(rootKey);
|
RegCloseKey(rootKey);
|
||||||
|
@ -293,6 +299,7 @@ void InitDefaultConfiguration()
|
||||||
|
|
||||||
auto currentScreenResolution = GetScreenResolution();
|
auto currentScreenResolution = GetScreenResolution();
|
||||||
|
|
||||||
|
g_Configuration.EnableSubtitles = true;
|
||||||
g_Configuration.AutoTarget = true;
|
g_Configuration.AutoTarget = true;
|
||||||
g_Configuration.SoundDevice = 1;
|
g_Configuration.SoundDevice = 1;
|
||||||
g_Configuration.EnableReverb = true;
|
g_Configuration.EnableReverb = true;
|
||||||
|
@ -422,13 +429,20 @@ bool LoadConfiguration()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool autoTarget = false;
|
bool autoTarget = true;
|
||||||
if (GetBoolRegKey(rootKey, REGKEY_AUTOTARGET, &autoTarget, true) != ERROR_SUCCESS)
|
if (GetBoolRegKey(rootKey, REGKEY_AUTOTARGET, &autoTarget, true) != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
RegCloseKey(rootKey);
|
RegCloseKey(rootKey);
|
||||||
return false;
|
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++)
|
for (int i = 0; i < KEY_COUNT; i++)
|
||||||
{
|
{
|
||||||
DWORD tempKey;
|
DWORD tempKey;
|
||||||
|
@ -464,6 +478,7 @@ bool LoadConfiguration()
|
||||||
g_Configuration.AutoTarget = autoTarget;
|
g_Configuration.AutoTarget = autoTarget;
|
||||||
g_Configuration.EnableRumble = enableRumble;
|
g_Configuration.EnableRumble = enableRumble;
|
||||||
g_Configuration.EnableThumbstickCameraControl = enableThumbstickCamera;
|
g_Configuration.EnableThumbstickCameraControl = enableThumbstickCamera;
|
||||||
|
g_Configuration.EnableSubtitles = enableSubtitles;
|
||||||
|
|
||||||
// Set legacy variables
|
// Set legacy variables
|
||||||
SetVolumeMusic(musicVolume);
|
SetVolumeMusic(musicVolume);
|
||||||
|
|
|
@ -24,6 +24,7 @@ using namespace TEN::Math;
|
||||||
|
|
||||||
#define REGKEY_ENABLE_RUMBLE "EnableRumble"
|
#define REGKEY_ENABLE_RUMBLE "EnableRumble"
|
||||||
#define REGKEY_ENABLE_THUMBSTICK_CAMERA "EnableThumbstickCamera"
|
#define REGKEY_ENABLE_THUMBSTICK_CAMERA "EnableThumbstickCamera"
|
||||||
|
#define REGKEY_ENABLE_SUBTITLES "EnableSubtitles"
|
||||||
|
|
||||||
#define REGKEY_AUTOTARGET "AutoTarget"
|
#define REGKEY_AUTOTARGET "AutoTarget"
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ struct GameConfiguration
|
||||||
int ShadowMapSize = 1024;
|
int ShadowMapSize = 1024;
|
||||||
int ShadowMaxBlobs = 16;
|
int ShadowMaxBlobs = 16;
|
||||||
|
|
||||||
|
bool EnableSubtitles;
|
||||||
bool AutoTarget;
|
bool AutoTarget;
|
||||||
bool EnableRumble;
|
bool EnableRumble;
|
||||||
bool EnableThumbstickCameraControl;
|
bool EnableThumbstickCameraControl;
|
||||||
|
|
|
@ -6775,6 +6775,8 @@ struct SaveGameT : public flatbuffers::NativeTable {
|
||||||
uint64_t ambient_position = 0;
|
uint64_t ambient_position = 0;
|
||||||
std::string oneshot_track{};
|
std::string oneshot_track{};
|
||||||
uint64_t oneshot_position = 0;
|
uint64_t oneshot_position = 0;
|
||||||
|
std::string voice_track{};
|
||||||
|
uint64_t voice_position = 0;
|
||||||
std::vector<int32_t> cd_flags{};
|
std::vector<int32_t> cd_flags{};
|
||||||
std::unique_ptr<TEN::Save::RopeT> rope{};
|
std::unique_ptr<TEN::Save::RopeT> rope{};
|
||||||
std::unique_ptr<TEN::Save::PendulumT> pendulum{};
|
std::unique_ptr<TEN::Save::PendulumT> pendulum{};
|
||||||
|
@ -6831,23 +6833,25 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||||
VT_AMBIENT_POSITION = 62,
|
VT_AMBIENT_POSITION = 62,
|
||||||
VT_ONESHOT_TRACK = 64,
|
VT_ONESHOT_TRACK = 64,
|
||||||
VT_ONESHOT_POSITION = 66,
|
VT_ONESHOT_POSITION = 66,
|
||||||
VT_CD_FLAGS = 68,
|
VT_VOICE_TRACK = 68,
|
||||||
VT_ROPE = 70,
|
VT_VOICE_POSITION = 70,
|
||||||
VT_PENDULUM = 72,
|
VT_CD_FLAGS = 72,
|
||||||
VT_ALTERNATE_PENDULUM = 74,
|
VT_ROPE = 74,
|
||||||
VT_VOLUMES = 76,
|
VT_PENDULUM = 76,
|
||||||
VT_CALL_COUNTERS = 78,
|
VT_ALTERNATE_PENDULUM = 78,
|
||||||
VT_SCRIPT_VARS = 80,
|
VT_VOLUMES = 80,
|
||||||
VT_CALLBACKS_PRE_START = 82,
|
VT_CALL_COUNTERS = 82,
|
||||||
VT_CALLBACKS_POST_START = 84,
|
VT_SCRIPT_VARS = 84,
|
||||||
VT_CALLBACKS_PRE_END = 86,
|
VT_CALLBACKS_PRE_START = 86,
|
||||||
VT_CALLBACKS_POST_END = 88,
|
VT_CALLBACKS_POST_START = 88,
|
||||||
VT_CALLBACKS_PRE_SAVE = 90,
|
VT_CALLBACKS_PRE_END = 90,
|
||||||
VT_CALLBACKS_POST_SAVE = 92,
|
VT_CALLBACKS_POST_END = 92,
|
||||||
VT_CALLBACKS_PRE_LOAD = 94,
|
VT_CALLBACKS_PRE_SAVE = 94,
|
||||||
VT_CALLBACKS_POST_LOAD = 96,
|
VT_CALLBACKS_POST_SAVE = 96,
|
||||||
VT_CALLBACKS_PRE_CONTROL = 98,
|
VT_CALLBACKS_PRE_LOAD = 98,
|
||||||
VT_CALLBACKS_POST_CONTROL = 100
|
VT_CALLBACKS_POST_LOAD = 100,
|
||||||
|
VT_CALLBACKS_PRE_CONTROL = 102,
|
||||||
|
VT_CALLBACKS_POST_CONTROL = 104
|
||||||
};
|
};
|
||||||
const TEN::Save::SaveGameHeader *header() const {
|
const TEN::Save::SaveGameHeader *header() const {
|
||||||
return GetPointer<const TEN::Save::SaveGameHeader *>(VT_HEADER);
|
return GetPointer<const TEN::Save::SaveGameHeader *>(VT_HEADER);
|
||||||
|
@ -6945,6 +6949,12 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||||
uint64_t oneshot_position() const {
|
uint64_t oneshot_position() const {
|
||||||
return GetField<uint64_t>(VT_ONESHOT_POSITION, 0);
|
return GetField<uint64_t>(VT_ONESHOT_POSITION, 0);
|
||||||
}
|
}
|
||||||
|
const flatbuffers::String *voice_track() const {
|
||||||
|
return GetPointer<const flatbuffers::String *>(VT_VOICE_TRACK);
|
||||||
|
}
|
||||||
|
uint64_t voice_position() const {
|
||||||
|
return GetField<uint64_t>(VT_VOICE_POSITION, 0);
|
||||||
|
}
|
||||||
const flatbuffers::Vector<int32_t> *cd_flags() const {
|
const flatbuffers::Vector<int32_t> *cd_flags() const {
|
||||||
return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_CD_FLAGS);
|
return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_CD_FLAGS);
|
||||||
}
|
}
|
||||||
|
@ -7064,6 +7074,9 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||||
VerifyOffset(verifier, VT_ONESHOT_TRACK) &&
|
VerifyOffset(verifier, VT_ONESHOT_TRACK) &&
|
||||||
verifier.VerifyString(oneshot_track()) &&
|
verifier.VerifyString(oneshot_track()) &&
|
||||||
VerifyField<uint64_t>(verifier, VT_ONESHOT_POSITION) &&
|
VerifyField<uint64_t>(verifier, VT_ONESHOT_POSITION) &&
|
||||||
|
VerifyOffset(verifier, VT_VOICE_TRACK) &&
|
||||||
|
verifier.VerifyString(voice_track()) &&
|
||||||
|
VerifyField<uint64_t>(verifier, VT_VOICE_POSITION) &&
|
||||||
VerifyOffset(verifier, VT_CD_FLAGS) &&
|
VerifyOffset(verifier, VT_CD_FLAGS) &&
|
||||||
verifier.VerifyVector(cd_flags()) &&
|
verifier.VerifyVector(cd_flags()) &&
|
||||||
VerifyOffset(verifier, VT_ROPE) &&
|
VerifyOffset(verifier, VT_ROPE) &&
|
||||||
|
@ -7217,6 +7230,12 @@ struct SaveGameBuilder {
|
||||||
void add_oneshot_position(uint64_t oneshot_position) {
|
void add_oneshot_position(uint64_t oneshot_position) {
|
||||||
fbb_.AddElement<uint64_t>(SaveGame::VT_ONESHOT_POSITION, oneshot_position, 0);
|
fbb_.AddElement<uint64_t>(SaveGame::VT_ONESHOT_POSITION, oneshot_position, 0);
|
||||||
}
|
}
|
||||||
|
void add_voice_track(flatbuffers::Offset<flatbuffers::String> voice_track) {
|
||||||
|
fbb_.AddOffset(SaveGame::VT_VOICE_TRACK, voice_track);
|
||||||
|
}
|
||||||
|
void add_voice_position(uint64_t voice_position) {
|
||||||
|
fbb_.AddElement<uint64_t>(SaveGame::VT_VOICE_POSITION, voice_position, 0);
|
||||||
|
}
|
||||||
void add_cd_flags(flatbuffers::Offset<flatbuffers::Vector<int32_t>> cd_flags) {
|
void add_cd_flags(flatbuffers::Offset<flatbuffers::Vector<int32_t>> cd_flags) {
|
||||||
fbb_.AddOffset(SaveGame::VT_CD_FLAGS, cd_flags);
|
fbb_.AddOffset(SaveGame::VT_CD_FLAGS, cd_flags);
|
||||||
}
|
}
|
||||||
|
@ -7313,6 +7332,8 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(
|
||||||
uint64_t ambient_position = 0,
|
uint64_t ambient_position = 0,
|
||||||
flatbuffers::Offset<flatbuffers::String> oneshot_track = 0,
|
flatbuffers::Offset<flatbuffers::String> oneshot_track = 0,
|
||||||
uint64_t oneshot_position = 0,
|
uint64_t oneshot_position = 0,
|
||||||
|
flatbuffers::Offset<flatbuffers::String> voice_track = 0,
|
||||||
|
uint64_t voice_position = 0,
|
||||||
flatbuffers::Offset<flatbuffers::Vector<int32_t>> cd_flags = 0,
|
flatbuffers::Offset<flatbuffers::Vector<int32_t>> cd_flags = 0,
|
||||||
flatbuffers::Offset<TEN::Save::Rope> rope = 0,
|
flatbuffers::Offset<TEN::Save::Rope> rope = 0,
|
||||||
flatbuffers::Offset<TEN::Save::Pendulum> pendulum = 0,
|
flatbuffers::Offset<TEN::Save::Pendulum> pendulum = 0,
|
||||||
|
@ -7331,6 +7352,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(
|
||||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> callbacks_pre_control = 0,
|
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> callbacks_pre_control = 0,
|
||||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> callbacks_post_control = 0) {
|
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> callbacks_post_control = 0) {
|
||||||
SaveGameBuilder builder_(_fbb);
|
SaveGameBuilder builder_(_fbb);
|
||||||
|
builder_.add_voice_position(voice_position);
|
||||||
builder_.add_oneshot_position(oneshot_position);
|
builder_.add_oneshot_position(oneshot_position);
|
||||||
builder_.add_ambient_position(ambient_position);
|
builder_.add_ambient_position(ambient_position);
|
||||||
builder_.add_callbacks_post_control(callbacks_post_control);
|
builder_.add_callbacks_post_control(callbacks_post_control);
|
||||||
|
@ -7350,6 +7372,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(
|
||||||
builder_.add_pendulum(pendulum);
|
builder_.add_pendulum(pendulum);
|
||||||
builder_.add_rope(rope);
|
builder_.add_rope(rope);
|
||||||
builder_.add_cd_flags(cd_flags);
|
builder_.add_cd_flags(cd_flags);
|
||||||
|
builder_.add_voice_track(voice_track);
|
||||||
builder_.add_oneshot_track(oneshot_track);
|
builder_.add_oneshot_track(oneshot_track);
|
||||||
builder_.add_ambient_track(ambient_track);
|
builder_.add_ambient_track(ambient_track);
|
||||||
builder_.add_action_queue(action_queue);
|
builder_.add_action_queue(action_queue);
|
||||||
|
@ -7422,6 +7445,8 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGameDirect(
|
||||||
uint64_t ambient_position = 0,
|
uint64_t ambient_position = 0,
|
||||||
const char *oneshot_track = nullptr,
|
const char *oneshot_track = nullptr,
|
||||||
uint64_t oneshot_position = 0,
|
uint64_t oneshot_position = 0,
|
||||||
|
const char *voice_track = nullptr,
|
||||||
|
uint64_t voice_position = 0,
|
||||||
const std::vector<int32_t> *cd_flags = nullptr,
|
const std::vector<int32_t> *cd_flags = nullptr,
|
||||||
flatbuffers::Offset<TEN::Save::Rope> rope = 0,
|
flatbuffers::Offset<TEN::Save::Rope> rope = 0,
|
||||||
flatbuffers::Offset<TEN::Save::Pendulum> pendulum = 0,
|
flatbuffers::Offset<TEN::Save::Pendulum> pendulum = 0,
|
||||||
|
@ -7457,6 +7482,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGameDirect(
|
||||||
auto action_queue__ = action_queue ? _fbb.CreateVector<int32_t>(*action_queue) : 0;
|
auto action_queue__ = action_queue ? _fbb.CreateVector<int32_t>(*action_queue) : 0;
|
||||||
auto ambient_track__ = ambient_track ? _fbb.CreateString(ambient_track) : 0;
|
auto ambient_track__ = ambient_track ? _fbb.CreateString(ambient_track) : 0;
|
||||||
auto oneshot_track__ = oneshot_track ? _fbb.CreateString(oneshot_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<int32_t>(*cd_flags) : 0;
|
auto cd_flags__ = cd_flags ? _fbb.CreateVector<int32_t>(*cd_flags) : 0;
|
||||||
auto volumes__ = volumes ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::Volume>>(*volumes) : 0;
|
auto volumes__ = volumes ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::Volume>>(*volumes) : 0;
|
||||||
auto call_counters__ = call_counters ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::EventSetCallCounters>>(*call_counters) : 0;
|
auto call_counters__ = call_counters ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::EventSetCallCounters>>(*call_counters) : 0;
|
||||||
|
@ -7504,6 +7530,8 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGameDirect(
|
||||||
ambient_position,
|
ambient_position,
|
||||||
oneshot_track__,
|
oneshot_track__,
|
||||||
oneshot_position,
|
oneshot_position,
|
||||||
|
voice_track__,
|
||||||
|
voice_position,
|
||||||
cd_flags__,
|
cd_flags__,
|
||||||
rope,
|
rope,
|
||||||
pendulum,
|
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 = ambient_position(); _o->ambient_position = _e; }
|
||||||
{ auto _e = oneshot_track(); if (_e) _o->oneshot_track = _e->str(); }
|
{ auto _e = oneshot_track(); if (_e) _o->oneshot_track = _e->str(); }
|
||||||
{ auto _e = oneshot_position(); _o->oneshot_position = _e; }
|
{ 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 = 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<TEN::Save::RopeT>(_e->UnPack(_resolver)); }
|
{ auto _e = rope(); if (_e) _o->rope = std::unique_ptr<TEN::Save::RopeT>(_e->UnPack(_resolver)); }
|
||||||
{ auto _e = pendulum(); if (_e) _o->pendulum = std::unique_ptr<TEN::Save::PendulumT>(_e->UnPack(_resolver)); }
|
{ auto _e = pendulum(); if (_e) _o->pendulum = std::unique_ptr<TEN::Save::PendulumT>(_e->UnPack(_resolver)); }
|
||||||
|
@ -9591,6 +9621,8 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(flatbuffers::FlatBufferBuild
|
||||||
auto _ambient_position = _o->ambient_position;
|
auto _ambient_position = _o->ambient_position;
|
||||||
auto _oneshot_track = _o->oneshot_track.empty() ? _fbb.CreateSharedString("") : _fbb.CreateString(_o->oneshot_track);
|
auto _oneshot_track = _o->oneshot_track.empty() ? _fbb.CreateSharedString("") : _fbb.CreateString(_o->oneshot_track);
|
||||||
auto _oneshot_position = _o->oneshot_position;
|
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 _cd_flags = _fbb.CreateVector(_o->cd_flags);
|
||||||
auto _rope = _o->rope ? CreateRope(_fbb, _o->rope.get(), _rehasher) : 0;
|
auto _rope = _o->rope ? CreateRope(_fbb, _o->rope.get(), _rehasher) : 0;
|
||||||
auto _pendulum = _o->pendulum ? CreatePendulum(_fbb, _o->pendulum.get(), _rehasher) : 0;
|
auto _pendulum = _o->pendulum ? CreatePendulum(_fbb, _o->pendulum.get(), _rehasher) : 0;
|
||||||
|
@ -9642,6 +9674,8 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(flatbuffers::FlatBufferBuild
|
||||||
_ambient_position,
|
_ambient_position,
|
||||||
_oneshot_track,
|
_oneshot_track,
|
||||||
_oneshot_position,
|
_oneshot_position,
|
||||||
|
_voice_track,
|
||||||
|
_voice_position,
|
||||||
_cd_flags,
|
_cd_flags,
|
||||||
_rope,
|
_rope,
|
||||||
_pendulum,
|
_pendulum,
|
||||||
|
|
|
@ -515,6 +515,8 @@ table SaveGame {
|
||||||
ambient_position: uint64;
|
ambient_position: uint64;
|
||||||
oneshot_track: string;
|
oneshot_track: string;
|
||||||
oneshot_position: uint64;
|
oneshot_position: uint64;
|
||||||
|
voice_track: string;
|
||||||
|
voice_position: uint64;
|
||||||
cd_flags: [int32];
|
cd_flags: [int32];
|
||||||
rope: Rope;
|
rope: Rope;
|
||||||
pendulum: Pendulum;
|
pendulum: Pendulum;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include "framework.h"
|
#include "framework.h"
|
||||||
#include "Specific/trutils.h"
|
|
||||||
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "Renderer/Renderer11.h"
|
#include "Renderer/Renderer11.h"
|
||||||
#include "Renderer/Renderer11Enums.h"
|
#include "Renderer/Renderer11Enums.h"
|
||||||
|
#include "Specific/trutils.h"
|
||||||
|
|
||||||
using TEN::Renderer::g_Renderer;
|
using TEN::Renderer::g_Renderer;
|
||||||
|
|
||||||
|
@ -118,6 +118,20 @@ namespace TEN::Utils
|
||||||
return std::wstring(buffer);
|
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<std::string> SplitString(const std::string& string)
|
std::vector<std::string> SplitString(const std::string& string)
|
||||||
{
|
{
|
||||||
auto strings = std::vector<std::string>{};
|
auto strings = std::vector<std::string>{};
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace TEN::Utils
|
||||||
{
|
{
|
||||||
// String utilities
|
// String utilities
|
||||||
std::string ConstructAssetDirectory(std::string customDirectory);
|
std::string ConstructAssetDirectory(std::string customDirectory);
|
||||||
|
std::string ReplaceNewLineSymbols(const std::string& string);
|
||||||
std::string ToUpper(std::string string);
|
std::string ToUpper(std::string string);
|
||||||
std::string ToLower(std::string string);
|
std::string ToLower(std::string string);
|
||||||
std::string ToString(const std::wstring& wString);
|
std::string ToString(const std::wstring& wString);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue