A profile and source code for a looped command that reads the ED journal log and says them in random voices. Works best with multiple voices installed, will probably need adjusting in the profile for what is set up on your system. I'm still tweaking and making changes to this as I go, but it works for me as is fine right now.
The command labeled with "startup" is run on VA startup to begin the loop of the main "npc messages" routine. It's not crucial to have, you could for instance just do a kill and run sequence for the main at each ship launch to begin and ensure you have just one thread running.
The command checks against the last four names and keeps the same voice if it finds them in its history. The "police timer" is something I came up with to try and add both variety and consistency to the police voices, since they have a generic name. If they're talking repeatedly, within a minute of the last message they said, it keeps the same voice, otherwise it allows randomization again.
The "check exceptions" is the newest thing still in progress. I use one of the source codes to strip commas and periods from the message, as I found the pause too long. But I've found that some messages need some adjustment based on the lack of that pause, or the words themselves just didn't sound correct as is, so I enhanced them. A perfect case is the "No, no!" that some npcs will say. Changing that to "know know" sounds better in speed and annunciation. Any time I run across something in game that sound bad to me, I'll note it and go back and add to this list.
Used Visual Stupid 2017 to make these in C++. Be sure when compiling to change the pathways in the code to where the ED journal log is on your system.
Code "npc.exe" in VA profile that extracts the message itself from the most recent journal log.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <io.h>
#include <fstream>
#include <string>
using namespace std;
vector<string> lines;
string lastname() // Get the last log file name, should be the most recent one
{
_finddata_t data;
int ff = _findfirst("C:\\Users\\<USERNAME>\\Saved Games\\Frontier Developments\\Elite Dangerous\\*.log", &data);
if (ff != -1)
{
int res = 0;
while (res != -1)
{
res = _findnext(ff, &data);
}
_findclose(ff);
}
return data.name;
}
string getloglines(string file) // Read log file, get the last line that has a message
{
int i = 0;
string temp;
string message;
ifstream input;
input.open(file);
do
{
getline(input, temp); // put all the lines into an array
lines.push_back (temp);
i++;
} while (input.peek() != EOF);
while (i>5) { // now go through array backwards to find the first message
size_t channel = lines[i].find("Channel\":\"npc"); // they all have this string in them
if (channel != string::npos) {
size_t start = lines[i].find("Message_Localised"); start += 20; // find unique strings
size_t end = lines[i].find("Channel"); end = end - start - 4; // that the message is
message = lines[i].substr(start, end); // between, adjust the position and extract
return message;
}
i--;
}
exit(0); // if we get this far, no messages yet
}
void main()
{
string filename = lastname();
filename = "C:\\Users\\<USERNAME>\\Saved Games\\Frontier Developments\\Elite Dangerous\\" + filename;
cout << getloglines(filename);
}
Code "whosaid.exe" in VA profile to pass message back and see who said it for further filtering and voice selection.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <io.h>
#include <fstream>
#include <string>
using namespace std;
vector<string> lines;
string lastname() // Get the last log file name, should be the most recent one
{
_finddata_t data;
int ff = _findfirst("C:\\Users\\<USERNAME>\\Saved Games\\Frontier Developments\\Elite Dangerous\\*.log", &data);
if (ff != -1)
{
int res = 0;
while (res != -1)
{
res = _findnext(ff, &data);
}
_findclose(ff);
}
return data.name;
}
string getwhosaid(string file, string message)
{
int i = 0;
string temp;
string whosaid = "Not found"; // In case for some reason it doesn't find it
ifstream input;
input.open(file);
do
{
getline(input, temp); // put all the lines into an array
lines.push_back (temp);
i++;
} while (input.peek() != EOF);
while (i>5) {
size_t channel = lines[i].find(message); // find the message
if (channel != string::npos) {
size_t npc = lines[i].find("npc_name_decorate"); // is it a npc ship?
if (npc != string::npos) {
npc += 24;
size_t end = lines[i].find("From_Localised"); end = end - npc - 5;
whosaid = lines[i].substr(npc, end); // get the name between these two
return whosaid;
}
size_t greeting = lines[i].find("DockingChatter"); // station greetings
if (greeting != string::npos) {
size_t start = lines[i].find("From"); start += 7;
greeting = greeting - start - 15;
whosaid = lines[i].substr(start, greeting); // grab the station name
return whosaid;
}
size_t police = lines[i].find("Police"); // is it the cops?
if (police != string::npos) {
return "Police"; // for now don't care about their specifics
}
size_t station = lines[i].find("STATION"); // is it general station stuff?
if (station != string::npos) {
return "Station"; // return this so it can be skipped in TTS
}
}
i--;
}
return whosaid;
}
void main(int argc, char *argv[])
{
string filename = lastname();
filename = "C:\\Users\\<USERNAME>\\Saved Games\\Frontier Developments\\Elite Dangerous\\" + filename;
string message = argv[1];
for (int i = 2; i < argc; i++) {
message = message + " " + argv[i]; // builds input message into string using argc for length
}
cout << getwhosaid(filename,message);
}
Code "nopunct.exe" in VA profile to remove commas and periods. Others could be done too, but they seem to be the only ones that really affect timing for me.
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <io.h>
#include <fstream>
#include <string>
using namespace std;
bool IsPeriodOrComma(char c)
{
switch (c)
{
case '.':
case ',':
return true;
default:
return false;
}
}
void main(int argc, char *argv[])
{
string message = argv[1];
for (int i = 2; i < argc; i++) {
message = message + " " + argv[i];
}
message.erase(std::remove_if(message.begin(), message.end(), &IsPeriodOrComma), message.end());
cout << message;
}