0 votes
by (170 points)

I'm working on a Twine where the player character is randomly generated. So, to give this randomly generated character a name, I'm resorting to namelists, created using real world namesets and Donjon's excellent Markov Name Generator.

I'm unsure how to efficiently store and retrieve names from the nameset.

The current method I'm using is to store the entire set of namelists in arrays in Harlowe's startup passage, and then use the (either:) macro to randomly generate a name. However, this (predictably) causes large amounts of overhead, which I can live with if there's no other option, but would prefer to avoid.

Is there any way to efficiently use a namelist that I haven't thought of or didn't know about?

2 Answers

+1 vote
by (63.1k points)
selected by
Best answer

It's possible to get around Harlowe's rather slow processing by using pure JavaScript.  For example (goes in story JavaScript):

window.names = window.names || {
    // you can group names if you wish by doing something like this.
    male   : ['Ben', 'Thomas', 'Jimbo', 'Nicholas', 'Arthur'],
    female : ['Betty', 'Theresa', 'Jane', 'Sarah', 'Ellen'],
    // this function ( `names.pick()` ) selects a random name
    pick   : function (gender) {
        // handle the argument
        gender = (typeof gender === 'string') ? gender.trim().toLowerCase() : '';

        // select which name list to use
        var list = (gender === 'male' || gender === 'm') ? names.male : names.female;

        // return a random name from the indicated list
        return list[Math.trunc(Math.random() * list.length)];

Then, to retrieve the names:

(set: $boyName to names.pick('m'))\
(set: $girlName to names.pick())\
$boyName | $girlName

This should speed up performance markedly.

I've heard that datamaps in Harlowe are destroyed and recreated basically every time they are accessed, meaning there's a lot of overhead in using them for certain things.  I don't know for sure, but it's possible the same thing happens with arrays, which would mean that particularly large arrays, and doing a lot of things to them in one chunk of code, could cause similar issues.  Code like this will get around that by keeping Harlowe from ever interacting with the arrays at all.

by (170 points)
Yep, something like this was exactly what I was looking for!

I didn't know you could call Javascript functions from directly inside a macro. Thanks for explaining, I'm still quite new to the platform!
by (63.1k points)

I didn't know you could call Javascript functions from directly inside a macro. 

Here's a write up with examples by @greyelf about using JS in Harlowe. 

A few notes: 

  • Setting Harlowe (i.e. TwineScript) variables to JavaScript variables is possible, though they have to be scoped correctly. The easiest way is to do that with globals. 
  • It's way harder to get TwineScript variables into JavaScript, because of the way Harlowe's engine is scoped. It's possible with hacks, but these hacks aren't guaranteed to work in newer Harlowe versions, and some older hacks have already been broken. 
  • As a general rule, it's possible to access Harlowe's engine functions and other data from within macros, but these will be out of scope in scripts without hacks. 
So it's definitely possible to use JavaScript in Harlowe, but only in certain situations. It's not an officially supported feature either, meaning it could theoretically go away at any time, but the chances of that are slim, since it would require some weird changes to the way Harlowe works. 
+2 votes
by (6.2k points)

Could you not just do:

(set: $name to (either: 'James','Peter','Mary','Kate'))

Or is this what you are already doing? Could you please supply your code, and if this is what you did, what's wrong with it?

by (170 points)
edited by

Thanks for the answer smiley

That is, actually, basically what I'm already doing to implement the random number name generation, but I'm not completely satisfied with it, since each of my namesets has about a 100 names. Having to load multiple giant arrays into memory every time I run introduces some significant lag on startup, which I'd like to avoid as much as possible.

What I'm asking is, is there any faster way to store and/or retrieve these names?

by (63.1k points)

That is, actually, basically what I'm already doing to implement the random number generation

Why are you generating a number at all? 

by (170 points)

Why are you generating a number at all? 

Typo, my apologies. Fixed in the comment now.

by (63.1k points)
Oh okay. I thought maybe you were generating a random number and then somehow using that to cross reference with the array, which is possible, but probably slower than (either:).