It's nice to see you putting up some code, Yu.
I agree with Zeriab on the string literal case advice. When you consider the end user, they may not care or know to pay attention to case sensitivity when writing the plugin command. That can easily become a source of frustration. You seem to have taken notice of that with the args parsing so it might have been an oversight.
Additionally, keep in mind that MV will parse any preceding white space in the command box as a null string, which will then become your command argument. You might want to check if that is the case and take a peek at args[0]. It's probably not like to happen but if it does, it's another source of frustration and potential confusion for the end user.
I also want to comment on the braces. Even for single line statements, include braces. It's a bad habit to get into, and is the source of many bugs - and they do exist in real world code out there (Apple had a case of that a few years ago with their SSL certification validation process; a duplicate 'goto fail;' line ended up in the main body of the function and it exposed a vulnerability in the security). There's often an argument regarding screen real estate efficiency but I find it lacks in comparison to protecting yourself from future bugs and general maintainability of code.
Lastly, a bigger one building on from Zeriab's concern about your loop. This is mostly for learning but feel free to use it practically.
Making use of performance.now() (a built-in function that takes a time stamp that is independent of the system clock), I looked at how long it takes your loop to operate over varying numbers of names used in total in a potential game.
Here's the function that I modified:
// Combine name parts together
Yuyu_RandomName.combineParts = function(type, id, gender) {
var start = "", end = "", name = "";
// Initialize variable array (if necessary)
//if (!Array.isArray($gameVariables.value(vId)))
this.initializeArray();
var times = [];
for (var j = 0; j < 100; ++j) {
this.initializeArray();
var t1 = performance.now();
for (var i = 0; i < 4000; ++i) {
// Get start, end, name, then add to data variable
do {
start = start = this.nameStart();
end = (gender == "m") ? this.nameEndMale() : this.nameEndFemale();
name = start + end;
} while (unique == true && this.nameRepeat(name));
// Set actor name or store npc name in variable
$gameVariables.value(vId)[i] = name;
}
var diff = performance.now() - t1;
times.push(diff);
}
var timeTaken = 0;
for (var i = 0; i < 100; ++i) {
timeTaken += times[i];
}
var avgTime = timeTaken / 100;
};
Basically, store 1000 generated names in the array and record the time it takes to complete. I also kept a count of how many times the do/while executed in a single pass to show how often a collision might occur.
Average Time Taken: 4.93ms
So, 1000 names is quite ok. Let's increase that to 2000.
Average Time taken: 20.05ms
Twice the names, and 5x the time taken. Still only 1 retry on average, so that's ok.
Let's double it up again to 4000.
Average Time Taken: 73.61ms
You can already see that it is taking exponentially longer when doubling up the count.
Let's look at 10k names, so increasing the count by 2.5x.
Average Time Taken: 471.47ms
At about 29k names, it starts to get into an infinite loop of retries to find a unique name. So that's around the limit. I figured that out by testing with 100k names but it wouldn't finish. After leaving it for about 20 minutes and then coming back to check where it was (by pausing the code via debug), i was at 29982.
The reason that it takes so long is because you use an Array for storing currently used names. Arrays are great when it comes to indexing or inserting things, but they're terrible for searching through. This is because it has to be done sequentially, from start to finish. In the case of looking to see if a name already exist, it starts from index 0 and runs through to index n, which is either the same name or the end of the array. This makes our "infinite loop" also take longer and longer to try to resolve itself; it's taking seconds (we can assume by deduction from exponential explosion theory) to retry each time a conflict happens.
Instead, I turned the Array into a Map, and used the generated name as a key. I'm only doing this for demonstration and it requires a change to the nameRepeat function. As an implementation to the problem, it isn't ideal at all because you want to be able to refer to names by their ID and this would be ineffecient for that purpose - we'd have to search all values to find a match and that's worse than indexing an array.
The same 10k names took an average of 4.91ms. That's as fast as 1k names with an Array.
Because of how Maps break down when it comes to searching, they're quick for this kind of purpose. In terms of their time complexity (a measurement of time units that an operation takes), Maps have constant time searching whereas Arrays are linear time depending on their size and where the target actually is.
You wouldn't want to use a Map solely for this problem - you really do want the ID number to be the key and not the name itself. You could, however, consider keeping a seperate Map that exists purely for keep a track of currently used names and then store an array of names in the $gameVariables as you are doing. But this comes at a cost of increased memory usage; you're effectively doubling it to save time.
Given that a game won't typically have huge numbers of NPCs, it probably isn't an issue. So take this as a thought exercise that simply points out the ups and downs to what data structure you choose to use. There are multiple solutions to this problem that I can think of from the top of my head which might make for some good learning opportunities.