I'm pretty sure I've seen this done in other games, so it must be doable. Basically, in the style of Zelda 1 and 2, and Castlevania 2, each string character shows one at a time.
Does anyone have any recommendations on how to implement this sort of thing?
Script for printing text one letter at a time?
Moderators: marionline, SDHawk
This problem is very programmery and organizational, so I'm sure someone else is way more qualified to handle the answer than me, but there's some basic pointers I can give.
The most important issue at the start, is how are you going to be storing your text? Zelda 1 seemed to do it on a room by room basis. It only cleared the string when a new one was drawn or when you left the room. In a game like that, you can be sloppy and just have scripts that are like..
You could do the same for Ninja Gaiden or Megaman or anything that did cutscenes that way, assuming there's not too many of 'em. Zelda 2 and Castlevania 2 were more RPG-like, and having so much text it might be obnoxious to try to store all the text in the Hss (But not impossible!) If that were the case, you might try to keep the text in the default textbox editor, but access it with something the Textboxline command like this
What these scripts are going to have in common is a way to send a certain letter from a source to a destination.
And a means to call that script many times. You could use a for loop if you wanted, but a while loop would give you more opportunities to let the player fast-forward or skip the textbox, add multiple letters (or even multiple lines) at a time for the exact effect you wanted.
I suppose if you wanted, you could just write the desired text on screen (as a string or a textslice) and then cover it with a rectangle or container slice and shrink/expand the "cover" to gradually reveal the text, but it might look weird? Again, I'm not the best person to answer this.
The most important issue at the start, is how are you going to be storing your text? Zelda 1 seemed to do it on a room by room basis. It only cleared the string when a new one was drawn or when you left the room. In a game like that, you can be sloppy and just have scripts that are like..
Code: Select all
#Dragons Room
Light Torches
Draw Dragon
String1="I am a dragon, who are you?"
FancyTextyStringyStuff (String1)
Code: Select all
Have the NPC pass the textbox he wants to show as an argument
plotscript,StealTextboxText,WhatTextbox,begin
TextboxLine (1,WhatTextbox,0)
TextboxLine (2,WhatTextbox,1)
TextboxLine (3,WhatTextbox,2)
SO ON
End
Code: Select all
script,DeliverLetter,SourceString,WhatLetter,DestinationString,begin
variable (LetterToSend)
LetterToSend := AsciiFromString (SourceString,WhatLetter)
AppendASCII (DestinationString,LetterToSend)
end
I suppose if you wanted, you could just write the desired text on screen (as a string or a textslice) and then cover it with a rectangle or container slice and shrink/expand the "cover" to gradually reveal the text, but it might look weird? Again, I'm not the best person to answer this.
Do you want a regular textbox to appear one letter at a time? Well you can always have text with no box, so I'll assume "yes". I know that Giz did it before script commands to manipulate the textbox existed, but doing it now is pretty easy actually. I'm surprised there was no script for it on the wiki yet.
Something like (untested!)
To use:
Note that the engine's builtin line-by-line fade in will still happen, but if this script works you shouldn't notice, unless maybe you have several blank/short lines at the start so that the script gets ahead of the builtin scroll-in. Despite the builtin effect, the textbox slice always contains the full text; a different mechanism is use to cause only part of the text to display, something that's currently invisible to scripts.
You should make sure the "showtextbox happens immediately" backcompat bitset is on; otherwise you would have to wait(1) before calling the script.
Something like (untested!)
Code: Select all
define constant(99, temp str)
# Shorten a string if it's longer than 'length'
script, trim string to length, str, length, begin
variable(i)
for(i, string length(str), length + 1, -1) do (delete char(str, i))
end
# This script is also the equivalent of "wait for textbox"
script, textbox letterwise reveal, letters per tick = 2, begin
variable(boxnum, txtsl, length)
txtsl := lookup slice(sl:textbox text)
if (txtsl == false) then (exit script)
boxnum := current textbox
while(boxnum == current textbox) do (
get slice text(temp str, txtsl)
trim string to length(temp str, length)
set slice text(txtsl, temp str)
length += letters per tick # keeps increasing to infinity, doesn't matter
wait(1)
)
end
Code: Select all
show textbox(1)
textbox letterwise reveal # Optionally specify a speed argument
You should make sure the "showtextbox happens immediately" backcompat bitset is on; otherwise you would have to wait(1) before calling the script.
Last edited by TMC on Thu Nov 24, 2016 12:11 pm, edited 2 times in total.
Yeah, I deliberately didn't bring that up because it was a shitshow. Every textbox in the game was stored in a single string, and when I used a textbox, it'd skip two hundred characters into that string (I had 5 rows of 40) times the argument of the NPC.TMC wrote:I know that Giz did it before script commands to manipulate the textbox existed, but doing it now is pretty easy actually. I'm surprised there was no script for it on the wiki yet.
The downside of this was that one string had to be METICULOUSLY formatted. If you fix a typo halfway through, you have to make sure you didn't add or subtract any characters, because that would throw off every other box in the game. Not a good way to do business! You can see how goofy it looked here (Why Shiz decided to use this particular textbox in the gamelisting, I'll never know)
The only piece of code I like (and mind you I still had to clean it up a ton, I was a moron 8 years ago) was the one that made text-y sounds.
Code: Select all
#What letter is the last ascii added to the string.
script,NoisyText,WhatLetter,begin
#Make no noise for space.
Switch (WhatLetter)
do (
#No sound for a space
#If the case doesn't do anything, it gets smushed in with the next one. Usually I have a script that's like "DoNothing" for situations like this, but why muddy the waters?
Case (32)
SystemYear
#Vowels play Sound 0
#Upper and Lower case covered
Case (97)
playsound (0,false,true)
Case (65)
playsound (0,false,true)
Case (101)
playsound (0,false,true)
Case (69)
playsound (0,false,true)
Case (105)
playsound (0,false,true)
Case (73)
playsound (0,false,true)
Case (111)
playsound (0,false,true)
Case (79)
playsound (0,false,true)
Case (117)
playsound (0,false,true)
Case (85)
playsound (0,false,true)
#Anything else plays Sound 1, to generate some contrast
Case (Else)
playsound (1,false,true)
)
end
# My script worked differently than TMC's so I'm not exactly sure how I'd want to trigger it from his. Maybe slip it in between like
#trim string to length(temp str, length)
#NoisyText (ASCIIFromString (TempStr,Length))
#set slice text(txtsl, temp str)
#In that while loop
Oh, I never noticed that vowels played a different sound effect (that's something really hard to notice), though I think I do vaguely remember that you used more than one sound effect, which gives a nice effect.
Giz's script is pretty easy to insert into mine, just add a line like:
after the "get slice text". That'll be silent if it hits a space even it it revealed several other characters the same tick.
(Hah, SystemYear. The way to have a case do nothing is to just write "do()" after it.)
Giz's script is pretty easy to insert into mine, just add a line like:
Code: Select all
if (string length(temp str) <= length) then (NoisyText(ascii from string(temp str, length)))
(Hah, SystemYear. The way to have a case do nothing is to just write "do()" after it.)