GameMaker draw_text_special() script and typewriter style

Ednei

Member
Guys, I need some help.

I found this wonderful draw_text_special () script on this site:
https://www.gmlscripts.com/forums/viewtopic.php?id=2054

Code:
/*
argument0=x
argument1=y
argument2=text
argument3=font
argument4=color
argument5=vertical spacing (-1 default)
argument6=max width (-1 default)
argument7=full align
argument8=icon sprite resource (-1 for none)
argument9: 0= draw text, 1= return text width, 2= return text height
argument10: 0= align text left, 1= align text center, 2= align text right
argument11: 0= align text top, 1= align text middle, 2= align text bottom

special characters:
\sym{x} draw a symbol of a symbol spriteset (argument8) with subimage x
\col{R,G,B}text/ changes color to RGB value for text
*/

var list_char;list_char=ds_list_create();
var list_line;list_line=ds_list_create(); //list members are other lists containing the line's characters
var list_alignmentapplies;list_alignmentapplies=ds_list_create();
var list_linewidth;list_linewidth=ds_list_create();
var i,j,k,m,p,t,z,c,a,changeline;
var cred,cgreen,cblue;
var numspaces;
var forcealign;
var symbolsize;
var txtwidth;txtwidth=argument6;
if argument6=-1 then txtwidth=99999;
var tspac;tspac=argument5;
var wordspace;
var spacewidth;
var diesiwidth;
var offx,offy;
var strlen;strlen=string_length(argument2); //char length of text

draw_set_halign(fa_left);
draw_set_valign(fa_top);
draw_set_font(argument3);
symbolsize=string_height("0");
if argument5=-1 then tspac=symbolsize;
spacewidth=string_width(" ");
diesiwidth=string_width("\#");
//insert all chars into the list and transform symbols
i=0;
do
{
i+=1;
k=0;
if string_char_at(argument2,i)="\" then
{
    if string_copy(argument2,i,5)="\sym{" then
    {
    i+=5;j=i;do j+=1 until string_char_at(argument2,j)="}";
    ds_list_add(list_char,"sym"+string_copy(argument2,i,j-i));
    i=j;k=1; //special symbol found
    }
  
    if string_copy(argument2,i,5)="\col{" then
    {
    i+=5;j=i;do j+=1 until string_char_at(argument2,j)="}";
    ds_list_add(list_char,"col"+string_copy(argument2,i,j-i));
    i=j+1;
    j=i;do {ds_list_add(list_char,string_char_at(argument2,j));j+=1} until string_char_at(argument2,j)="/";
    ds_list_add(list_char,"col"+calc_real2str(color_get_red(argument4),0,0,0,0,0)+","+calc_real2str(color_get_green(argument4),0,0,0,0,0)+","+calc_real2str(color_get_blue(argument4),0,0,0,0,0));
    i=j;k=1; //special symbol found
    }
  
    if string_copy(argument2,i,2)="\#" then
    {
    i+=1;
    ds_list_add(list_char,"pr#");
    k=1; //special symbol found
    }
}
if k=0 then ds_list_add(list_char,string_char_at(argument2,i));
}
until i=strlen;

//create lines
i=-1;
t=-1; //tracks start of line relative to list_char
j=0; //text width
changeline=0; //if line changes then it is set to 1
do
{
i+=1;
k=ds_list_find_value(list_char,i);
if string_length(k)=1 then j+=string_width(k) else {if string_copy(k,1,3)="sym" then j+=symbolsize;if string_copy(k,1,3)="pr#" then j+=diesiwidth;}

if k<>"#" then
{
    if j>=txtwidth then
    {
    changeline=1;forcealign=argument7;
    i+=1;m=j;do
    {
    i+=-1;
    z=ds_list_find_value(list_char,i);
    if string_length(z)=1 then m+=-string_width(z) else {if string_copy(k,1,3)="sym" then m+=-symbolsize;if string_copy(k,1,3)="pr#" then m+=-diesiwidth;}
    }
    until ds_list_find_value(list_char,i)=" ";
    ds_list_add(list_linewidth,m);
    }
}
else
{
    changeline=1;forcealign=false;ds_list_add(list_linewidth,j);
} 

    if changeline=1 then //line change
    {
    j=0; //text width resets to 0
    changeline=0; //line change resets to 0
    p=ds_list_create();
    ds_list_add(list_line,p);
    ds_list_add(list_alignmentapplies,forcealign);
        repeat i-t
        {
        t+=1;
        ds_list_add(p,ds_list_find_value(list_char,t));
        }
    }
}
until i=ds_list_size(list_char)-1;

//add last line
p=ds_list_create();
ds_list_add(list_line,p);
ds_list_add(list_alignmentapplies,false);
repeat i-t+1
{
t+=1;
ds_list_add(p,ds_list_find_value(list_char,t));
}
ds_list_add(list_linewidth,j);

switch argument9
{
case 0: //draw text normally
{

break;
}

case 1: //return width
{
var list_linewidth_orig;list_linewidth_orig=ds_list_create();
ds_list_copy(list_linewidth_orig,list_linewidth);
ds_list_sort(list_linewidth,0);
var whereismax;whereismax=ds_list_find_index(list_linewidth_orig,ds_list_find_value(list_linewidth,0));
j=ds_list_find_value(list_linewidth,0);
i=-1;repeat ds_list_size(list_line) {i+=1;if ds_list_find_value(list_alignmentapplies,i)=1 then {j=argument6;break;}}

ds_list_destroy(list_linewidth_orig);

ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);
return j;
break;
}

case 2:  //return height
{
j=ds_list_size(list_line)*tspac;

ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);
return j;
break;
}
}

//draw text
draw_set_color(argument4);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
j=-1;
k=0;
a=0; //because wordspace=floor((txtwidth-c)/numspaces),due to the floor() some space will be lost. 'a' stores that extra space.
p=ds_list_find_value(list_line,i);
wordspace=spacewidth;
switch argument10
{
case 0:{offx=0;break;}
case 1:{offx=-round(ds_list_find_value(list_linewidth,i)/2);break;}
case 2:{offx=-ds_list_find_value(list_linewidth,i);break;}
}

switch argument11
{
case 0:{offy=0;break;}
case 1:{offy=-round(0.5*ds_list_size(list_line)*tspac);break;}
case 2:{offy=-ds_list_size(list_line)*tspac;break;}
}

if argument7=1 then //find number of spaces in line
{
if ds_list_size(list_line)>1 then
{
if ds_list_find_value(list_alignmentapplies,i)=true then
{
numspaces=0;t=-1;c=0;
repeat ds_list_size(p)-1
{
t+=1;
m=ds_list_find_value(p,t);
if string_length(m)=1 then {if m<>" " then c+=string_width(m) else numspaces+=1;} else {if string_copy(m,1,3)="sym" then c+=symbolsize;if string_copy(m,1,3)="pr#" then c+=diesiwidth;}
}
if numspaces>0 then
{
wordspace=floor((txtwidth-c)/numspaces);
a=txtwidth-c-numspaces*wordspace;
}
}
}
switch argument10
{
case 0:{offx=0;break;}
case 1:{offx=-round((argument6)/2);break;}
case 2:{offx=-argument6;break;}
}
}

    repeat ds_list_size(p)
    {
    j+=1;
    m=ds_list_find_value(p,j);
        if string_length(m)=1 then
        {
        draw_text(argument0+k+offx,argument1+offy+tspac*i,m);
        if m=" " then {k+=wordspace;if a>0 then {a+=-1;k+=1;}} else k+=string_width(m);
        }
        else
        {
            if string_copy(m,1,3)="col" then
            {
            t=3;z=3;do z+=1 until string_char_at(m,z)=",";cred=string_copy(m,t+1,z-t-1);z+=1;t=z;
            do z+=1 until string_char_at(m,z)=",";cgreen=string_copy(m,t,z-t);t=z;
            cblue=string_copy(m,t+1,string_length(m)-z);
            draw_set_color(make_color_rgb(real(cred),real(cgreen),real(cblue)));
            }
          
            if string_copy(m,1,3)="sym" then
            {
            draw_sprite_ext(argument8,real(string_digits(m)),argument0+k+offx+symbolsize/2,argument1+offy+tspac*i+(symbolsize/2),symbolsize/sprite_get_width(argument8),symbolsize/sprite_get_width(argument8),0,c_white,1);
            k+=symbolsize;
            }
          
            if string_copy(m,1,3)="pr#" then
            {
            draw_text(argument0+k+offx,argument1+offy+tspac*i,"\#");
            k+=diesiwidth;
            }
        }
    }
}


ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);



This script is working very well in my RPG project. It allows you to enter colored letters and sprites in the text.
Example:
Code:
draw_text_special(10,10,"While \col{0,255,255}Scientists/ offer a large bonus to \sym{2} Research,  \col{255,128,0}Engineers/ are skilled craftsmen who specialize in increasing your \sym{0} Production. They are skilled at \col{255,255,0}Small guns/, \col{255,255,0}Shotguns/ and \col{255,255,0}Big guns/.",font0,c_white,18,250,1,spr_icon);
Result:



However I would like this script to work in a way to simulate typed text (typewriter) like in classic RPGs.

Could anyone tell me how I should modify this script to display typed text?
 
Last edited:

TheouAegis

Member
What do you mean typed text like in classic RPGs? And how classic are we going here? Like, ZORK classic? Bard's Tale classic? Ultima classic?
 

TheouAegis

Member
Oooooh.... That's gonna be tedious. Need a global variable to keep track of what character you are currently displaying. Then, at a glance, I'd say it looks like you have the script jump to whatever character you're on and resume transcribing. ...To keep things simpler, if I were him/her/it, I'd let special words draw in full immediately. That way you wouldn't have to keep track of where the last style command was.
 

Ednei

Member
What do you mean typed text like in classic RPGs? And how classic are we going here? Like, ZORK classic? Bard's Tale classic? Ultima classic?
screen1.png screen2.png

I'm sorry, I guess I just said it wrong. My English is bad.
The script is already implemented in my game and allows you to display icons in the text as well as allows you to modify the colors as I wish.

The problem is that the text is displayed instantly. I would like this script to display the text letter by letter in a paused way. Like I'm using a typewriter.

I've tried several tutorials and tried to adapt them to this script, but I could not. So I'm here to get some idea of how to do it.

Thank you.
 
D

dannyjenn

Guest
If I were you, I'd just rewrite the script. Rewriting it is probably easier than trying to modify it.

I would start by writing some code to parse the string. Your code could break up the string into a ds_list. And your ds_list would then look something like this:
Code:
While
\col{0,255,255}
Scientists
/
 offer a large bonus to
\sym{2}
 Research,
\col{255,128,0}
Engineers
/
 are skilled craftsmen who specialize in increasing your
\sym{0}
 Production. They are skilled at
\col{255,255,0}
Small guns
/
,
\col{255,255,0}
Shotguns
/
 and
\
col{255,255,0}
Big guns
/
.
From there you could loop through the ds_list. If you come across a \col{...} you change the drawing color, if you come across a / you change the drawing color back to the default (or you could change it back to the previous color, though that would require an additional ds_stack), and if you come across a sym{...} you draw a symbol. Otherwise you draw the string one letter at a time. (Though it would be far easier to do this with a monospace font, and for the text not to be justified.)
 
Last edited by a moderator:

Rob

Member
View attachment 21307 View attachment 21308

I'm sorry, I guess I just said it wrong. My English is bad.
The script is already implemented in my game and allows you to display icons in the text as well as allows you to modify the colors as I wish.

The problem is that the text is displayed instantly. I would like this script to display the text letter by letter in a paused way. Like I'm using a typewriter.

I've tried several tutorials and tried to adapt them to this script, but I could not. So I'm here to get some idea of how to do it.

Thank you.
This is what I mainly used to set up my Not-Working-Perfectly (my fault, not his) text boxes.
http://michaelvandiest.com/advanced-dialogue-box/

I'm pretty sure the way the typewriter effect works is the timer/cutoff variables so if you can incorporate that into the script then you're golden!
 

Ednei

Member
This is what I mainly used to set up my Not-Working-Perfectly (my fault, not his) text boxes.
http://michaelvandiest.com/advanced-dialogue-box/

I'm pretty sure the way the typewriter effect works is the timer/cutoff variables so if you can incorporate that into the script then you're golden!
I believe the snippet of code that should be modified would be this:

Code:
//draw text
draw_set_color(argument4);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
j=-1;
k=0;
a=0; //because wordspace=floor((txtwidth-c)/numspaces),due to the floor() some space will be lost. 'a' stores that extra space.
p=ds_list_find_value(list_line,i);
wordspace=spacewidth;
switch argument10
{
case 0:{offx=0;break;}
case 1:{offx=-round(ds_list_find_value(list_linewidth,i)/2);break;}
case 2:{offx=-ds_list_find_value(list_linewidth,i);break;}
}

switch argument11
{
case 0:{offy=0;break;}
case 1:{offy=-round(0.5*ds_list_size(list_line)*tspac);break;}
case 2:{offy=-ds_list_size(list_line)*tspac;break;}
}

if argument7=1 then //find number of spaces in line
{
if ds_list_size(list_line)>1 then
{
if ds_list_find_value(list_alignmentapplies,i)=true then
{
numspaces=0;t=-1;c=0;
repeat ds_list_size(p)-1
{
t+=1;
m=ds_list_find_value(p,t);
if string_length(m)=1 then {if m<>" " then c+=string_width(m) else numspaces+=1;} else {if string_copy(m,1,3)="sym" then c+=symbolsize;if string_copy(m,1,3)="pr#" then c+=diesiwidth;}
}
if numspaces>0 then
{
wordspace=floor((txtwidth-c)/numspaces);
a=txtwidth-c-numspaces*wordspace;
}
}
}
switch argument10
{
case 0:{offx=0;break;}
case 1:{offx=-round((argument6)/2);break;}
case 2:{offx=-argument6;break;}
}
}

    repeat ds_list_size(p)
    {
    j+=1;
    m=ds_list_find_value(p,j);
        if string_length(m)=1 then
        {
        draw_text(argument0+k+offx,argument1+offy+tspac*i,m);
        if m=" " then {k+=wordspace;if a>0 then {a+=-1;k+=1;}} else k+=string_width(m);
        }
        else
        {
            if string_copy(m,1,3)="col" then
            {
            t=3;z=3;do z+=1 until string_char_at(m,z)=",";cred=string_copy(m,t+1,z-t-1);z+=1;t=z;
            do z+=1 until string_char_at(m,z)=",";cgreen=string_copy(m,t,z-t);t=z;
            cblue=string_copy(m,t+1,string_length(m)-z);
            draw_set_color(make_color_rgb(real(cred),real(cgreen),real(cblue)));
            }
          
            if string_copy(m,1,3)="sym" then
            {
            draw_sprite_ext(argument8,real(string_digits(m)),argument0+k+offx+symbolsize/2,argument1+offy+tspac*i+(symbolsize/2),symbolsize/sprite_get_width(argument8),symbolsize/sprite_get_width(argument8),0,c_white,1);
            k+=symbolsize;
            }
          
            if string_copy(m,1,3)="pr#" then
            {
            draw_text(argument0+k+offx,argument1+offy+tspac*i,"\#");
            k+=diesiwidth;
            }
        }
    }
}


ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);

I'm trying to replace the "repeat" function with its "while" equivalent to try to create the Typewriter effect but I still can not succeed. :bash:
 

vdweller

Member
I wouldn't touch the script if I were you, it's very hairy. I know since I wrote it.

But you also don't need to.

See, in typewriter effects all you need to do is modify the string, not the method of display.

You just have your string (str) and each X steps you display a part of the string using string_copy(str,1,count), but each time you do it, count is incremented by 1 (store this in a variable). When do you stop? When count is equal to string_length(str). That's all.

Plug that str to draw_text_special and you're good to go.
 

TheouAegis

Member
I wouldn't touch the script if I were you, it's very hairy. I know since I wrote it.

But you also don't need to.

See, in typewriter effects all you need to do is modify the string, not the method of display.

You just have your string (str) and each X steps you display a part of the string using string_copy(str,1,count), but each time you do it, count is incremented by 1 (store this in a variable). When do you stop? When count is equal to string_length(str). That's all.

Plug that str to draw_text_special and you're good to go.
*facepalm* So simple! But.... doesn't the script use control words? So then wouldn't the string at some point contain only part of the control word and thus the control word would be printed out instead of processed?
 

sylvain_l

Member
*facepalm* So simple! But.... doesn't the script use control words? So then wouldn't the string at some point contain only part of the control word and thus the control word would be printed out instead of processed?
that just mean he needs to create a custom version of string_length(str). that would jump the content of control world like their non-printable char
 

TheouAegis

Member
So he would basically need to write a script that does the exact same thing as half of draw_text_special... So he'd basically be running draw_text_special 1.5x every step.
 

sylvain_l

Member
not perfect; but usually if it's for dialogue typewriting sequence of the game; he shouldn't be at it's most demanding part of the game in term of cpu/gpu. So He should be good to do that 1.5 run of that script.
(but that's a wild assumption I must admit :( )
 
D

dannyjenn

Guest
I have an idea which will work in GMS2 (not sure about GMS1 though, and it will certainly not work in GM8).

What you can do is modify the control words such that each control word is only a single character long. By doing that, you can display the text letter-by-letter and you won't end up printing the control words before they complete.

This will only allow for 12-bit color though, but the player probably won't notice.

The idea is to use the single-character UTF-8 code $Frgb instead of the several-character-long string "\col{rr,gg,bb}" to change the color, and the single-character UTF-8 code $E00x instead of the several-character string "\sym{x}" to display a symbol. So, for example, "\col{255,128,0}" becomes "\uFF70", where the $F70 is a red value of $F (out of $F), a green value of $7 (out of $F), and a blue value of $0 (out of $F).

I've modified the script as follows:
Code:
// script draw_text_special_modified

/*
argument0=x
argument1=y
argument2=text
argument3=font
argument4=color
argument5=vertical spacing (-1 default)
argument6=max width (-1 default)
argument7=full align
argument8=icon sprite resource (-1 for none)
argument9: 0= draw text, 1= return text width, 2= return text height
argument10: 0= align text left, 1= align text center, 2= align text right
argument11: 0= align text top, 1= align text middle, 2= align text bottom

special characters:
\uE00x draw a symbol of a symbol spriteset (argument8) with subimage x
\uFrgbtext/ changes color to 12-bit RGB value for text
*/

var __x = argument0;
var __y = argument1;
var __text = argument2;
var __font = argument3;
var __color = argument4;
var __v_spacing = argument5;
var __max_width = argument6;
var __full_align = argument7;
var __spr_icon = argument8;
var __mode = argument9;
var __h_alignment = argument10;
var __v_alignment = argument11;

var list_char;list_char=ds_list_create();
var list_line;list_line=ds_list_create(); //list members are other lists containing the line's characters
var list_alignmentapplies;list_alignmentapplies=ds_list_create();
var list_linewidth;list_linewidth=ds_list_create();
var i,j,k,m,p,t,z,c,a,changeline;
var cred,cgreen,cblue;
var numspaces;
var forcealign;
var symbolsize;
var txtwidth;txtwidth=__max_width;
if __max_width=-1 then txtwidth=99999;
var tspac;tspac=__v_spacing;
var wordspace;
var spacewidth;
var diesiwidth;
var offx,offy;
var strlen;strlen=string_length(__text); //char length of text

draw_set_halign(fa_left);
draw_set_valign(fa_top);
draw_set_font(__font);
symbolsize=string_height("0");
if __v_spacing=-1 then tspac=symbolsize;
spacewidth=string_width(" ");
diesiwidth=string_width("M");
//insert all chars into the list and transform symbols
i=0;
do
{
i+=1;
k=0;
if (ord(string_char_at(__text,i))&$F000)=$E000 then // symbol
{
ds_list_add(list_char,"sym"+string((ord(string_char_at(__text,i))&$FFF)));
k=1; //special symbol found
}
else if (ord(string_char_at(__text,i))&$F000)=$F000 then // begin color
{
var __r = ((ord(string_char_at(__text,i))&$0F00)>>4);
var __g = (ord(string_char_at(__text,i))&$00F0);
var __b = ((ord(string_char_at(__text,i))&$000F)<<4);
ds_list_add(list_char,"col"+string(__r)+","+string(__g)+","+string(__b));
k=1; //special symbol found
}
else if string_char_at(__text,i)="/" then // end color
{
ds_list_add(list_char,"col"+string(color_get_red(__color))+","+string(color_get_green(__color))+","+string(color_get_blue(__color)));
k=1;  //special symbol found
}
if k=0 then ds_list_add(list_char,string_char_at(__text,i));
}
until i=strlen;

//create lines
i=-1;
t=-1; //tracks start of line relative to list_char
j=0; //text width
changeline=0; //if line changes then it is set to 1
do
{
i+=1;
k=ds_list_find_value(list_char,i);
if string_length(k)=1 then j+=string_width(k) else {if string_copy(k,1,3)="sym" then j+=symbolsize;if string_copy(k,1,3)="pr\n" then j+=diesiwidth;}

if k<>"\n" then
{
    if j>=txtwidth then
    {
    changeline=1;forcealign=__full_align;
    i+=1;m=j;do
    {
    i+=-1;
    z=ds_list_find_value(list_char,i);
    if string_length(z)=1 then m+=-string_width(z) else {if string_copy(k,1,3)="sym" then m+=-symbolsize;if string_copy(k,1,3)="pr\n" then m+=-diesiwidth;}
    }
    until ds_list_find_value(list_char,i)=" ";
    ds_list_add(list_linewidth,m);
    }
}
else
{
    changeline=1;forcealign=false;ds_list_add(list_linewidth,j);
}

    if changeline=1 then //line change
    {
    j=0; //text width resets to 0
    changeline=0; //line change resets to 0
    p=ds_list_create();
    ds_list_add(list_line,p);
    ds_list_add(list_alignmentapplies,forcealign);
        repeat i-t
        {
        t+=1;
        ds_list_add(p,ds_list_find_value(list_char,t));
        }
    }
}
until i=ds_list_size(list_char)-1;

//add last line
p=ds_list_create();
ds_list_add(list_line,p);
ds_list_add(list_alignmentapplies,false);
repeat i-t+1
{
t+=1;
ds_list_add(p,ds_list_find_value(list_char,t));
}
ds_list_add(list_linewidth,j);

switch __mode
{
case 0: //draw text normally
{

break;
}

case 1: //return width
{
var list_linewidth_orig;list_linewidth_orig=ds_list_create();
ds_list_copy(list_linewidth_orig,list_linewidth);
ds_list_sort(list_linewidth,0);
var whereismax;whereismax=ds_list_find_index(list_linewidth_orig,ds_list_find_value(list_linewidth,0));
j=ds_list_find_value(list_linewidth,0);
i=-1;repeat ds_list_size(list_line) {i+=1;if ds_list_find_value(list_alignmentapplies,i)=1 then {j=__max_width;break;}}

ds_list_destroy(list_linewidth_orig);

ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);
return j;
break;
}

case 2:  //return height
{
j=ds_list_size(list_line)*tspac;

ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);
return j;
break;
}
}

//draw text
draw_set_color(__color);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
j=-1;
k=0;
a=0; //because wordspace=floor((txtwidth-c)/numspaces),due to the floor() some space will be lost. 'a' stores that extra space.
p=ds_list_find_value(list_line,i);
wordspace=spacewidth;
switch __h_alignment
{
case 0:{offx=0;break;}
case 1:{offx=-round(ds_list_find_value(list_linewidth,i)/2);break;}
case 2:{offx=-ds_list_find_value(list_linewidth,i);break;}
}

switch __v_alignment
{
case 0:{offy=0;break;}
case 1:{offy=-round(0.5*ds_list_size(list_line)*tspac);break;}
case 2:{offy=-ds_list_size(list_line)*tspac;break;}
}

if __full_align=1 then //find number of spaces in line
{
if ds_list_size(list_line)>1 then
{
if ds_list_find_value(list_alignmentapplies,i)=true then
{
numspaces=0;t=-1;c=0;
repeat ds_list_size(p)-1
{
t+=1;
m=ds_list_find_value(p,t);    if(!is_string(m)){ m=""; }
if string_length(m)=1 then {if m<>" " then c+=string_width(m) else numspaces+=1;} else {if string_copy(m,1,3)="sym" then c+=symbolsize;if string_copy(m,1,3)="pr\n" then c+=diesiwidth;}
}
if numspaces>0 then
{
wordspace=floor((txtwidth-c)/numspaces);
a=txtwidth-c-numspaces*wordspace;
}
}
}
switch __h_alignment
{
case 0:{offx=0;break;}
case 1:{offx=-round((__max_width)/2);break;}
case 2:{offx=-__max_width;break;}
}
}

    repeat ds_list_size(p)
    {
    j+=1;
    m=ds_list_find_value(p,j);    if(!is_string(m)){ m=""; }
        if string_length(m)=1 then
        {
        draw_text(__x+k+offx,__y+offy+tspac*i,m);
        if m=" " then {k+=wordspace;if a>0 then {a+=-1;k+=1;}} else k+=string_width(m);
        }
        else
        {
            if string_copy(m,1,3)="col" then
            {
            t=3;z=3;do z+=1 until string_char_at(m,z)=",";cred=string_copy(m,t+1,z-t-1);z+=1;t=z;
            do z+=1 until string_char_at(m,z)=",";cgreen=string_copy(m,t,z-t);t=z;
            cblue=string_copy(m,t+1,string_length(m)-z);
            draw_set_color(make_color_rgb(real(cred),real(cgreen),real(cblue)));
            }
      
            if string_copy(m,1,3)="sym" then
            {
            draw_sprite_ext(__spr_icon,real(string_digits(m)),__x+k+offx+symbolsize/2,__y+offy+tspac*i+(symbolsize/2),symbolsize/sprite_get_width(__spr_icon),symbolsize/sprite_get_width(__spr_icon),0,c_white,1);
            k+=symbolsize;
            }
      
            if string_copy(m,1,3)="pr\n" then
            {
            draw_text(__x+k+offx,__y+offy+tspac*i,"#");
            k+=diesiwidth;
            }
        }
    }
}


ds_list_destroy(list_char);
i=-1;
repeat ds_list_size(list_line)
{
i+=1;
ds_list_destroy((ds_list_find_value(list_line,i)));
}
ds_list_destroy(list_line);
ds_list_destroy(list_alignmentapplies);
ds_list_destroy(list_linewidth);
(Lines 66-83 (lines 51-76 in the original script) are the bulk of what was changed.)

Test code:
Code:
// create event:
final_string = "While \uF0FFScientists/ offer a large bonus to \uE002 Research,  \uFF70Engineers/ are skilled craftsmen who specialize in increasing your \uE000 Production. They are skilled at \uFFF0Small guns/, \uFFF0Shotguns/ and \uFFF0Big guns/.";
current_string = " "; // <-- needs to be a space, not an empty string, or else the program will freeze

i = 0;
alarm[0] = 1;
Code:
// alarm[0] event:
i += 1;
current_string = string_copy(final_string,1,i);
alarm[0] = 1;
Code:
// draw event:
draw_text_special_modified(10,10,current_string,font0,c_white,18,250,1,spr_icon,0,0,0);
It works, but there's one huge problem with it: when the text approaches the end of the line, and the last word gets too long, then the last word abruptly jumps to the next line and the previous line spreads itself out to justified alignment. Looks horrible.
(There's probably some way to fix it, but I'm not sure how at the moment and I don't have time to figure it out.)
 
Last edited by a moderator:
D

dannyjenn

Guest
A second idea is to cheat and draw the entire text to a surface (using the original script... no need to modify it), and then use draw_surface_part() to only show part of that surface rather than showing it all at once. You'd then increase draw_surface_part()'s width by about 10 pixels or so each time the alarm goes off and it will sort of give the illusion that the text is showing up letter-by-letter. It won't be perfect since the font isn't monospace, but this is probably the easiest way to do it (and depending upon your alarm's speed, it might not be too noticeable).
 

vdweller

Member
*facepalm* So simple! But.... doesn't the script use control words? So then wouldn't the string at some point contain only part of the control word and thus the control word would be printed out instead of processed?
Hahhaaaa yes you are right, I'm such an idiot! Indeed you would need a modifier script, but it would be really a lot simpler than draw_text_special, since all you need to do is check the string end and backwards for symbols and append their content when necessary. draw_text_special() offers some extra stuff like full text aligment which is kind of complicated and breaks up each and every character so it's still better not be messed with.

And since I mentioned it, full alignment with typewriter effect will probably not work together, so that argument is better left to false.
 

Ednei

Member
Hahhaaaa yes you are right, I'm such an idiot! Indeed you would need a modifier script, but it would be really a lot simpler than draw_text_special, since all you need to do is check the string end and backwards for symbols and append their content when necessary. draw_text_special() offers some extra stuff like full text aligment which is kind of complicated and breaks up each and every character so it's still better not be messed with.

And since I mentioned it, full alignment with typewriter effect will probably not work together, so that argument is better left to false.
Vdweller,

First of all I would like to thank you for the excellent script. The draw_text_special works perfectly for what it was proposed. If I can finish my game someday I will give you the deserved credits.

After reading everyone's posts on this topic, it seems the best solution would be this way, look at this draft:


Code:
Example : draw_text_special(10,10,"The \col{0,255,255}Scientists/ .",font0,c_white,18,250,1,spr_icon);


//CREATE

str_full = "The \col{0,255,255}Scientists/ ."

//STEP

str_part = "T"
str_part = "Th"
str_part = "The"
str_part = "The \col{0,255,255}S/ "
str_part = "The \col{0,255,255}Sc/ "
str_part = "The \col{0,255,255}Sci/ "
str_part = "The \col{0,255,255}Scien/ "
str_part = "The \col{0,255,255}Scient/ "
str_part = "The \col{0,255,255}Scienti/ "
str_part = "The \col{0,255,255}Scientis/ "
str_part = "The \col{0,255,255}Scientist/ "
str_part = "The \col{0,255,255}Scientists/ "
str_part = "The \col{0,255,255}Scientists/ ."

//DRAW

draw_text_special(10,10,str_part,font0,c_white,18,250,1,spr_icon);


I will have to write a modifier script to identify the control words and separate them so that they can be interpreted correctly by the draw_text_special script in the way written above.

It would be wonderful if there was an argument in the draw_text_special that enabled a native "typewrite" function and did all that work by simply running it in DRAW (without the need to create Alarms or Steps). But I see that this is impossible at the moment.

I'm at work at the moment But if I can write the script correctly I will post the results here.

Thank you all!
 
Top