Advanced DragonSpeak Reference

So, you've been digging around the website to learn all the tips, tricks, and tools to make your own Dream be as unique and awesome as possible, and you've finally arrived at at the Advanced DS reference! Yes, this is quite a huge page, but it does cover a lot of the more advanced aspects of DragonSpeak that can be used to your advantage! Specifically you'll find all the nuts and bolts about many of the lesser used aspects of DS, including usage, limitations, and quirks of variables, strings, regions, PhoenixSpeak, arrays, DS buttons, and more!

If you're new to DragonSpeak, or just want more of an overview first, please check out the Beginning DragonSpeak tutorial first. There's also an Intermediate DragonSpeak tutorial to follow, once you've gotten the overview down, and then even the DragonSpeak Reference page which covers how DS works as a whole and in much more broader terms than anything in this page.

All of those pages should be thoroughly learned and experimented with downpat before you'll ever need to dive into anything here. In fact, you could make very complex DragonSpeak for any Dream without ever needing to understand anything on this page! But, we made this page anyway for the hardcore scripters out there. Enjoy, fuzzballs!

Note that for many of the topics mentioned here, there are both alternate pages that cover the overview and beginning tutorials, and then also specific tutorials are included here to help explain many of the concepts more concretely.


Variables

If you're not sure what variables are, there's a great overview and tutorial about them called Introduction to Variables. The following has more detailed information about them as a reference for you!

Broadly speaking, variables are integer values that are represented by a string of text beginning with the symbol %. For instance, %JoesHotdogs is a variable, and so is %amountofbones. Variables like these can be used almost anywhere in DS where a number is expected.

Variables open up new possibilities in DS manipulation because they're dynamic. They can be used for multiple DS triggers as they are able to keep their values, or they could be used for grabbing data from the map or from a string or PhoenixSpeak entry (more on that later) without having to use DS triggers that scan for every possible range of values.

Naming

Variables are able to contain characters A-z (upper and lower case), 0-9, and underscores. They are case sensitive. For instance:

%Test is not the same as %test

%Test_variable is a valid name

The Limits

At the time of writing, DragonSpeak variables can handle numbers ranging from -32768 to +32767. If you try to execute an operation that would throw these numbers out of range, the result may be unexpected.

For example, if you add 1 to +32767, it would roll over to -32768. Conversely, if you subtract 1 from -32768, it would roll over to +32767. Think of it as a number wheel with values -32768 to +32767.

As stated earlier, variables are named and identified by the percent sign (%) in front of a word. The names are case sensitive, and allows character A-z, 0-9, and underscores.

You are allowed up to 500 numerical variables, and each variable can hold two integers (for map coordinates). That gives a total of 1000 integers that could be stored into variables.

By default, unless the variable is being used for coordinates, or being copied, it will always behave as though the .x value is being referenced unless specified. How do we access the second integer? We add a .y to the end of the variable being used.

These two lines do the same thing:

  (5:300) set variable %test to the value 2.
(5:300) set variable %test.x to the value 2.

To use the other half of the variable, simply set the .y coordinate to a value:

  (5:300) set variable %test.y to the value 4.

You can manually set both values in the variable by using this line as well:

  (5:384) set variable %test to the x,y position (2,4).

If variable %test was treated as a coordinate, it would be recognized as position (2,4) on the map. Coordinates aren’t the only way to utilize this, but it is the most basic.

When emitting coordinate variables, it’s important to append the .x and .y modifiers, or you’ll only see the x coordinate returned.

For example, if you use this emit without the .x and .y:

  (5:200) emit message {You are at position %test} to the triggering player.

[♦] You are at position 2

It's not a coordinate -- only half of one. You get the x value alone.

If you instead use:

  (5:200) emit message {You are at position %test.x, %test.y} to the triggering player. 
[♦] You are at position 2, 4

It’s also worth noting that variables can be preceded by characters, but cannot be followed by any additional characters except for .x or .y (i.e: you cannot append characters immediately following a variable). For example:

A valid variable reference:

  (5:632) forget the PhoenixSpeak info {button%buttonNum} about this Dream.

This is valid because the variable name %buttonNum is still being recognized properly by the DS parser. The word ‘button’ does not affect the variable name at all.

An invalid variable reference:

  (5:632) forget the PhoenixSpeak info {%buttonNumbutton} about this Dream.

This is invalid because the parser will try to read %buttonNumbutton as a variable instead of just %buttonNum.

Note: This limitation is not true of strings, which are able to be immediately preceded or followed by characters, as long as any character following the string is not valid as part of a string name (e.g: !, @, #, $, ^, &, *, (, ), <, >, etc.).

For example, if you used ~PlayerName as a string and insert it anywhere in DS that takes text input, you can add characters before or after the string name and the parser will still recognize it properly. In other words, DS will still recognize Hello!~PlayerName and ~PlayerName! as just ~PlayerName by the parser.

The (5:301) DragonSpeak Line

There is a variable-related DS line that works a bit differently than one might expect, and it has a limitation that prevents it from working in certain circumstances:

  (5:301) copy the value of variable % into variable %.

By default, this lets you copy both of a variable's values, including even unused .y values (it sets the receiving variable’s .y value to 0) into another variable, like this:

  (5:301) copy the value of variable %var1 into variable %var2.

Using .x and .y in the first space works, but if you use it in the second space, it will cause unexpected behavior to occur. Here's how it works correctly:

  (5:301) copy the value of variable %var1.x into variable %var2.
  (5:301) copy the value of variable %var1.y into variable %var2.

But what if you need to copy .y of the first variable into .x of the second variable? Though it won't work with (5:301), you can work around this with (5:300). Here's an example:

  (5:300) set variable %var2.y to the value %var1.x.
(5:300) set variable %var2.x to the value %var1.y.

The line (5:384) may also be useful here. Here’s an example:

  (5:384) set variable %var2 to the x,y position (%var1.y, %var1.x).

Debugging

If you use DragonSpeak Constructor, you can review all your variables through the Variable Information dialog, available under the Tools menu. Clicking Refresh will scan the lines of DS in the active section and summarize how many variables and strings that are in use, and where.

This can help you know if you are over the limit for variables, or if you are using different variables across sections of your DS (remember, case sensitive)! You may find that you can consolidate variables that represent the same thing.

Summary

To summarize, variables:

  • can replace numbers in almost all instances of DragonSpeak where a number is required in a line
  • are capable of storing integers (no decimal points) ranging from -32768 to +32767
  • are named by adding the % symbol before a string of text
    • Names are case sensitive, and can consist of letters A-z, 0-9, and underscores
  • can be reviewed from the Variable Information dialog
    • Dreams are limited to 500 unique variables
  • are capable of storing two integers each by appending .x or .y to the end of a variable name. This means in essence, a total of 1000 integers

Entry Codes

In DragonSpeak, an entry code is a number that is automatically assigned to every player that arrives in a Dream, which is where the term entry comes from. This means that this particular number will be directly associated with a player, establishing a clear distinction between an entry code and a variable (mentioned above), which has a value that is non-player-specific.

The value of a player's entry code is temporary and only exists so long as that person is still in the Dream. In other words, the entry code information for that player is lost once that player departs from the Dream, making the value of entry codes non-persistent.

How are entry codes assigned?

As the name implies, a player’s entry code is assigned upon their entry into the Dream, however, it is important to emphasize that entry codes have no relation with the entry method DS lines shown below:

  (1:91) and their entry method was # (One=Dream portal, Two=summoned in, Three=Dream url),
(1:191) and their entry method was not # (One=Dream portal, Two=summoned in, Three=Dream url),

By default, a player’s entry code is automatically assigned the value 0 irrespective of their method of entry into the Dream.

There is an exception to this, however: players can access a Dream through its Furcadia DreamURL with any desired entry code appended at the end, and then they will have that entry code assigned to themselves.

Here is an example:

furc://FurreName:DreamName/42

If someone types out that URL with the /42 at the end and clicks on it, that player will give themselves the entry code 42. In other words, this means it is possible for any player to assign themselves an entry code of their choosing without restrictions.

Tutorial 1: Giving your players a special entrance

One example usage of entry codes would be to provide a special place for any players to arrive. You can give them a particular Furcadia DreamURL with a specific entry-code to let them get there.

Read more: Entry Codes Tutorial 1: Giving a special entrance

Tutorial 2: Setting up access levels for staff

You can use entry codes to set up simple staff access levels! After all, being a Rah of your own Dream can be tiring -- this way you can make sure only the people you trust and who have been proven to be responsible will have certain abilities. These extra awesome people we will call our Senior Staff. The newer staff we have will be Junior Staff: we want them to have some special abilities, but maybe not all of them. They need to earn their rank after all!

To do this, we need to make sure only certain people will be able to use special commands, even if they are all staff members. For this example we'll give all our staff members, both junior and senior, the ability to make an announcement, but then restrict one other command to only more senior staff: turning on and off the ability for visitors to use swear words.

Read more: Entry Codes Tutorial 2: Setting up access levels

The Limits

Entry codes support the use of integers ranging from -32768 to 32767 as their value. Negative numbers can only be given to a player through the use of the (5:316) DragonSpeak line.

Note, however, that negative numbers cannot be assigned to entry codes through a Furcadia DreamURL. Any attempts to do so will result in the - symbol being ignored and the arriving player being assigned the positive counterpart of the number as their entry code instead.

Summary

To summarize, entry codes:

  • are specific to individual players, but are lost for that player once they leave the Dream
  • support integers (without decimal point) ranging from -32768 to 32767
  • can be self-assigned by a player through the use of a Furcadia DreamURL (supporting only positive integers)
  • can be assigned to a player that is already in the Dream through the use of the (5:316) DragonSpeak line (which support both positive and negative integers)

Regions

You can check through the How to use Regions tutorial first if you want a big overview! Though that tutorial covers basic usage of regions, there are almost endless other ways to use regions to your advantage. The advantage regions have over the other map layers like floors, items, and effects, is the fact that they're completely invisible and never overwrite the other layers.

While there are many ways to utilize regions, we'll only be covering one in this reference.

Tutorial 1: Forcefield

Regions are powerful, and why not show it! You could even use regions to track players' movements. For instance, let's say your Dream is anticipating the arrival of a very infamous individual known as Ms. Agatha Frumpybottoms. There's only one issue though... this woman is a high school principal with very low tolerance for riff raff, and therefore exudes an aura that makes everyone around her shiver. Wouldn’t it be cool to make a special set of triggers that make it so the other students will actively avoid approaching her? We'll showcase how to do this with region DS by creating a force field of space around Principal Frumpybottoms that others cannot enter. The principal, however, will still be able to move up to others.

Read more: Regions Tutorial: Forcefield

The Limits

There are 40,000 regions available, however in the Dream Editor, they are not visually numbered in sequence after the first 200. For instance, region 201 in the Dream Editor visually is represented as region 1, even though it really is 201.

You can use regions for indoors/outdoor DS and you can use regions for miscellaneous other reasons... but you may run into a problem with trying to use both methods at the same time. In some instances you can’t. When you can, you will likely be restricted to regions for outdoor use only. This is because indoor regions hide items and objects making it difficult to add interactive DS to them.


PhoenixSpeak Manipulation

If you're not familiar with PhoenixSpeak, the overview of PhoenixSpeak covers the general usage and lists out all the params. Read that before going through this section!

Database structure

As mentioned in the PhoenixSpeak overview, the structure of a Dream’s PhoenixSpeak database can be best explained as being divided into Tables, Rows and Entries. The table is the biggest part of the database; it's the overlying structure that all the data is in. PS automatically comes with two tables by default, the Dream table, and character table. Later on in this reference page, how to make more custom tables is presented.

So, inside the table, you can add rows in it, which are the next way to subdivide. Finally, there's the individual entries that are in each row.

For instance, this entire box is a representation of a table:

Table of Mysterious Rows and Entries

Row 1

Entry 1. Each row can have as many entries as it needs.

Entry 2, plain and simple.

See, row 1 has a third entry.

Row 2

These are row 2's entries.

Row 2 could have 20 entries if it wanted, but then we would run out of room on the webpage.

Row 3

Row 3 has only this entry.

Entries and rows

The smallest yet most common unit within a PhoenixSpeak Database is the entry.

Entries can contain either text or numbers, and even be used to convert data freely between both types. This makes them the PhoenixSpeak equivalent of variables as well as strings. Here is an example:

We can set PS info to be a string of text, but use numbers as the data:

(5:605) memorize that the PhoenixSpeak info {Text to number} about this Dream will now be {1234}.

We can then grab the same PS info as a variable, so if we emit the value as a result, we’d end up with the number:

(5:612) remember the PhoenixSpeak info {Text to number} about this Dream, and put it in variable %result.
(5:200) emit message {The result is %result} to the triggering player.

For this, the result would be 1234.

Rows are subsections of tables that allow for a greater degree of control as well as organization of the data within it.

Tables

Think of tables as a sort of dictionary that you can read and write data to that will not be erased when the Dream is reuploaded (unlike entry codes, variables, and strings, which are erased upon reupload). The name of the dictionary itself would be the name of the table.

By default, PhoenixSpeak caters for two predefined tables (or dictionaries in our metaphorical example) and has Dragonspeak lines to handle those properly. However, you can still manually create and use custom tables to an extent, but we’ll get to that later. First let's look at the two default tables: the Dream and the Character tables.

Dream table

Think of the Dream table as a dictionary that can have multiple words defined on the pages, but only ever lists just one definition per word. The Dream table is therefore not as flexible as the character tables (we will get to that later) but it does have its own purposes. For this example, let’s treat the Dream table as an actual dictionary, and try to define the word lie using it:

(5:605) memorize that the PhoenixSpeak info {lie} about this Dream will now be {to be in a horizontal or resting position on a supporting surface.}.

We can only store one definition of the word using the Dream table, unless we add more text to the word itself. This might not seem very useful at first, but it uses slightly less data than the character table would have since it didn’t dedicate an entire page to just that single word.

As mentioned under Maintenance Commands in the PhoenixSpeak overview, there are many commands Dream Owners can use. We can take a closer look at the entry we just made in the Dream table through the use of the ps get command:

ps get dream

PS Ok: get: result: lie='to be in a horizontal or resting position on a supporting surface.'

Visually, this is what our current Dream table would look like as our dictionary:

DREAM TABLE

Definition (Entry 1)

lie

to be in a horizontal or resting position on a supporting surface.

Character Table

In our previous example, we showed that the Dream table can only store one definition per word. In other words, it can store only one entry per row. We can also continue this metaphor by thinking of the character table as a sort of dictionary that has one word per page, but the page can fit as many definitions of the word as will fit on that page (it's limited in memory).

So, let's define the word lie by giving it two definitions:

(5:604) memorize that the PhoenixSpeak info {definition 1} about the furre named {lie} will now be {to be in a horizontal or resting position on a supporting surface.}.

(5:604) memorize that the PhoenixSpeak info {definition 2} about the furre named {lie} will now be {an intentionally false statement.}.

Visually, this is what our current character table would look like as a dictionary:

CHARACTER TABLE

Definition 1 (Entry 1)

Definition 2 (Entry 2)

lie

to be in a horizontal or resting position on a supporting surface.

an intentionally false statement.

We can take a closer look at this through the use of the ps get command once again for the character table, specifically at the row called lie:

ps get character[ ‘lie’ ]: 1

PS Ok: get: result: 1='to be in a horizontal or resting position on a supporting surface.'

ps get character[ ‘lie’ ]: 2

PS Ok: get: result: 2='an intentionally false statement.'

Or you can grab all of the definitions at once by looking up the row name:

ps get character[‘lie’]

PS Ok: get: result: 1='to be in a horizontal or resting position on a supporting surface.', 2='an intentionally false statement.'

So, the character table is mostly used for storing individual player stats (but there are other uses, mentioned later), where an entire page is dedicated to a specific person. We’ll call each person’s page a row. Every player can get their own row in the character table, and the row is named after the player's own name.

It is also worth noting that the character table is special because the amount of rows that may be contained within it is limited.

All Dreams have a certain amount of data available to use for free, but your Dream can have more space if you have a Group Package. So, the amount of data you can have is dependant on the type of Group Package your Dream has. You can read more about the limits on the Group Packages page!

Tutorial 1: Manipulating PS for a stamina system

So far we've shown how PS can be written to, and read, but not how to manipulate any data. There are specific ways to do that! Let's say we want to to limit how many tiles a player can move before needing to rest for a certain amount of time. We can use PS to keep track of a player's stamina.

Read more: PhoenixSpeak Tutorial 1: Stamina System

Tutorial 2: Custom tables

For most ends and purposes, the default character and Dream tables are more than sufficient, but on the other hand it's good to know that it's also possible to create your own custom tables with the ps set command. This way you can make things like a database of important NPC’s in your Dream with descriptions about them, stats, inventory, as well as other bits and entries of information about them!

Using custom tables also allows you to set up information you'd want to use in your Dream manually without wasting any DS lines (since strings and arrays/variables are each limited to only 500 total per Dream, whereas PS is only limited by total memory used, rather than length/number). Plus, any information you set up in your database will stay when the Dream is reuploaded.

Read more: PhoenixSpeak Tutorial 2: Custom Tables

The ins and outs of using $

Just like we can use % to mention a variable, and ~ to mention a string, we can also mention a PS entry within any type of text {...} field in a DS line if we use $ before the entry name.

Usually you have to first remember (load) the value of a PS entry into a string, and then use that string in order to emit the value. However, if we instead use the $ symbol, we can actually save a step (and extra DS lines) by bypassing the remembering (loading) step!

There are many, many ways you can use and integrate $ into your DS. We'll break it down by examining how it works in the Dream table versus the Character table, then look at some of the other uses, and finally we'll also show you handy tricks!

Dream table $

The Dream table (which consists of the table itself and entries contained within it directly, no rows) uses the following syntax:

$tablename.entryname

But what does that look like in practice? We'll give a simple example of how to reference the Dream table using $.

Read more: PhoenixSpeak Tutorial 3: Dream table $

Character table $

So, what about if we want to use $ to call the value of an entry that resides within a row that is part of a table, such as the character table? The syntax is similar, except for that the row’s name appears before the name of the entry:

$tablename.rowname.entryname

Within the character table, all of the rows contained within it are named after players. That's why we used Joey as the row name parameter in our $ PhoenixSpeak entry in following example:

Read more: PhoenixSpeak Tutorial 4: Character table $

PS Tables Syntax Reference

Dream Table:

$dream.entryname

Character Table:

$character.furrename.entryname

Custom Table:

$tablename.entryname

$tablename.rowname.entryname

Ways to use $ with dynamic text

You can also use $ to substitute the names of the elements with a variable, a string or a special text replacement string. This way you can capture lots of moving information and match it with your Dream's database! Check out the following tutorials to see this in depth.

Tutorial 5: Partial substitution example

There are many valid reasons to use substitution in DS, as it can be useful for many things. For starters, you could do something as simple as giving an item number a description in your Dream through PS. The description could post to a player when they bump into it (The PS entry may look like this {%item_bumped description} = 'This is my description!').

You can also use substitution for something like when NPCs change locations. You could, in this situation, add coordinate prefixes to the NPC's PS info (for example {%npc_location.x %npc_location.y Health}).

In the NPC example, we're using %npc_location as a variable to dynamically grab data from PS info (this is partial substitution), based on the coordinate of the map. This is done instead of checking all the locations of the map by hard coding each possible tile in the Dream. (And in any case, this wouldn't be possible anyway, as a 200x200 map has ~40k tiles alone, which is way beyond DS line limitation).

Imagine if you had to write DS to detect all possible coordinates and items in your Dream! The example below will show you how to use partial substitution in a similar manner as the examples above.

Read more: PhoenixSpeak Tutorial 5: Partial Substitution

Tutorial 6: PS entry browser

To put it all together, let's take a look at how one might see all the pieces of $ substitution used in one set of triggers. We'll make a PS entry browser to look at what's in the database as our example.

Read more: PhoenixSpeak Tutorial 6: PS entry browser

$ Substitution Syntax Reference:

Total Substitution:

$[PARAM1].[PARAM2]

$[PARAM1].[PARAM2].[PARAM3]

$~StringA.~StringB

$~StringA.~StringB.~StringC

$%VariableA.%VariableB

$%VariableA.%VariableB.%VariableC

Partial Substitution:

$Table_[PARAM1].Entry_[PARAM2]

$Table_[PARAM1].Row_[PARAM2].Entry_[PARAM3]

$Table_~StringA.Entry_~StringB

$Table_~StringA.Row_~StringB.Entry_~StringC

$Table_%VariableA.Entry_%VariableB

$Table_%VariableA.Row_%VariableB.Entry_%VariableC

Tutorial 7: Making a command usage monitor

Let's imagine you’re the owner of a Dream with lots of commands available, and so you would like to keep track of their usage statistics. To learn which ones are the most popular, you decide to keep track of how many times every command has been used.

Without the use of dynamic text substitution, you would have to create a single trigger for every possible command in your Dream, because each one has a different name than the other. But if we substitute the name of every PS entry with a special text replacement keyword, we can generate names that correspond to the current text held within that keyword. Here's how:

Read more: PhoenixSpeak Tutorial 7: Command usage monitor

Tutorial 8: Permanent daily visit counter

Let's say you want a permanent record of the amount of visits your Dream gets daily. This can be useful for giving you an idea of how popular your Dream is, and for scoping out good upload locations. (Because, let's face it, Dream owners have busy lives and can’t keep an eye on their Dream 24/7!) But the problem is, it'd be preferable to not have to reupload the Dream every day, or manually reset variables and strings just to keep track of daily values. The next tutorial will show you how to use PS in conjunction with DS parameters to automatically handle visit counts daily, and store those counts permanently.

Read more: PhoenixSpeak Tutorial 8: Permanent daily visit counter

DS Line Syntax Reference

Total Substitution:

(5:602) memorize that the PhoenixSpeak info {[PARAM1]} about this Dream will now be #.

(5:602) memorize that the PhoenixSpeak info {~String} about this Dream will now be #.

(5:602) memorize that the PhoenixSpeak info {%Variable} about this Dream will now be #.

(5:602) memorize that the PhoenixSpeak info {$dream.entry} about this Dream will now be #.

Partial Substitution:

(5:602) memorize that the PhoenixSpeak info {Entry_[PARAM1]} about this Dream will now be #.

(5:602) memorize that the PhoenixSpeak info {Entry_~String} about this Dream will now be #.

(5:602) memorize that the PhoenixSpeak info {Entry_%Variable} about this Dream will now be #.

(5:602) memorize that the PhoenixSpeak info {Entry_$dream.entry} about this Dream will now be #.

Substituting the furre name field dynamically

Naturally, you can also use this concept with Furre Name fields of DS that deal with the character table, too!

Tutorial 9: Player PS checker

The default PS maintenance commands can sometimes be intimidating for Dream owners to use, and more importantly, many people might prefer to only give certain people in their Dream the ability to view PS data, without giving them PS access to all of your Dreams. In this situation, there's actually a way to mimic the ps get maintenance command by, instead, using total substitution in the DS lines.

Total substitution is similar to partial substitution, except it gives complete dynamic control over data to manipulate it, without needing any hard coded prefixes or suffixes. The following example gives a simple demonstration of what total substitution is capable of.

Read more: PhoenixSpeak Tutorial 9: Player PS checker

Tutorial 11: Converting text based numbers to numerical with PS

Finally, we'll end with a most obscure property of PhoenixSpeak! Anywhere in DS where it has a # symbol requires a number or variable, so if you're including numbers in your strings, the DS lines won't always work if you're wanting the string to represent a variable.

This is where PS can save lives! PhoenixSpeak gives you the ability to convert numbers introduced into an entry in textual form (through a string, a special text replacement string or a PS entry called through $) into, instead, a numerical form that is extractable into a variable.

Read more: PhoenixSpeak Tutorial 11: Convert text numbers to numerical


Arrays

Learn here how to use arrays to your advantage! Arrays give sequential order to an otherwise disorganized set of data for simpler DS manipulation. For example, if you have a playlist of songs for your Dream, but the music files are all out of order (m4, m72, m2, m34, m16, etc), or you have an NPC in your Dream that gives a random statement when bumped, arrays can be useful here to not only organize your data effectively, but also will allow you to accomplish your goal using less DS lines.

What is an array?

An array is a type of variable or string that orders multiple numbers (variables) or pieces of text (strings) within itself. They can do the same thing as variables and strings, but they have a lot of uses beyond that, as you'll see here!

How is an array set up?

Before you start, an array has to be set up first. You can use the (5:276) line to set up arrays that use strings, and (5:311) for arrays that use variables.

(5:276) use message ~StringArray[5] as an array, and set entry 0 of it to {First Entry.}.
(5:311) use variable %NumericalArray[5] as an array, and set entry 0 of it to 1.

Array size and entries

Here is each element one by one! We'll use the following as our example:

(5:276) use message ~StringArray[5] as an array, and set entry 0 of it to {First Entry.}.
(5:311) use variable %NumericalArray[5] as an array, and set entry 0 of it to 1.

The first thing to decide is how big you need your array to be, as they can only hold a set number of entries, and however many you decide to use has to be declared when the array is first added to the DS. So, in both examples, we made 2 arrays, one called ~StringArray and the other %NumericalArray. Each have 5 entries within themselves.

Note: Array sizes can't be initialized by variables. In other words, %NumericalArray[%Size] or ~StringArray[%Size] may not be used. This not only will mess up your arrays, but also count towards your variable/string limits.

It's only necessary to set the size of the array during the very first time the array appears in the DS, so you don't have to keep defining it over and over again.

Each entry within an array of either type can work just like regular strings or variables, only now they're organized! But, of course, there is a catch, too. Every entry you add to an array does also count towards the total limit of strings and variables in the Dream.

Array entries and their properties

Now we will look at setting entries:

(5:276) use message ~StringArray[5] as an array, and set entry0 of it to {First Entry}.
(5:311) use variable %NumericalArray[5] as an array, and set entry 0 of it to 1.

This tells which entry you are introducing data into. In the example, we are setting the very first entry (index number 0) to be First Entry in ~StringArray and then in %NumericalArray we set the first one to be 1.

As you'll notice, arrays start at 0! This is because entry 0 is also a valid entry. In other words, in our examples, ~StringArray has entries 0 through to 4 within itself, and so does %NumericalArray.

One of the most useful aspects to arrays is that entries also accept variables! For example, let's say we have a variable called %TheAmigos that holds the number 3 within itself:

(5:276) use message ~StringArray[5] as an array, and set entry %TheAmigos of it to {Third Entry.}.
(5:311) use variable %NumericalArray[5] as an array, and set entry %TheAmigos of it to 3.

In this example, the array will be declared as usual, with 5 entries (starting from Entry 0), however, it will be Entry 3 within ~StringArray that receives the value Third Entry and also Entry 3 that receives the value 3 within %NumericalArray.

Tutorial 1: Using Arrays to play a random song from a list

We've learned the theory, now let's test it out with an example! Let's imagine we have a rad jukebox in our RPG Dream that is capable of playing a random song from a list when bumped into. The DS for that should be simple enough but uh-oh! The way our music files are named puts the numbers all over the place! They're named things like m4, m72, m2, m34, and m16.

What are our options, supposing we can't rename the files?

  • Use a ton of DS lines to select a random song, or..
  • Use arrays to create a list of song numbers that's readable in a sequential format! Bonus: it also uses very little lines of DS to set up, and is therefore more elegant.

This example will show you how to use arrays to accomplish this goal.

Read more: Arrays Tutorial 1: Play a random song from a list

The one line...

There is a single array line in all of DS-cadia that does not behave like the typical array lines. Variable arrays store both the x and y coordinates of the entry in question, and when placed in a variable, copies both x and y coordinates with it. Normally, the coordinates are not treated like separate entries, but the following line is special:

(5:390) starting with entry #, set # entries in array # to #.

This line sets coordinate specific entries. In our previous array %Jukebox, we would have to declare entries 0, 2, 4, 6, and 8 to store the same data line (5:311) did since this line only stores half the array value. In reality, our %Jukebox array, if represented as a line of data would look like this:

4 0 72 0 2 0 34 0 16 0

As you can see, to properly use (5:390), you’d have to multiply the entry you’re trying to store by 2 if it's an X coordinate, or multiply by 2 then add 1 if you wanted to store a Y coordinate instead.

To further illustrate this concept, let's use a short example to compare how to store coordinates to arrays first using line (5:311) use variable # as an array, and set entry # of it to # and then again, using line (5:390) starting with entry #, set # entries in array # to #.

Read more: Arrays: The one line...

The Limits

Besides each entry within an array occupying one of the 500 available string or variable slots available for your Dream, entries also share the same limitations of strings and variables.

Variable entries can handle numbers ranging from -32768 to +32767. They also can store a max of 1000 numbers if they're all used, because they have the .x and .y coordinates (while arrays that use strings can't, due to not having .x and .y available).

Meanwhile, though entries within string arrays can be 4096 characters long, they also contribute to the total of 32,000 characters limit across all strings in your Dream (this includes spaces).


Strings

Strings have many uses, as covered in the beginning String DS and you may already be wondering how to apply them in even more inventive ways! In this section we will lay down some of the more advanced concepts, including techniques on how to create string-based systems.

Because of the vast amount of data alone that strings can hold compared to arrays, it's a good idea to master string manipulation for any type of database that would otherwise be impossible to achieve without a Dream Package (for PS storage). The main drawback with using string manipulation, though, is that strings are far more difficult to manipulate than arrays.

Tip: The term string will often be used throughout this guide instead of message (although they both refer to the same feature).

Tutorial 1: Text substitution and strings

So, there's text substitution for variables (%Var), special text replacement strings (like [FURRE]), other strings (such as ~Message) and even PhoenixSpeak entries called up through $ (like $dream.EntryName). We'll use this knowledge as a building block of advanced string manipulation!

Read more: Strings Tutorial 1: Text substitution

Tutorial 2: Adding text/strings onto the end of (another) string

In DS, there are currently two lines that let us to add text onto the end of a string. These lines are very useful for dynamically generating lists (and some main maps even use this for minigames to keep track of players), adding to a dynamic string database, or even stitching multiple strings together for one simple output.

Read more: Strings Tutorial 2: Adding text to the end of (another) string

Using strings as lists for data storage

Strings can actually be used for data storage in a similar way as arrays, but without using any of the array lines! But, one big disadvantage to this is that strings difficult to use for extracting and manipulating data (but it's still possible with some work!). The next example will show a way to use strings as a simple database, by baking words into a string separated by spaces.

Tutorial 3: Automatic share system

Let's start off with a very basic type of string database: a list of players to share Dream control to when they arrive! Before string DS, this would be done by adding a trigger for every player you want to share control with. This isn’t necessarily taxing on DS, but it could really add up if you have a lot of staff! The following string implementation will not only save DS lines, but also give you an idea of what strings are capable of.

Read more: Strings Tutorial 3: Auto share system

Tutorial 4: Manipulating elements in a string (Introduction)

Now that we went through a simple set of triggers to give share to a list of players, it's probably a good time to mention that these triggers don't actually account for three other scenarios:

  • Adding a new player to the share list
  • Removing a player from the share list
  • Moving a player from the automatic share list and into another list

All of these things require you to edit the contents of the ~ShareList string. Certain DS lines let us temporarily manipulate the string in the Dream itself, meaning we don't have to reupload the Dream every time we wanted to edit it (though you would need to edit your DS later if you want to keep this information in the string for the next upload the Dream). The following will cover how to edit and manipulate elements in a string!

Read more: Strings Tutorial 4: Manipulating elements in a string (Intro)

Manipulating words in a string

Each element within a string that is separated from another element by spaces is considered to be a word. Using this concept of words can extremely useful for the reading and extraction of individual elements within a string. How so? Well, for example, let's say we’re making an RPG, and there is an enemy camp with patrolling goblins.. what could we do if we want these goblins follow a fixed, looped path?

A way to accomplish this by manipulating words in a string is to give each NPC a string, and then designate a direction they will move to as a word. The string's example contents might look something like this: {NW NW NE NE SE SE SW SW }.

From there, it's a simple matter of removing the first word from a string (in this case, NW), comparing it with conditions, and then moving the NPC one space NW. Afterwards, the word NW can be added to the end of the string to keep the cycle going. There are plenty more ways manipulating words in a string could be useful, and in the following tutorial we'll briefly explain the components of how to do so in more detail.

Read more: Strings Tutorial 5: Planet eater

Extracting string data from a specific range

Text can also be extracted from a string if you know the specific beginning and ending positions of the data. For example, if we have a string called ~Furcadia that with the text "Let your imagination soar!", how could we pull out only the imagination word from it and nothing else, into another string?

Well, every character within a string counts as a position. So the very first character within the string (the L in this case) will be in position 1, the one following immediately after it (the e) will be in position 2, and so on.

So if we wanted to pull out imagination from the ~Furcadia string, we would go about it like this:

(5:272) set message ~Extract to be the portion of message ~Furcadia from position 10 to position 20.

Position 10 within the string contains the very first i within imagination and position 20 contains the n at the end of it. So with this DS line, we've set the ~Extract string to be imagination, but we haven't removed it from the original ~Furcadia string.

Now that we have some background on what positions within a string represent, let's take a look at an example! We'll make a set of triggers to make ambient music loop the selection of songs indefinitely, playing song after another in randomized order.

Read more: Strings Tutorial 6: Randomized, seamless ambient music

Using symbols in strings to separate words

And now we get to one of the most universally useful techniques useable with strings, using symbols to separate words! This concept is best explained visually, but basically in other words, we use uncommonly used characters (such as @, !, ^, &, *, (, ), - and =) in order to define sections, ranges and delimiters within a string. (Delimiters are any symbols used to contain portions of text, i.e. with Jake, Jeff, Joe, the delimiters are commas).

We have mentioned already that strings can be used to mimic arrays in a sense. In our array tutorial, our implementation took a disorganized set of data and made it organized to do our bidding! Muahaha! Since strings can also do this, in the following tutorial you'll get to see how to not only group disorganized data together, but give it attributes, too.

Tutorial 7: Colorful clothing shop

Let’s say that while we’re making an RPG Dream, we have come to realize that our world is missing a shop. Oh no! We also can’t spare any more arrays or PhoenixSpeak data because not only are we cheap, we are conserving the memory for the player stats! What do we do?

By mimicking how arrays organize data, we can make our own shop! Instead of using arrays, though, we'll use strings to group the data we need, and also give it attributes that we need for selling stuff, such as the item number that represents what we're selling, the name of the item, and then the cost!

Read more: Strings Tutorial 7: Colorful clothing shop

The Limits

A Dream can have 500 string variables in addition to any numerical variables it might have. Each string can be 4096 characters long. You are limited to a total of 32,000 characters in all strings if you add all the characters together (this includes spaces).


DragonSpeak Buttons

DS Buttons can be used in many ways, both simple and complex, since the function of each DS Button solely depends on you, and what you choose to do with it. If you've read through the basic overview of DS buttons and you think you're ready to try doing more with DS buttons, here are some slightly more advanced techniques to using DS Buttons that will help you to achieve the most from your Dream!

Tutorial 1: Menus

Although (as mentioned in the Basic Overview of DS buttons above), using DS Buttons for simple player interaction on the screen is a common use, you can also use DS buttons to have a full chain of events. So, when would you use a menu?

Say you have a cluster of buttons filling up the screen. Although you see that it's cluttery, you probably don't want to get rid of all of your fancy buttons just yet! So, how can we compromise? How about by making a menu!

Read more: DS Buttons Tutorial 1: Menus

Tutorial 2: Making special displays with DS buttons, like a clock

DS Buttons can also be used to spice up your skin by adding buttons as special effects. Combine them with animation (a bit of KitterSpeak) and you can produce some amazing additions onto your interface. In fact, DS buttons don't even have to be buttons at all!

For instance, we can even do something as complex as a clock that displays the time on our skin! In this tutorial we'll walk you through both through creating the patches, then the animation parts, and then finally the DS lines associated with it.

Read more: DS Buttons Tutorial 2: Making a clock

Integrating DS Buttons into tabs

Okay, so if you've made it this far, it might be safe to say you have a pretty good idea of how to use DS with the buttons!

But if you've gone into the Skin Editor and tried setting various DS buttons to be visible on default Furcadia tabs, you'll quickly notice that they don't display the same way in your Dream. The reason for this is that DS buttons behave differently than other default Furcadia buttons.

DS Buttons, opposed to the Furcadia skin buttons, need to have specific DS in order to show in your Dream. In fact, when it comes to DS Buttons, most of the information is handled through DS, rather than the Skin Editor. For instance, you can position (x,y) a DS button in the Skin Editor to save on DS line space, but even then that isn't necessary, as there are already DS lines for that, too.

When it comes down to positioning DS Buttons, there are 4 main DS lines. Two of them set the x,y position of the button, while the other two set a tab location (i.e. the default Furcadia tabs, including A, B, C, D, E, and F).

These are the lines are used to change the x,y position of the button:

  (5:182) move the triggering player's DragonSpeak Button # to (#,#).
(5:192) move everyone in the Dream's DragonSpeak Button # to (#,#).

As for tabs: Even though tabs use letters in Furcadia, in DS they're represented by numbers.

A = 1, B = 2, C = 3, D = 4, E = 5, and F = 6.

So instead of thinking A B C D E F, think 1 2 3 4 5 6.

  (5:183) show the triggering player's DragonSpeak Button # in tab #.
(5:193) show everyone in the Dream's DragonSpeak Button # in tab #.

Reference List

Testing command
  • Typing `dsbtn # will use the button even if you don't have it patched for testing
buttons.fox
  • This file houses DS Buttons 1-10 (Object Number 177-196)
  • Also it contains all of the patches for other non DS buttons and tabs
  • It's bigger in size due to having more objects
dsbtns.fox
  • This houses DS Buttons 11-99
  • Fox file used only for DS Buttons
  • Since it has less objects, it's also smaller in size overall

Summary

If your buttons will overlap any interface buttons, use the Skin Editor to move all DS buttons to the middle or top Z-order, instead of the bottom, so they aren't overdrawn by buttons from the skin.

The ranges are:
  • #Button Number: 1 to 99
  • #Tab Number: 0 (for not on a tab) to 5 (on tab E)
  • #X: 0 (far left) to 639-[width of button] (far right).
  • #Y: 0 (top of the Furcadia window) to 479-[height of button] (bottom)

#X and #Y can be outside these limits, but if so, you won't be able to see all of the button: like, drawing it at 800,800 will be outside the Furcadia window.

Lines 1:95 and 1:195 (is button visible/not visible?) only test if 5:180 or 5:183 (show button lines) have been run for the button, without a subsequent 5:181 (hide). If a shown button is moved off the screen, or is on a tab that is not currently selected, it is still counted as visible.

Workarounds

There's no simple way at the moment to:

  • set a button to draw on top of another (workaround: higher numbered buttons usually draw higher, but it depends on your skin. You can set each button to one of three z-orders in the Skin Editor).
  • test what tab they're currently showing (no known workaround).
  • set what tab they're currently showing (no known workaround).

Hopefully some of these will be addressed in future updates!


More technical specs and tips

DragonSpeak is an easy to learn plug-and-play scripting language that is great for beginners, but it can also help build a logical programming mindset. DS most closely resembles assembly or procedural languages, which means changes at the top of your DS file can impact the outcome of triggers near the bottom (i.e the entire DS file will execute every time).

One potentially helpful analogy (if you're into math, anyway) may be to imagine that your DS file is one large math statement, where each trigger is a logical if statement. The cause, condition, area and filter lines combine to form this statement, and if the statement is true, the effect lines will trigger. Since effect lines near the top of your DS can impact if statements near the bottom, order matters!

Every time something happens, a request to run your DS file is queued. These requests run synchronously and in order. Another helpful metaphor is to imagine your DS file is an ice cream truck and each queued request is a customer standing in line. Everyone waits for their turn, because the ice cream vendor will only serve one customer at a time in the order that they arrived. The vendor does this so that orders, change, and small talk get to the correct customer. In the same way, an event running your DS file is not interrupted or polluted by other events, it will finish the entire file before another event runs.

There is, however, a state to your DS file. Changes to variables, strings, and PS persist from one execution of the file to the next. Consider the ice cream truck example again. Every time a customer interacts with the vendor, they are changing the current state. Perhaps by the time a customer gets to the front of the line, there are no more ice cream tacos, or the vendor doesn’t have change for a large bill. The vendor will still interact with the customer, but they may not be able to fulfill their request as expected.

Best practices

Since DragonSpeak is a type of scripting language, best practices are guidelines intended to help keep your triggers clean and maintainable. This is particularly useful when working on DS with a team, especially if everyone has a different style. Here are some of our suggestions for writing clean DS:

  • Use the DS Constructor's Sections feature to organize and separate specific functions or events in a complex Dream, making it easier to find what you're looking for and remember all the aspects you have already added to your Dream.
    • The right-click, Autocomment feature on each section will also help you for debugging, when you need to isolate parts of your DS file for testing purposes.
  • Follow a naming convention when making variables and strings to avoid typos
    • Use consistent capitalization, whether it be all lower, all upper, or camelcase
    • Use compound words to express meaning, such as starting with a verb like is or has where it makes sense
      • %hasKey vs. %key
    • Establish guidelines for underscores and numbers -- should they be used?
      • %hasKey vs. %has_Key
      • %room as an array vs. %room1
  • Use comments above blocks and in between lines to clarify complex logic. You’ll be surprised how often you forget why you did something!
  • Use caution when removing or changing the descriptive text (non-keywords) in DS lines. Mismatches between descriptive text and line numbers can be extremely difficult to debug and even advanced weavers use descriptive text to quickly understand various triggers!
  • Make backups of your work! Nothing is more frustrating than having hours, days, or even weeks of work lost due to a computer crash or accidental overwrite.
    • Use a flash drive or external hard drive to save regular backups
    • Store your files on the cloud to preserve versioning

Debugging tips

There will be times you can't figure out why your DS isn't working, and there isn't a Mason around to help you. In these trying times, here are some tips on methods you can try to figure out and isolate the error you're experiencing.

In general, the "ice cream truck" metaphor mentioned above is handy to keep in mind, as everything that happens in your DS affects the overall state of the file. So, what can you try if whatever your first attempt was isn't working?

  • Comment out (the autocomment feature in the DS Constructor) large chunks of your DS and see if the other parts are interfering.
    • If you've used the DS Constructor's Section feature to organize your DS, it's easy to then right click each section and then select Autocomment for testing purposes.
  • Move the new DS you're working on to the bottom, middle, or top of the DS file, depending on how it might or might not affect the order of occurrences/events happening in your map.
  • Make a copy of the map and DS and trim off as much extraneous stuff as possible. Sometimes it's the other stuff happening in your map that interferes with your idea.
  • Use the PhoenixSpeak maintenance commands (listed at the bottom of that page) to get a clearer picture of what's happening with your memory management if you're having an issue with any triggers using PS lines.
  • Variables and strings are case-sensitive (A vs a) so double check you don't have any typos in your strings or variables.
    • You can check for mismatched variables by using DS Constructor's Variable information dialog (Alt + V).
  • Try making a second bare bones version of your map with no patches or DS, and only the new feature you're working on is present.
  • Temporarily have any hidden strings, variables, arrays, entry codes, emit their contents out loud in your Dream, line by line as your trigger goes through its event.
    • For example: (5:204) emitloud message {Variable %temp says this now} to everyone on the map.
  • Double check that the lines you copied match the wording of the original line / the line you intended. Sometimes the wrong ones are copied, or the numbers are accidentally mismatched!
    • Remember, the DS parser doesn't care about the wording of the line, only numbers, variables, strings and whatever is inside {these}!
  • Temporarily add debug messages to every effect DS line in your triggers to explain which part of the event is happening and when. For example:

This:

(0:14) When someone picks up any item,
(3:5) where the triggering player was at,
(5:4) place item 1.
(5:22) copy the item to (10,20).
(5:50) set countdown timer 1 to go off in 10 seconds.

Becomes this (for testing purposes):

(0:14) When someone picks up any item,
(3:5) where the triggering player was at,
(5:4) place item 1.
(5:204) emitloud message {Someone picked up an item and item 1 was placed down.} to everyone on the map.
(5:22) copy the item to (10,20).
(5:204) emitloud message {The item was copied to (10,20).} to everyone on the map.
(5:50) set countdown timer 1 to go off in 10 seconds.
(5:204) emitloud message {Countdown timer 1 was triggered to go off in 10 seconds.} to everyone on the map.

DreamEd hacks

  • CTRL + Left click to automatically copy coordinates
  • CTRL + M to toggle the Furcadia Field of View when designing large areas
  • Use the Show menu to toggle walls or other layers when designing

DragonSpeak Constructor hacks

  • CTRL + SHIFT + F to bring up the Line Finder
  • CTRL + SPACE for line auto completion
  • Use Sections to break up segments of DS for better manageability
  • ALT + V to bring up the Variable Information dialog -- great for debugging variables!
  • CTRL + R to fix line indentation
  • Listen to default sounds from Tools > Sound Preview without digging through patch folders


Thank you to the Beekin Masons who collaborated and shared their deep knowledge about Dreamweaving to help create these epic tutorials! This amazing collection of tutorials would never have been possible without their help!

DragonSpeak is a wonderful way to add magic and life to your Dreams, so feel free to explore and try new things with your own ideas. If you have any further questions about it, feel free to contact the Beekins in game by saying help I need a mason!

Account E-Mail

Password