Declaring long string constants?

Hopefully a simple question…

I want to declare a long string constant in my script - something on the order of 800 characters long. What is the length limit on string literals in NWScript? How do I get continue a long line of code onto the next line in NWScript? I seem to recall that in C, I could do something like
const char *MyStr = "This is my silly, long string with many "
"characters that runs over several lines "
"and finally comes to a stop.";
How does one do that in NWN?

Strings are concatenated by using the plus sign:

const string MyStr = "This is my silly, long string with many " +
					 "characters that runs over several lines " +
					 "and finally comes to a stop.";

I don’t know what the max length is.

@Aqvilinus Concatenation like that is legal for a string variable, but not for a constant. Your example generates the message ERROR: INVALID VALUE ASSIGNED TO CONSTANT.

The reason is that a constant can only take a value, not an expression.

If the OP can live with a string variable, that method works fine.

According to the file format documentation, the maximum string length is 2 to the power of 32 (4,294,967,296). I don’t think anyone knows whether that’s fully supported in nwscript. Back in the day, someone tried to make progressively longer strings, which worked up to 8 million characters, but at that point they got bored because the lag became tedious. Bioware used to recommend a maximum of 1024, but that was only because networks were very slow in 2002. Simple answer - 800 is no problem at all.

2 Likes

@Proleric It works fine in NWN2 (with Skywing’s Advanced Script Compiler). Sorry, didn’t know it’d be a bit different in NWN1.

2 Likes

note that Nwn2 has gui scripts that are compiled on the fly by the engine. I’ve tried const string concatenation and, in gui scripts, it’s a rabbit hole … no error, just fail.

(gui scripts are compiled on the fly (server side) as some sort of guard against, uh, player intervention)

1 Like

The first question would have to be why? The second is does it have to be a constant? Is it in danger of being altered by your code? If not I may have an alternative for you. At that length a string of that size is going to take up an awful lot of script real estate. Why not put this string into a custom 2da file like -


2DA V2.0

	BigString
0	"This is my silly, long string with many "
1	"characters that runs over several lines "
2	"and finally comes to a stop.#####";

terminating the last line with a sequence of 5 # characters and then use a function like


//function to create a large string from the contents of a custom 2da
//note 1 - last line of 2da ***absolutely must*** finish with 5 # characters
//note 2 - according to the lexicon you cannot have more than 267 characters to a field
//otherwise it will crash NwN so break your string into chunks that are less than this
//
//OK onto the function header - 
//s2daFile is the name of the 2da file without the .2da
//sColumnName is the name of the column in the 2da file that has your string's lines
string BuildBigString(string s2daFile, string sColumnName);

string BuildBigString(string s2daFile, string sColumnName)
{
	int iIndex = 0;
	int iTestLength = 0;
	string sReturnMe = "";
	string sTestMe = "";
	
	while(True) //danger of infinite loop if you forget the terminal sequence ("#####")
	{
		sTestMe = Get2DAString(s2daFile, sColumnName, iIndex++);
		iTestLength = GetStringLength(sTestMe);
		
		if(iTestLength < 5)
		{
			//put code here for error condition
		}
		else
		{
			if(GetStringRight(sTestMe, 5) == "#####") //note the last 2da line must have more than characters than just this pattern
			{
				sReturnMe += GetStringLeft(sTestMe, iTestLength - 5);
				break;
			}
			else
				sReturnMe += sTestMe;
		}
	}
	return sReturnMe;
}

to retrieve it. You then create a string constant just for the 2da name (without the .2da bit) instead. You would then use something like -

	string sMyBigString = BuildBigString(csThis2da, "BigString");

to get it into your script where csThis2da is a string constant containing the 2da file name.

Advantage - String of any size that can be changed at any time without recompiling.
Disadvantage - Danger of infinite loop if you forget to add “#####” to the last line of your string. Last line of string must be greater than 5 characters long. Also string needs to be split into chunks that are less than or equal to 267 characters.

TR

Thank you, folks. I was hoping to use a string constant because 1) they are values that won’t change unless CEP or Beamdog change some art assets and 2) I thought (perhaps without justification) that it would be faster than using variable strings. It turns out that the strings I am using work acceptably fast as variables.

With variable strings, using + for concatenation works fine. I ended up going that route.

As for why I wanted to do this, I was using a string to represent a list of ints. Not the most efficient method, but without native array support, it seemed like the most straightforward approach.

Thanks again.

Ah yes, I use exactly that technique to generate random heads etc.

1 Like

While real arrays don’t exist in NwN you can use pseudo arrays. People have been making, using and posting them in the threads on the various NwN boards for years. This is a little odd seeing as the functions -

SetLocalArrayInt(object, string, int, int)
GetLocalArrayInt(object, string, int)
SetLocalArrayString(object, string, int, string)
GetLocalArrayString(object, string, int)

Have been available since at least patch 1.69 at the latest. They are accessed by having this include file in your script -

#include "nw_o0_itemmaker"

Before using these it is probably a good idea to check them out in the lexicon.

TR

Also: https://forum.neverwintervault.org/t/modularising-the-prc/653/15