Formatting text with ACS

Archive of the old editing forum
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. This forum is archived - please use this set of forums to ask new questions.
Locked
User avatar
kodi
 
 
Posts: 1355
Joined: Mon May 06, 2013 8:02 am

Formatting text with ACS

Post by kodi »

I'm writing a function that formats a string with "\n" sequences every LineLength characters. Can't use the standard SetHudWrapWidth function because I need to keep track of how many lines the message consists of. The following works, but ideally I want it to make line breaks only at the last space character of every line so no words are broken up. I've tried doing so in many ways but I just can't seem to get it to work, so I figured I'd have to ask for help.

StringInsert() is from VisualVincent's ACS.NET library and takes the following arguments just FYI:
Spoiler:

Code: Select all

str tempstr="";
str string = "LOTS OF WORDS HERE";
int linelength=55;
int linecount=1;
for(int I=0;I<=strlen(string);I++)
	{

	tempstr=strparam(s:tempstr,c:(getchar(string,I)));
	delay(1); //for debugging 		
				
	if(I== LineLength*linecount && I < strlen(string))
		{
		tempstr=strparam(s:StringInsert(tempstr,I-1,"\n"));
		linecount++;
		}
	print(s:tempstr);
	}
User avatar
Scotty
Posts: 35
Joined: Tue Mar 24, 2009 10:43 pm

Re: Formatting text with ACS

Post by Scotty »

Hey dude, I took a crack at your problem.
It's probably not the best way to do this, but here's what I came up with.
Attached is an example wad.
BlockFormat.wad
(55.95 KiB) Downloaded 42 times

Code: Select all

int lineCount = 0;

function str blockFormatString(str inputString, int charsPerLine) {
    str Result = "";
    
    //reset this to 0 so it can be reused on new calls 
    lineCount = 0;
    
    //Store the text in a temp string. Data will be removed from this variable and separated out into substrings.
    str tempStr = inputString;
    
    //Loop through and determine how to divvy out the lines.
    while(strlen(tempStr) > charsPerLine) {
    
        //check the char after the end of the line to check if it's a space
        if(getChar(tempStr, charsPerLine) == ' ') {
            //If so, concatenate the proper text into the result.
            result = concatenateStrings(3, result, stringSubstring(tempStr, 0, charsPerLine + 1), "\n", "");
            //Clean out the stuff we just concatenated into the result
            tempstr = StringRemove(tempStr, 0, charsPerLine + 1);
            lineCount++;
        //Else, FIND A SPACE TO BREAK AT!
        } else {
            bool found = false;
            //Cycle backwards through the string until a space is found (or run out of characters).
            //Initialze our index here at charsPerLine - 1 because the index in Strings starts at 0.
            for(int i = charsPerLine - 1; i > 0 && !found; i--) { 
                //Check for a space at the current character
                if(getChar(tempStr, i) == ' ') {
                    found = true;
                    
                    //the i + 1 is to copy the found space.
                    result = concatenateStrings(4, result, stringSubstring(tempStr, 0, i + 1), "", "\n");
                    tempstr = stringRemove(tempStr, 0, i + 1);
                    lineCount++;
                }
            }
            
            //If no space was found, break the line off anyway.
            if(!found) {
                result = concatenateStrings(3, result, stringSubstring(tempStr, 0, charsPerLine), "\n", "");
                tempstr = stringRemove(tempStr, 0, charsPerLine);
                lineCount++;
            }
        }
    }
    
    //And this takes care of a hanging line.
    if(strlen(tempStr) > 0) {
        result = concatenateStrings(2, result, tempStr, "", "");
        lineCount++;
    }
    
    return result;
}
I hope I understood your intent and I hope this solves your issue!
User avatar
The Zombie Killer
Posts: 1528
Joined: Thu Jul 14, 2011 12:06 am
Location: Gold Coast, Queensland, Australia

Re: Formatting text with ACS

Post by The Zombie Killer »

If you use gdcc-acc, something like this would probably work:

Code: Select all

Script "ScriptName" (void)
{
	str string  = "LOTS OF WORDS HERE";
	int lineLen = 55;
	
	BeginStrParam();
	for (int i = 0; i < StrLen(string); i++)
	{
		PrintRaw(c:GetChar(string, i));
		if (i % lineLen == 0)
			PrintRaw(c:'\n');
	}
	PrintRaw(c:'\0');
	string = EndStrParam();
	
	Print(s:string);
}
You can emulate this behavior in regular ACS by using C strings, I might edit an example in later

EDIT: This might work in regular ACS, note that none of these examples are tested

Code: Select all

int strBuf[512];
int strBufPos;

function void BeginStrParam(void)
{
	strBufPos = 0;
}

function str EndStrParam(void)
{
	return StrParam(a:strBuf);
}

function void PrintRawChar(int c)
{
	strBuf[strBufPos] = c;
	strBufPos++;
}

Script "ScriptName" (void)
{
	str string  = "LOTS OF WORDS HERE";
	int lineLen = 55;
	
	BeginStrParam();
	for (int i = 0; i < StrLen(string); i++)
	{
		PrintRawChar(GetChar(string, i));
		if (i % lineLen == 0)
			PrintRawChar('\n');
	}
	PrintRawChar('\0');
	string = EndStrParam();
	
	Print(s:string);
}
User avatar
Apothem
Posts: 2070
Joined: Sat Nov 29, 2003 7:13 pm
Location: Performing open heart surgery on an ACS compiler.

Re: Formatting text with ACS

Post by Apothem »

The Zombie Killer wrote:If you use gdcc-acc, something like this would probably work:

Code: Select all

Script "ScriptName" (void)
{
	str string  = "LOTS OF WORDS HERE";
	int lineLen = 55;
	
	BeginStrParam();
	for (int i = 0; i < StrLen(string); i++)
	{
		PrintRaw(c:GetChar(string, i));
		if (i % lineLen == 0)
			PrintRaw(c:'\n');
	}
	PrintRaw(c:'\0');
	string = EndStrParam();
	
	Print(s:string);
}
You can emulate this behavior in regular ACS by using C strings, I might edit an example in later
It'd be easier to use GDCC as it will still compile and run correctly in ACS, and will let you do more stuff along the lines of what you're trying to do.

String manipulation is no easy task, and strings can't be moved in memory because of the way ZDoom handles them.
User avatar
kodi
 
 
Posts: 1355
Joined: Mon May 06, 2013 8:02 am

Re: Formatting text with ACS

Post by kodi »

Epic wrote:Hey dude, I took a crack at your problem.
Man, it works 100% exactly like I want it to. Thank you so much, especially for the heavy commenting and example wad.
Spoiler:
The Zombie Killer wrote:If you use gdcc-acc, something like this would probably work:
I don't yet, but I'll inevitably want to transition to it at some point. Thank you - I'll save your gdcc-acc version until then.
You can emulate this behavior in regular ACS by using C strings, I might edit an example in later
EDIT: This might work in regular ACS, note that none of these examples are tested
Again, thanks a ton. I'll test your version out too as soon as I've had some sleep.
User avatar
Nash
 
 
Posts: 17484
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia
Contact:

Re: Formatting text with ACS

Post by Nash »

There is literally no difference from your point of view if you use gdcc-acc as a drop-in replacement for acc.exe, it just works as before, but suddenly you get access to structs and enums and macros and other advanced features. :D The sooner you move into it, the more you'll be happy as you don't have to hack around limitations anymore.
User avatar
Scotty
Posts: 35
Joined: Tue Mar 24, 2009 10:43 pm

Re: Formatting text with ACS

Post by Scotty »

@Kodi

No problem dude, I'm glad to help! The only thing I can think of that will mess with the function is adding color, but that will just make the lines shorter. I tried playing with that for about an hour and gave up because it was 4am. I have some fresh ideas on how to implement that though so I might take another swing at it.

@Nash

HOW IS THIS A THING? This sounds amazing, I need this in my life right now.
User avatar
Nash
 
 
Posts: 17484
Joined: Mon Oct 27, 2003 12:07 am
Location: Kuala Lumpur, Malaysia
Contact:

Re: Formatting text with ACS

Post by Nash »

Epic: check out zdata.acs in my real-time weather system and see how I packed a huge amount of data ( the FWorld struct) into just 1 global variable. :D
User avatar
Scotty
Posts: 35
Joined: Tue Mar 24, 2009 10:43 pm

Re: Formatting text with ACS

Post by Scotty »

WHAAAAAAAT DOOM CAN DO THAT???
Where have I been? This is amazing!
User avatar
kodi
 
 
Posts: 1355
Joined: Mon May 06, 2013 8:02 am

Re: Formatting text with ACS

Post by kodi »

Epic wrote: No problem dude, I'm glad to help! The only thing I can think of that will mess with the function is adding color, but that will just make the lines shorter. I tried playing with that for about an hour and gave up because it was 4am. I have some fresh ideas on how to implement that though so I might take another swing at it.
Colour sequences isn't necessary for my own purposes, but a way to put new line markers in the original string would be helpful if not strictly necessary (would make in-game books nicer).
What if one used a special character (like "|" or one of the first 31 characters of a font) instead of a space to denote a new line? Your function could either replace it normally the same way it does the space character, but otherwise a second function called after BlockFormatString could just look through the string and replace each such character with "\n". That way there's no need to keep track of how many characters you add to the string. Might be a very stupid idea, I'm just rambling :P
Nash wrote:There is literally no difference from your point of view if you use gdcc-acc as a drop-in replacement for acc.exe, it just works as before, but suddenly you get access to structs and enums and macros and other advanced features. :D The sooner you move into it, the more you'll be happy as you don't have to hack around limitations anymore.
The two reasons I have for not transitioning are :
A) everything I have is written with hacks or in otherwise strange ways, so I'd be compelled to rewrite everything and never get anything out the door
B) I've had the goal of making my code modular and drag-and-droppable to some extent, and most modders still use regular ACC to my knowledge
But like I said, it will happen eventually :)
User avatar
Scotty
Posts: 35
Joined: Tue Mar 24, 2009 10:43 pm

Re: Formatting text with ACS

Post by Scotty »

kodi wrote: Colour sequences isn't necessary for my own purposes, but a way to put new line markers in the original string would be helpful if not strictly necessary (would make in-game books nicer).
What if one used a special character (like "|" or one of the first 31 characters of a font) instead of a space to denote a new line? Your function could either replace it normally the same way it does the space character, but otherwise a second function called after BlockFormatString could just look through the string and replace each such character with "\n". That way there's no need to keep track of how many characters you add to the string. Might be a very stupid idea, I'm just rambling :P
Okay, this may work for you. It breaks the line as normal using just spaces, and you can put in a | to force a break, which can create paragraphs.
Check out the example. The switch on the very right will be of interest to you.
BlockFormat_paragraphs.wad
(73.67 KiB) Downloaded 30 times

Code: Select all

int lineCount = 0;

function str blockFormatString(str inputString, int charsPerLine) {
    str Result = "";
    
    //reset this to 0 so it can be reused on new calls 
    lineCount = 0;
    
    //Loop through and determine how to divvy out the lines.
    while(strlen(inputString) > charsPerLine) {
        //Check to see if the string has the escape character: |
        //This is wrapped in an if else block due to possibility of breaking if the string to modify is around
        //charsPerLine and the leftovers from this function get run through the next if/else block. For example,
        //if we had "The Quick Brown fox jumps over the lazy dog. |The quick", at the end of a string, with a 
        //charsPerLine of say 30, "The quick" would be leftover and would not be able to run through the if or else
        //blocks because both use getChar, which would return an error, because there isn't a 30th position in that string.
        //So thus we restart the while loop to recheck the condition.
        
        //Create a copy of the theoretical line that we can check through and modify.
        str tempStr = stringSubstring(inputString, 0, charsPerLine);
        if(stringContains(tempStr,"|")) {
            //keep track of the last | position so we know what to chop off of inputString.
            int lastPosition = stringFindLast(tempStr, "|") + 1; //note index starts at 0
            //using this because stringRemove has a glitch where it will not remove the last character.
            tempStr = stringSubstring(tempStr, 0, lastPosition);
            //Loop through the string
            for(int index = 0; index < strlen(tempStr); index++) {
                //check the string for '|' and add to the linecount for each one.
                if(getChar(tempstr, index) == '|') {
                    lineCount++;
                }
            }
            tempstr = stringReplace(tempstr, "|", "\n", 0, 0);
            //Add this to the result, remove the stuff we just added
            result = concatenateStrings(2, result, tempstr, "", "");
            inputString = stringRemove(inputString, 0, lastPosition);
                
        } else {

            //check the char after the end of the line to check if it's a space
            if(getChar(inputString, charsPerLine) == ' ') {
                //If so, concatenate the proper text into the result.
                result = concatenateStrings(3, result, stringSubstring(inputString, 0, charsPerLine + 1), "\n", "");
                //Clean out the stuff we just concatenated into the result
                inputString = StringRemove(inputString, 0, charsPerLine + 1);
                lineCount++;
            //Else, FIND A SPACE TO BREAK AT!
            } else {
                bool found = false;
                //Cycle backwards through the string until a space is found (or run out of characters).
                //Initialze our index here at charsPerLine - 1 because the index in Strings starts at 0.
                for(int i = charsPerLine - 1; i > 0 && !found; i--) { 
                    //Check for a space at the current character
                    if(getChar(inputString, i) == ' ') {
                        found = true;
                        
                        //the i + 1 is to copy the found space.
                        result = concatenateStrings(4, result, stringSubstring(inputString, 0, i + 1), "", "\n");
                        inputString = stringRemove(inputString, 0, i + 1);
                        lineCount++;
                    }
                }
            
                //If no space was found, break the line off anyway.
                if(!found) {
                    result = concatenateStrings(3, result, stringSubstring(inputString, 0, charsPerLine), "\n", "");
                    inputString = stringRemove(inputString, 0, charsPerLine);
                    lineCount++;
                }
            }
        }
    }
    
    //And this takes care of a hanging line.
    if(strlen(inputString) > 0) {
        //loop through the remainder of the string and check for |
        for(int index2 = 0; index2 < strlen(inputString); index2++) {
            //check the string for '|' and add to the linecount for each one.
            if(getChar(inputString, index2) == '|') {
                lineCount++;
            }
        }
        //replace the | with \n
        inputString = stringReplace(inputString, "|", "\n", 0, 0);
        result = concatenateStrings(2, result, inputString, "", "");
        lineCount++;
    }
    
    return result;
}
User avatar
kodi
 
 
Posts: 1355
Joined: Mon May 06, 2013 8:02 am

Re: Formatting text with ACS

Post by kodi »

Works amazingly! It handles strings of more than adequate length, and entire books could be handled if they're broken up into pieces and strparam'd together. Implementing ACS mouse cursor "hitboxes" for variable length messages will be a breeze with this, as will collapsible menus. Can't thank you enough :mrgreen:

I added your name to the credits list and to the top of the BlockFormatString library - would you like me to include a license of your choice as well? The whole project I'm using this for will be free and open upon release just FYI.
User avatar
Scotty
Posts: 35
Joined: Tue Mar 24, 2009 10:43 pm

Re: Formatting text with ACS

Post by Scotty »

Glad it worked for you! Just credit is way more than enough, I don't usually mess with licenses.
User avatar
Vincent(PDP)
Posts: 60
Joined: Fri May 16, 2014 3:49 pm
Location: Sweden
Contact:

Re: Formatting text with ACS

Post by Vincent(PDP) »

That's a rather interesting piece of code you've got there, Epic.
I would like to use it, or at least parts of it, for my next ACS.NET version - if that is okay.

If so, it will be distributed under the current license (unless you want to use another one for your parts) with credit and copyright to you for your code.
User avatar
Scotty
Posts: 35
Joined: Tue Mar 24, 2009 10:43 pm

Re: Formatting text with ACS

Post by Scotty »

That sounds cool to me, go for it!
I'm not active on Zandro anymore, but I was known as Scotty over there to some of the old skulltaggers. Would you credit it under that name?

Come to think of it, I should look into changing my name on here.
Locked

Return to “Editing (Archive)”