Internal commands

Started by Hilbert, July 28, 2012, 01:23:29 PM

Previous topic - Next topic

FIQ

That's very logical. The strings should be stored 1 time only and taken when needed.
Makes more sense if you know machine code (which I don't, so I can't explain fully).

Pyrite

how do you use these in 2.1

Dav999

Quote from: manofperson on July 29, 2012, 02:21:37 AM
how do you use these in 2.1
Quote from: FIQ on July 28, 2012, 11:06:32 PM
manofperson: By tricking the parser, the explanation is in various places in this forum, but it all boils down to this:

say(-1)
text(1,0,0,4)
say(5)
internalscript
internalscript
internalscript
internalscript
text(1,0,0,4)
say(5)
internalscript
internalscript
internalscript
internalscript
text(1,0,0,4)
say(5)
...
text(1,0,0,4)
say(5)
internalscript
internalscript
endcutscene
untilbars
loadscript(stop)

Hilbert

Quote from: Dav999 on July 28, 2012, 11:21:36 PM
It's hard to extract the full game script from the binary, because it is compressed or something. I noticed that no line of text appears twice.
For example:


squeak(terminal)
text(gray,0,0,2)
This is a
terminal!
position(center)
speak_active
squeak(terminal)
text(gray,0,0,2)
Again, this is a
terminal!
position(center)
speak_active
squeak(terminal)
text(gray,0,0,2)
And this is another
example text!
position(center)
speak_active


Would appear in the binary as something like this (I use a hex editor to read the binary):


squeak(terminal).text(gray,0,0,2).This is a.terminal!.position(center).speak_active.Again, this is a.And this is another.example text!


Lines that are used more than once just disappear the second time!
Instead of periods for dividers, I think it uses the | key

Dav999

Quote from: RoskillaHULK!! on July 29, 2012, 12:43:16 PM
Instead of periods for dividers, I think it uses the | key
That only appears in custom levels, which is why you shouldn't use ä (the | character looks like ä in the VVVVVV font). But in the real game, it uses the zeroth character, which shows up as a period:


In a text editor it will not even show anything:


So, it doesn't use | as a seperator.

Pyrite

but isn't that in 2.0? i tried using the text command it doesn't work.

Dav999

Quote from: manofperson on July 29, 2012, 03:00:55 PM
but isn't that in 2.0? i tried using the text command it doesn't work.

What do you mean by 'that'? The internal commands or | as a seperator?

FIQ

#22
The text command is (interestingly) the most complex thing to work with internally. Only use it if you must. You'll have to recreate how it's made with simple scripting, something like this can be used:

say(-1)
text(1,0,0,4)
say(5)
(do things)
text(1,0,0,4)
say(2)
squeak(cyan)
text(1,0,0,4)
say(5)
text(cyan,-1,30,1)
Test!
speak_active
endtext
text(1,0,0,4)
say(2)
squeak(cyan)
text(1,0,0,4)
say(5)
text(cyan,-1,30,1)
Test with 2
lines!
speak_active
text(1,0,0,4)
say(2)
squeak(cyan)
text(1,0,0,4)
say(5)
text(cyan,-1,30,1)
Last test!
speak_active
endtext
text(1,0,0,4)
say(5)
(more non-dialog things)
text(1,0,0,4)
say(3)
endcutscene
untilbars
loadscript(stop)

Note that the last text line *must* include endtext (it's optional otherwise), and therefore can only be 1 line max, if you're not going to exit from the internal scripting "mode". If you're fine with exiting it, you can use this (but it will make the last dialog appear in center as position(center) is inserted by the parser):

...
text(1,0,0,4)
say(5)
text(cyan,0,0,4)
The
last
text
dialog


EDIT: typos

Dav999

Internally, text boxes will look like this:

squeak(terminal)
text(gray,0,0,1)
This is a text box.
position(center)
speak_active

squeak(terminal) makes a terminal sound, text(gray,0,0,1) stores the following line of text in the memory, position(center) overrides the coordinates used in the text() command and makes sure the text box is in the center, and without speak_active nothing would show up at all: speak_active makes the text box appear.

Terry didn't have to worry about the number of lines available for commands, but if you want to use internal commands in the level editor, you have to use this:

say(-1)
text(1,0,0,4)
say(5)
[internal]
[internal]
[internal]
[internal]
text(1,0,0,4)
say(5)
[internal]
[internal]
[internal]
[internal]
text(1,0,0,4)
say(5)
Etc.

You can only use 4 lines of internal code after each other each time, so the code I showed in the beginning of this post won't fit. You have to split it up. You have to split it after squeak(terminal), because these lines:

text(gray,0,0,1)
This is a text box.
position(center)
speak_active

have to come after each other.

So you can use:

say(-1)
text(1,0,0,4)
say(2)
squeak(terminal)
text(1,0,0,4)
say(5)
text(gray,0,0,1)
This is a text box.
position(center)
speak_active
text(1,0,0,4)
say(4)
endtext
endcutscene()
untilbars()
loadscript(stop)

Now you can only have a text box with one line of text. If you omit position(center), the text box will appear at the top left corner of the screen. If you omit speak_active, no text box will appear at all. If you put these commands after text(1,0,0,4) say(5), you will see a text box with gibberish. You can omit position(center), as long as you use coordinates in the text() command to put it at the appropriate position. FIQ used 54,55 to put it in the center. If you use that, you can use two lines:

say(-1)
text(1,0,0,4)
say(2)
squeak(terminal)
text(1,0,0,4)
say(5)
text(gray,54,55,2)
This is a text box
with two lines!
speak_active
text(1,0,0,4)
say(4)
endtext
endcutscene()
untilbars()
loadscript(stop)

If you use 2.1, and only IF, you can also use this:

say(-1)
text(1,0,0,4)
say(infinite number of lines)
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
etc.

So you can use something like this:

say(-1)
text(1,0,0,4)
say(13)
squeak(terminal)
text(gray,0,0,5)
This
is a
long
text
box.
position(center)
speak_active
endtext
endcutscene()
untilbars()
loadscript(stop)

But please note that this only works with 2.1, and it will not work with 2.0!

FIQ

#24
Quote from: Dav999 on July 29, 2012, 04:25:03 PM
Internally, text boxes will look like this:

squeak(terminal)
text(gray,0,0,1)
This is a text box.
position(center)
speak_active

squeak(terminal) makes a terminal sound, text(gray,0,0,1) stores the following line of text in the memory, position(center) overrides the coordinates used in the text() command and makes sure the text box is in the center, and without speak_active nothing would show up at all: speak_active makes the text box appear.

Terry didn't have to worry about the number of lines available for commands, but if you want to use internal commands in the level editor, you have to use this:

say(-1)
text(1,0,0,4)
say(5)
[internal]
[internal]
[internal]
[internal]
text(1,0,0,4)
say(5)
[internal]
[internal]
[internal]
[internal]
text(1,0,0,4)
say(5)
Etc.

You can only use 4 lines of internal code after each other each time, so the code I showed in the beginning of this post won't fit. You have to split it up. You have to split it after squeak(terminal), because these lines:

text(gray,0,0,1)
This is a text box.
position(center)
speak_active

have to come after each other.

So you can use:

say(-1)
text(1,0,0,4)
say(2)
squeak(terminal)
text(1,0,0,4)
say(5)
text(gray,0,0,1)
This is a text box.
position(center)
speak_active
text(1,0,0,4)
say(4)
endtext
endcutscene()
untilbars()
loadscript(stop)

Now you can only have a text box with one line of text. If you omit position(center), the text box will appear at the top left corner of the screen. If you omit speak_active, no text box will appear at all. If you put these commands after text(1,0,0,4) say(5), you will see a text box with gibberish. You can omit position(center), as long as you use coordinates in the text() command to put it at the appropriate position. FIQ used 54,55 to put it in the center. If you use that, you can use two lines:

say(-1)
text(1,0,0,4)
say(2)
squeak(terminal)
text(1,0,0,4)
say(5)
text(gray,54,55,2)
This is a text box
with two lines!
speak_active
text(1,0,0,4)
say(4)
endtext
endcutscene()
untilbars()
loadscript(stop)

If you use 2.1, and only IF, you can also use this:

say(-1)
text(1,0,0,4)
say(infinite number of lines)
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
etc.

So you can use something like this:

say(-1)
text(1,0,0,4)
say(13)
squeak(terminal)
text(gray,0,0,5)
This
is a
long
text
box.
position(center)
speak_active
endtext
endcutscene()
untilbars()
loadscript(stop)

But please note that this only works with 2.1, and it will not work with 2.0!
A thing I noticed way after using 54,55 is that you can, in fact, make it in center in the x axis (<---->) by using -1 as coordinate, i.e. text(cyan,-1,55,1). This will always be at center, no matter how long the text string is, so no need to calculate that.

Also, as I said before, you MUST have endtext at the last textbox that will appear in your script, or the textbox will not go away.

FIQ

#25
The simplified -> internal scripting conversions, if anyone wonders (most useful if you want to utilize them in internal scripts as they work normally): ("|" means >1 line).

Simplified: Internal
ifflag(N,script): customifflag(N,script)
iftrinkets(N,script): customiftrinkets(N,script)
iftrinketless(N,script): customiftrinketless(N,script)
delay(N): delay(N)
destroy(x): destroy(x)
map(on/off): map(on/off)
flag(N,on/off): flag(N,on/off)
flash: flash(5)|playef(9)|shake(20)
happy: squeak(cyan)|changemood(player,0)
happy(crewmate/colour): squeak(colour)|changemood(colour,0)
sad: squeak(cry)|changemood(player,1)
sad(crewmate/colour): squeak(cry)|changemood(colour,1)
squeak(crewmate/colour): squeak(colour)
music(N):
The following conversion will be made if possible:
0->stopmusic()
1->play(1)
2->play(2)
3->play(3)
4->play(4)
5->play(6)
6->play(8)
7->play(10)
8->play(11)
9->play(12)
10->play(13)
11->play(14)
other->play(other) (This is why music(0a), for example, works)

say(1)|hi: squeak(terminal)|text(terminal,0,0,1)|hi|customposition(center)|speak_active|endtext
reply(1)|hi: squeak(cyan)|text(cyan,0,0,1)|hi|customposition(player,above)|speak_active|endtext
say(1,crewmate/colour)|hi: squeak(colour)|text(colour,0,0,1)|hi|customposition(colour,above)|speak_active|endtext

Also, the parser will first scan the script "file" before any execution for say()/reply() lines. If it finds any, the following will be altered:

cutscene()
untilbars()
(THE SCRIPT)
endcutscene()
untilbars()

This is why the internal scripting exploit always turn on these, and this is why checking flags to stop a script containing say()/reply() scripts is a bad idea and will make cutscenebars stuck.

Dav999

#26
Quote from: FIQ on July 29, 2012, 08:03:21 PM
say(1)|hi: squeak(terminal)|text(terminal,0,0,1)|hi|customposition(center)|speak_active|endtext
reply(1)|hi: squeak(cyan)|text(cyan,0,0,1)|hi|customposition(player,above)|speak_active|endtext
say(1,crewmate/colour)|hi: squeak(colour)|text(colour,0,0,1)|hi|customposition(colour,above)|speak_active|endtext

What is the difference between position(x) and customposition(x)? I don't think it converts to customposition, because if I run this script in 2.0:


say(6)
This
is a
text
box with
six
lines.
say(2)
This is a text
box with two lines.


I get a text box with:


This
position(center)
speak_active
squeak(terminal)
text(gray,0,114,2)
This is a text


Which is the proof it converts to position(). Also if I make a text box using internal script, and if I use customposition(center), it doesn't work. In that case it works with the coordinates specified in text().
Also, I didn't find a single customposition in the binary!

Quote from: FIQ on July 29, 2012, 07:40:38 PM
A thing I noticed way after using 54,55 is that you can, in fact, make it in center in the x axis (<---->) by using -1 as coordinate, i.e. text(cyan,-1,55,1). This will always be at center, no matter how long the text string is, so no need to calculate that.

Nicely found! Also, if you use text(colour,-1,-1,lines), it replaces position(centerx).

blue626

#27
Quote from: Dav999 on July 29, 2012, 04:25:03 PM
If you use 2.1, and only IF, you can also use this:

say(-1)
text(1,0,0,4)
say(infinite number of lines)
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
[internal]
etc.

So you can use something like this:

say(-1)
text(1,0,0,4)
say(13)
squeak(terminal)
text(gray,0,0,5)
This
is a
long
text
box.
position(center)
speak_active
endtext
endcutscene()
untilbars()
loadscript(stop)

But please note that this only works with 2.1, and it will not work with 2.0!

If you read the 1st post in the "Script commands index and tips" thread, you'll see that in say/reply(n), n can be only 1-11, so, say(13) won't work. say(13) = text box with 5 lines, so, say(11) = text box with 3 lines. If you want text boxes (using internal scripting) with more than 3 lines, you have to split the internal commands (using more say(-1) and text(1,0,0,4) commands).

EDIT: Looking at the posts above, where Dav999 and FIQ wrote examples of how to use internal scripting, and reading what Dav999 wrote about the command text, I don't see why do you have to use text(1,0,0,4) sometimes. I also don't see why you'll need say(-1) at the start. Look at the example below, specially, at the 1st line:

text(1,0,0,1)
say(5)
Internal scripting
Internal scripting
Internal scripting
Internal scripting
Internal scripting


Wouldn't it work? If not, would it work if I replaced the 1st line with text(1,0,0,4), or if I wrote say(-1) before the 1st line?

EDIT 2: I know why you need say(-1) now (because the editor would erase the text command if this command wasn't written, am I right?). I still don't know why do you need to use text(1,0,0,4).

Dav999

Quote from: blue626 on July 29, 2012, 10:25:25 PM
If you read the 1st post in the "Script commands index and tips" thread, you'll see that in say/reply(n), n can be only 1-11, so, say(13) won't work. say(13) = text box with 5 lines, so, say(11) = text box with 3 lines. If you want text boxes (using internal scripting) with more than 3 lines, you have to split the internal commands (using more say(-1) and text(1,0,0,4) commands).

It can't produce a text box longer than 11 lines, but it can be used to accept an unlimited number of internal commands (I've seen custom levels which used say(33), and this will work in 2.1, but not in 2.0)

Quote from: blue626 on July 29, 2012, 10:25:25 PM
EDIT: Looking at the posts above, where Dav999 and FIQ wrote examples of how to use internal scripting, and reading what Dav999 wrote about the command text, I don't see why do you have to use text(1,0,0,4) sometimes. I also don't see why you'll need say(-1) at the start. Look at the example below, specially, at the 1st line:

text(1,0,0,1)
say(5)
Internal scripting
Internal scripting
Internal scripting
Internal scripting
Internal scripting


Wouldn't it work? If not, would it work if I replaced the 1st line with text(1,0,0,4), or if I wrote say(-1) before the 1st line?

EDIT 2: I know why you need say(-1) now (because the editor would erase the text command if this command wasn't written, am I right?). I still don't know why do you need to use text(1,0,0,4).

I also don't know why there has to be text(1,0,0,4). I can't see the logic of taking 4 lines below it, but yeah. It works. :P

You don't have to use squeak(), position(), speak_active, endtext, endcutscene(), untilbars() and loadscript(stop), if you use the say(-1) trick again for every dialog you want to have coloured:

say(-1)
text(1,0,0,4)
say(5)
text(red,0,0,4)
This can
contain
four
lines!

Will create a red text box in the middle of the screen, and instead of say(), you can also use reply() to make a text box appear above :viridian:

reply(-1)
text(1,0,0,4)
reply(3)
text(yellow,0,0,2)
This box is yellow, but will
appear above the player!

This works because position() and speak_active are already part of the say(5) command or reply(5) command, whichever you use.

And you can just use the remaining space for other internal commands, or to extend it using text(1,0,0,4) say(5). That way, not everything has to be internal code.

FIQ

Because you want to overwrite 4 lines below. Let me show why:
You're using this, for example, to write a custom command (I only use the things absolutely necessary to show why it has to be used:

say(-1)
text(1,0,0,4)
say(3)
endcutscene()
untilbars()
loadscript(stop)

This is converted to (with "# text" telling what the parser does, "// text" tells what really happens):
cutscene() # It found a say() or reply() command // insert cutscenebars
untilbars() # Therefore, these are inserted // wait for cutscenebars to be inserted
squeak(terminal) # It found say(-1), insert before-dialog stuff // terminal sound
text(gray,0,114,-1) # The say() in itself is converted to this. The parser think it will be a 1-line dialog. // does nothing
text(1,0,0,4) # Believed to be part of dialog // Start a text dialog of 4 lines
customposition(center) # End of say(-1) // Part of text dialog, therefore not executed
speak_active # Print the dialog of say(-1) // Part of text dialog, therefore not executed
squeak(terminal) # It found say(3) // Part of text dialog, therefore not executed
text(gray,0,114,3) # Print a dialog with 3 lines // Part of text dialog, therefore not executed
endcutscene() # Believed to be part of dialog // End cutscene
untilbars() # Believed to be part of dialog // Wait until bars are gone
loadscript(stop) # Believed to be part of dialog // Stop the script (If this isn't used, a dialog will be created, see below for content)
customposition(center) # End of say(3) // Not executed
speak_active # Print the dialog of say(3) // Not executed
endtext # Ends all text dialogs // Not executed
endcutscene() # End cutscene // Not executed
untilbars() # Wait until bars are gone // Not executed


If loadscript(stop) isn't used, the script will continue - and therefore write the content of our text(1,0,0,4) command (as we didn't use other dialogs), which will be:

customposition(center)
speak_active
squeak(terminal)
text(gray,0,114,3)


Dav999: In 2.0, you couldn't use say()/reply() to get the dialogs of other crewmates. This works in 2.1. As crewmate are handled in another way in custom levels than in the main game, a "new" position command has to be created to position it accordingly to these. So in 2.0, position(center) is what say()/reply() will make, in 2.1, it's named customposition().