Tutorials on scripting

Ask and answer questions about making games and related topics. Unrelated topics go in that other forum.

Moderators: marionline, SDHawk

Post Reply
ArtimusBena
Slime Knight
Posts: 251
Joined: Thu Nov 16, 2017 5:22 am

Tutorials on scripting

Post by ArtimusBena »

(Apologies for the re-post, and sorry for the loss of your messages. I have taken screenshots for personal reference. However, the previous version of this thread was rendered rather toxic in my view, and kind of disrespectful -- in the very least, offputting for any 'noob' coming into it. Debate about the usefulness of this thread should take place outside of it. Thank you for understanding).

By now I'm pretty well versed and can explain how things work and where to start. We are all pretty aware that it's tough to find tutorials, much less good ones. I'd be happy to help people get started with plotscripting! If you are having trouble getting started or think there should be a tutorial on something, comment below and I'll do my best to provide a concise, noob-friendly explanation. And I will try to get the result posted to the Wiki as well.

To be clear, the purpose of this is to explain micro stuff. I know there are resources already on probably anything you could mention, but if you're having a similar experience that I had while learning these things the hard way, then you agree that what we can find out there is still too confusing.

Here is a short example I had whipped up. (It was commented on as not being basic enough itself! And I will be taking this advice going further. Anyway, it should give you an idea of what I'm going for):


EXAMPLE
_________________________________________________
Script Arguments:

Script arguments are a really nice feature. What they do is translate a number from one script to another script. Let's take a look at a basic example of how to set this up:

Normal script:
script, myscript, begin
end

A script with arguments:
script, myscript, x, y, begin
end

So, you have the script name, then make up some variables separated by commas. What does this do? Well it does two things:

1) it creates a new local variable. A local variable is just a number that only means anything *inside this particular script*.

And 2) it makes it so that when you call this script, you can plug any number you like into "x" and "y". This is what a "passed argument" is. Remember local variables only meaning anything inside that particular script? Well now you can PASS that number to another script, so that it also means something in the second script. Here's what that looks like:


SCRIPT A
script, run, begin
jump (1, 2) #calling a script called "jump" and giving it numbers
end

SCRIPT B
script, jump, x, y, begin
#do stuff with variable x
#do other stuff with variable y
end

In this example, when you call the script "jump," 1 and 2 become X and Y in the second script.
_________________________________________________


Topics that have come up (whether here or in discord):
Constants
Variables
Global variables
Arguments
Handles
Return commands


Something for intermediate folks, written by Kylekrack:
https://rpg.hamsterrepublic.com/ohrrpgc ... g_Tutorial
Last edited by ArtimusBena on Wed Jul 08, 2020 3:35 am, edited 1 time in total.
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Post by TMC »

I'm copying here what I've managed to save of the contents of the old thread, which I didn't get a chance to reply to (further replies are forthcoming).
Spoonweaver wrote:I like the idea of doing things a little different. Basically like writing better descriptions of what commands do and how to use them. There is some of this in the plot script dictionary, but not enough of it and the examples are incredibly basic. There is room for improvement there and it could very well be the best thing to help those looking to use the language.
This is a good point; people will refer to the dictionary more often than the tutorials, so it's also an important focus of improvements. I try to improve it every time someone complains about a command description. Anyone with a text editor can edit plotdict.xml and send us their changes or the whole file.
More examples would be better, though an example for every command would be too much. A single example can show off multiple commands, which those commands can refer to.
Artimus­Bena wrote:when you help someone 1 on 1, that answer should be added to an FAQ or turned into a tutorial of some sort.
Absolutely. Unfortunately I very rarely copy what I've written on the forums or discord onto the wiki. Which is an absurd amount of lost information.
Pepsi Ranger wrote:
Artemis Bena wrote:Script Arguments:

Script arguments are a really nice feature. What they do is translate a number from one script to another script. Let's take a look at a basic example of how to set this up:
So, for years, not understanding how to use arguments was the number one obstacle I faced in creating better organized scripts: I couldn't wrap my head around the concept of arguments. Part of the problem was with the word argument itself. In rhetoric, an argument is an assertion you make about a topic, usually using facts. In programming, it's basically another word for variable, which, in the case of functions, has to do with establishing parameters for that function. Because I come from an academic background, my thought process defaults to the rhetorical form of an argument. So, reading the old tutorials about arguments did nothing for me. It wasn't until years later that msw188 wrote either an article or a comment that made total sense that I finally understood how these [s]stupid[/s] wonderful things worked. (Note: I'm trying to find the reference, but I'm coming up empty. I'll edit in the link if I ever find it. It was the article that helped me understand advanced plotscripting and is worth sharing.)

In short, what msw188 did was to talk to me in language I could understand, using examples I could relate to.

Just understanding the basics of scripting language (including plotscripting) is a fundamental part of the tutorial process. You'll want to define what certain terms mean (like variable), since the engine is designed for nonprogrammers to jump right in and create something, and it assumes that nonprogrammers will, in fact, try to use it.
Artemis Bena wrote:Normal script:
script, myscript, begin
end

A script with arguments:
script, myscript, x, y, begin
end

So, you have the script name, then make up some variables separated by commas. What does this do? Well it does two things:

1) it creates a new local variable. A local variable is just a number that only means anything *inside this particular script*.
For anyone familiar with how plotscripting in the OHR works, this example would be fine.

But we're not writing for someone who already knows how to plotscript--otherwise, what are we doing here? I'd have to learn what variable means in scripting for anything you just said to make any sense. When Idontknow talks about hieroglyphics later on in the post, I think this is what he's talking about.
Artemis Bena wrote:And 2) it makes it so that when you call this script, you can plug any number you like into "x" and "y". This is what a "passed argument" is. Remember local variables only meaning anything inside that particular script? Well now you can PASS that number to another script, so that it also means something in the second script. Here's what that looks like:

If I were brand new to scripting, this would've just given me a headache.

Now, I don't know how far into the tutorial process an example like this might show up. If this were, say, Chapter 3 in a book about scripting in the OHR, then maybe I'd understand enough at this point to know what I'm looking at. But if you're creating piecemeal tutorials for the casual user with no particular anchor to the language, or any particular path for development, especially one that includes foundational knowledge, then all of this is going to look like nonsense. Establish a connection with the rookie the best you can before you assume he can follow your instructions enough to forge his own path.

The secret here is to remember that most of us who choose the OHR over something like Unity do so because it's accessible to nonprogrammers. If a nonprogrammer comes here looking to make a game, then you have to speak to him in nonprogrammer terms.

This is what msw188 did to make arguments finally click with me. I wish I could find the exact article where he wrote this, but essentially he interpreted the idea of arguments through a language I could follow rather than regurgitate programmer jargon at me and make me wish I'd just stuck to writing novels for my storytelling outlet.

So, although you eventually need to show the user how to write the code as code, as you've done in your "x and y" example, you'll want to connect with the user from a nonprogramming (and maybe even nonalgebraic) standpoint first to get him on your page.

Something like:

"Pretend you want to write a command that changes its results, depending on the information you provide it. Well, to do that, you'll want to first understand how writing commands and passing information works. In the real world, you tell somebody to walk 20 steps in a given direction, they typically know what you're asking them to do because your language is clear (whether they choose to do so depends on your authority and their submissiveness). In the OHR, however, although we have a similar user-friendly system, we refer to these syntax-exact commands as functions. You can also think of them as instructions for your game to follow. For now, we'll keep this idea simple.

"Let's say you want to command a hero to walk across a map by 20 steps. Let's say you want that hero to walk north (or up). You'll first have to give that hero the command 'walk hero (0, north, 20)' before he can do what you want. Notice that 'walk hero' is not 'move hero' or 'run hero.' We write 'walk hero' because that's the syntax that the script will understand. The Plotscript Dictionary explains the proper syntax of every available function so far. If you look at the arguments for 'walk hero,' or the values that provide this command (or function) its specific instruction (go 20 steps instead 10, for example), you'll see that giving your hero a clear destination is quite simple.

"This is the 'walk hero' function in action. As you can see, it's not complicated. It uses three arguments, or pieces of information, that can change the outcome of the command, or function. Change any of those values (called arguments), which refer to hero line position (0), direction (north), and distance (20), and you change the behavior of 'walk hero.' Would you rather the hero go south? Then change the argument for 'direction' to 'south,' and he'll walk south.

"This function works this way because it is scripted (or programmed) to work this way. The good news is that you can create your own functions, or commands, by writing scripts with arguments."

And so on.

As you can see, I've repeated programming concepts enough for the reader to understand it in context. But I didn't just dive right into using those terms. I first had to establish the language so that the reader could follow along with my logic. By the time the reader gets to the end of the passage (about halfway through the likely tutorial), he or she should understand the concepts well enough to get the gist of the lesson and continue learning with a basic understanding of the language. If you do a tutorial series, you should really keep this idea of the nonprogrammer in mind.

Basic rule of thumb, assume your reader has zero experience with programming or algebra and go from there. Assuming the reader follows along with you, you can ween him off of the common understanding and start using the actual terms in context. But even then, every new concept should first come with a relative example that a nonprogrammer would understand.

Example: "Next we'll want to embed a string into our textbox. In case that sounds like gibberish, what we're actually doing is placing (embedding) scripted text into the textbox at the specific marker (or string code) that we want the string, or conditional text, to appear. This allows us to change the content of the textbox via script. But first we need to decide which string code will properly display the text as we intend it."

Isn't that much better than: "Next we'll want to embed a string into our textbox to change it via script. First, we'll want to pick a string code that corresponds with the script string"? Ugh.
msw188 wrote:Hi Pepsi! It's cool to hear that I managed to help you so much that you still remember that specific example all these years later. I remember writing it too (it took me a long time to write, unsurprisingly). I just tried searching for it, but couldn't find it. From what I can remember, it was just a reply on the forum, not an article of any sort.
You put it on the wiki: What is a script argument for?
I added that article to the new Scripting section of the HowTo a few days ago.
kylekrack wrote:I wrote this tutorial yesterday which goes into writing scripts for a HUD created in a slice collection tutorial I made a while ago: https://rpg.hamsterrepublic.com/ohrrpgc ... g_Tutorial

I'm interested to hear how effective are the descriptions of variables and the various script commands. One of the things I was very careful with was slice handles. Handles are one of the things I consistently hear people having confusion about when it comes to scripting. I explained handles like this:

Every slice has a “handle,� which is like a unique reference number to a slice. This number is arbitrary and unpredictable. Think about your school or employee ID number: it’s yours, no one else shares it, it was assigned arbitrarily (meaning, it’s not reliably guessable), and others can use it to look up information about you on file. The slice collection we load has a handle itself, and we store that handle in the variable, “hud.�

Is this metaphor sensible? Accurate? Clear? I want these tutorials to help people understand the concepts, not just follow steps. And I certainly don't want to put any misleading information.

EDIT: This is what comes immediately before that description of slices:
First, we create a variable, which is a device that stores values. Instead of just loading the slice collection, we set our variable, called “hud,� to the value returned by “load slice collection(0).� The declaration “hud := “ will shove whatever value comes after the ‘:=‘ into the variable. In this case, “load slice collection� returns a slice handle for the loaded collection.

Wanted to explain variables concisely and simply.
Pepsi Ranger wrote:Most people understand the employee ID example, so this should work. I'd maybe finish the example by explaining that "hud" is the user-defined name that you're giving the variable so that you can recognize it later. I find that thinking of variables as "folders" or "storage containers" helps me to keep things in context. This is what I'm currently doing to wrap my head around arrays, especially fake arrays. (I'm actually trying to think of them as filing cabinets.)
kylekrack wrote:EDIT: This is what comes immediately before that description of slices:
First, we create a variable, which is a device that stores values. Instead of just loading the slice collection, we set our variable, called “hud,� to the value returned by “load slice collection(0).� The declaration “hud := “ will shove whatever value comes after the ‘:=‘ into the variable. In this case, “load slice collection� returns a slice handle for the loaded collection.
Again, this all sounds fine. I'd be a little suspicious of the word declaration if it's not previously defined, but other than that, I don't see anything here that would cause confusion. I'd just make sure that all functions are understood as functions. I'm sure that's why you're putting quotes around them. The barrier comes down to understanding the terms. Once you've properly established a baseline for understanding, the rest should take care of itself.

I think another *awesome* concept that new users will want to understand early on is the constant. Again, I was clueless for a long time what these were until I realized that a constant is just a name given to a number that plotscript uses to understand the details of the command. That's why "north" and "up" share the same number. Plotscript doesn't read "north" or "up." It reads "0," which is the value assigned to them. When users understand this concept, then they can create their own library of useful references, or constants, to keep their scripts organized. I've been using this a lot lately, and it's been keeping me out of trouble.
Last edited by TMC on Tue Jul 07, 2020 10:56 pm, edited 1 time in total.
User avatar
msw188
Metal Slime
Posts: 787
Joined: Tue Oct 16, 2007 1:43 am
Location: Los Angeles, CA

Post by msw188 »

You put it on the wiki:
Wow! That's it alright! I totally don't remember putting it on the Wiki.

I haven't really been very helpful in this conversation yet, but I think if you look at Bena's take on arguments versus mine, a couple of things stand out in line with what Pepsi was pointing out before.
1. Mine is a lot longer. Unfortunate for the impatient beginner, but I think to some degree necessary.
2. Mine focuses a lot more on "Why use arguments?" with a heavier emphasis on the end result. I have a whole paragraph about how authors can recognize the importance of arguments in absolutely basic commands where the author already knows what will happen. Bena carefully explains that the goal is to pass numbers from one script to another, but never shows an example of this being done which illustrates the end result.
3. Riffing on the issue of examples a bit more, there's a stark contrast between mine and Bena's. Mine is incredibly specific, accomplishing only a small, trivial, but easy to understand goal. Bena's is general, theoretically accomplishing a great number of goals, but practically accomplishing none of them without further input/thought from the user.
4. In mine, no "programming words" appear (like variable) until my specific example has been introduced. Although Bena also waits until he has an example in play for the technical words, his example is too vague to be of much help to the reader in his numbered list.

I'm sorry if this all sounds very negative, but it kind of is. I don't think Bena's example tutorial would be very helpful for a beginner who has no prior programming knowledge before trying to use HSpeak. Mine isn't perfect either, but I think it illustrates some important points to keep in mind. First and foremost, the beginner typically needs examples and explanations that have concrete end results in play. Only then can they appreciate how many other results may be possible.

By the way, this is the same in game design as well. It's maybe less of a thing for RPGs, but any time you introduce a new mechanic for a player that you want them to explore, it's often essential to give them a situation where the mechanic produces a concrete result as early as possible. See: pretty much every game Nintendo has ever made.
I am Srime
ArtimusBena
Slime Knight
Posts: 251
Joined: Thu Nov 16, 2017 5:22 am

Post by ArtimusBena »

Skimming your arguments article, msw, I agree. Yours is better.

If you would like to keep an eye on this thread and see a suggestion you'd like to write about, feel free!
User avatar
Pepsi Ranger
Liquid Metal Slime
Posts: 1457
Joined: Thu Nov 22, 2007 6:25 am
Location: South Florida

Post by Pepsi Ranger »

I don't remember seeing it on the wiki, either. Maybe it was imported. But yeah, that looks like the article. Thanks for finding it, TMC.

Since it's on the wiki, it might be useful to add a branch of related concepts that the student could read to further his understanding of how these things work. I know we talked about the constant in the other thread (too bad the screen capture didn't save all of the boldfaced terms), but something else of related use is converting the function (or script) into a variable that can be used in another script (using "exit returning"). The weeds in which we can enter . . .

It might be a good idea to outline an actual course where one concept can lead to another and then focus on writing articles for each section of the course. We could even compile the whole thing into an e-book (with formatting!) when we're finished (because I now have software that can do this, and it must be used!) and allow people to take it with them on the road or print it for their desks if they want.

Just a thought.
Place Obligatory Signature Here
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Post by SwordPlay »

Here's how I would write an introduction to scripting

NUMBERS AND WORDS
A variable is data which you store and recall. But only numbers!
We can use words as well, I'll come back to that.

It can represent any information, because we can assign meanings when the variable is at a certain value.
> The most common example is (1==True) and (0==False)
> A more advanced view is (0==False) and (0<>True)
> Also we can think about it as (False <= 0) and (True > 0) etc.,

All things in the engine are numbered, and when we refer to a hero, or slice, we are actually using their number.
Hence, when we assign a slice to a variable, we are actually storing its slice number, which we can easily access as a variable.

We operate on variables with
+= (add)
-= (subtract)
:= (set to)
and we can check conditions with
== (equals)
<> (not equal)
> (more than)
< (less than)

there are more operations and checks
(e.g,
division,
multiplication,
more or equal than,
less or equal than)
but thats the basic stuff.
You can see everything in the plotscripting dictionary.

Code: Select all

set slice visible (slice, on)
we can also write the number "1" or the word "true" instead of "on"

Code: Select all

IF(get slice visible(slice) == on) THEN (...
this checks if the condition is "true" (same as "on")

GLOBAL VARIABLES
If you wanted to store the health as a (global) variable, you could increase it when the player receives healing from a pickup or decrease it when they get bonked by a dinosaur.
You can check to see if the health is 0 (or less!) and make the player character die.

Code: Select all

Global Variable (100, Player Health)
Global Variable (101, Player Mana)
This declares the Global Variables

Code: Select all

Player Health += 1
Player Health -= Player Mana
Player Health := Maximum Health
Player Mana := 0
This adds 1 to Health,
decreases the value of Player Mana from Player Health,
sets the Health to the number in "Maximum Health"
and sets the Mana to 0, in that order.

Every Global Variable needs a unique number and name!
We can ask for Global Variables by their unique name or number.
Such as

Code: Select all

Read Global(100)

Code: Select all

Player Health

Both exactly mean the same thing in the script, which is the number stored in that Global, whatever it may be.

You usually won't use Read/Write Global, but it can be very useful because we can perform operations on any numbered list (more on that later)
Most importantly, we can use Read/Write Global to get the value from a Global when we don't know which Global is going to be needed, and we can store data in them like an array. (more on Arrays later on)


CONSTANTS
A constant must have a unique name.

Code: Select all

Define Constant (1000, Maximum Health)
So whenever we write "Maximum Health" the script will interpret that as "1000"

We can say

Code: Select all

IF(Player Health == Maximum Health)THEN(...
and it will check to see if the Health is at Max

However, if you want the player to be able to increase the Max Health, you need a (global) variable, and then be able to change this when they pick up a Health Powerup or whatever.

If you want to store text, like the name of something, or a description, you would use a string or text slice.
But you shouldn't use it to store something like the heroes health, because that would be more complicated than just using a number and representing it as text.
Also, we don't need to store text, because numbers are much, much quicker.

Variables are numbers is very important, because we can do things to numbers we can't do (easily) with words.

VARIABLES
You will usually use Global Variables for information that can be accessed anywhere, at any time, independently of other scripts.
It is usually saved when the game is saved.

Otherwise you use a Variable and pass it on to other scripts as needed. They only exist when the scripts are running.
They are temporary and will not be saved.
They do not have a unique number, but they must have a unique name.
Say we have a self-contained mini-game.

Example, say you want to count how many targets the player shoots, until they reach the limit, 20.

You can declare variables like so:

Code: Select all

Variable (high score, current score, target score)
So we count each successful shot as 1, until we reach the 20.

Code: Select all

IF(Check for Hit)THEN(score += 1)
"Check for Hit" is a check to see if the condition is met.
It can be the result of a command or script.

At some point, we can check the score:

Code: Select all

IF(score == 20)THEN(Player won)
"Player Won" is the victory script, where presumably the player gets cake

You probably want to check if the victory condition is met, whenever you check if a hit was successful. You can even put them in the same script.

Then the script will run all the time to check if the player has hit targets, and if the player reached the limit.

Then the script is over, and we don't need the variable anymore.

We can even name the target to reach as a variable, and change this based on the difficulty, for example.

Code: Select all

Variable (target score)
IF(score == target score) THEN(Player Won)
Note, this will work if score is changing 1 at a time.
Otherwise if you can score multiple points for a hit, you would use
Code:
IF(score >= target score)THEN(Player Won)


But say it was timed, and we want to keep the player's score.
You might want to pass on the score to another script that gives a reward (more on passing arguments to scripts later)
But when the scripts are done with this variable, it will no longer exist.
If you need to keep it around longer, put it in a global

Code: Select all

best score := targets hit

"best score" is a global variable that persists even when the script is not running.
It is being set to the value in "targets hit"
If we want the highest score (ever), we add a check

Code: Select all

IF(targets hit>best score)THEN(best score := targets hit)
If we use a Global Variable in place of a variable, we have to account for data we assigned to it already.

Say we want to use a global for "targets hit" so we can check how many we've hit so far.

Then next time we start the script, it will remember what was in the Global and continue counting from there.

If we want to a new count we must set it to 0 so it will start counting fresh.

Code: Select all

Targets Hit := 0
Then we put this before we start counting to make it start from 0 each time.

JOYS OF A NUMBERED LIST
Numbers, especially a numbered list, can correspond to text
For example, say we have a list of elemental types for our game,

1 - Water
2 - Earth
3 - Air
4 - Fire
etc.,


When we refer to element 1 (Water) we can represent this as text to the player, rather than a number.
I guess thats more complicated than using text, such as "Water" to refer to that element,
but we can do a LOT of clever tricks with a (numbered) list, especially working through them from start to finish, or taking sections of them.
If I want the 4 elements I can ask for elements 1 through 4, one by one.
That's much easier than asking for elements "Water" through "Fire", right?

Fear not, however, if you just want to ask for an element by name, you can do that too.
We do this by defining a constant (as above)
This helps us so we can use text in place of numbers.
We can ask for "Water" and the script will know this means "1" in our numbered list, and act accordingly.
You can only define each word once, but variations/permutations are okay.

NUMBERS, WHATS THE POINT

I mentioned that numbers can represent ANY information.
A numbered list can correspond to any number of states

For example Health;
0 - Dead
1 - Wounded
2 - Healthy
etc.,

We can think of all the states as corresponding to a number, even other things like "broken arm" or "broken leg"

However, if we store the states in a single variable, we can only store one state at a time, unless we use a bitmask.

Example,

we might track the player elemental resistances

we might have 1 global variable for each elemental resistance, and represent the states according to the following
-1 = vulnerability
0 = normal
1 = absorb

or we might have all the immunities in 1 number using a bitmask to read certain digits as on or off
(1011)
can be read as (on, off, on, on), so in other words, immune to water, earth and fire.
however, bitmasks have disadvantages. you can't say
(1 0 1 -1)
but you could say
(1 0 1 2) and use 2 in place of -1. Kinda complicated tho, isn't it?

please note you have to tell the script how to interpret each number, its just a number until you use it.. the computer/script does not know the meaning of each number, so make sure you give it the right one and tell it what it is supposed to mean

PLEASE NOTE THAT YOU CANNOT LEARN EVERYTHING FROM A TUTORIAL
There are COUNTLESS techniques which you can only learn by observing them, for example, in other people's scripts, figuring them out, or reading about them somewhere.
OTHERWISE YOU WILL CONTINUALLY BE DOING THINGS IN THE MOST BASIC WAYS ONLY

Most programmers admire the application of great techniques to perform nigh-impossible tasks, or to bring complex scripts to the level where we can easily modify, understand, manipulate etc., it

Advanced Techniques, or something like that:
Not an exhaustive or comprehensive list, by any means. Or accurate.

Operations. All of the operations.
Give them to me, your operations.
We can manipulate data various ways, including adding them together and splitting them apart. This also works with words (strings). Data can be scaled to reasonable values, clamped to a ceiling or floor, or interpreted into a manageable form. We don't have to work with raw data!

Loops and lines
We can work through data continuously, or make a pass over the sections we need.
It helps to understand recursion, and not creating infinite loops by accident. Kinda metal tho, right? We need to understand grasping sections of data, and understand that data might be comprised of dimensions, like X/Y for a position, or past/future for time. Other times, we want to keep going over something and changing it repeatedly, but we don't want to write it out manually. So we must loop over the data until it conforms to our expectations. Resistance is futile.

Data application. Customised Interpretation
Making numbers mean what you want them to mean.
You can use variables to store states of any kind. They can represent time, location, arbitrary values, etc., so don't be afraid! They are whatever you want them to be. Representing everything as a number is the main thing to grasp.
A single value can even represent more than one thing!

Data management. Storage, Presentation and piping.
Making it easy to access data wherever you want
As a beginner, you often find it difficult to access the data you want easily. You can set things up so that data requires minimum handling. You must master arguments and the flow of data between scripts. You also need to be able to parse data as a human, whilst not making it mechanically obtuse.

Data handling. Offsets etc.,. Pre/Post processing data.
Manipulating data more easily, and with less work.
Handling data can be arduous, but we can compensate by processing the data, rather than managing it by hand. We can clone the data and perform operations on it, whilst preserving the original data. Of course, we can modify the original data as well, but the original value will likely be lost.

Systematic handling. Creating your own system
Having the computer do the hard work
The computer can do almost everything if we set it up right. Otherwise we have to do practically everything! Once you know some advanced techniques, the amount of work can be minimised. Look at how other games have implemented systems to understand their workings. Often times its much simpler than it appears!

Visualisation and accessibility
Working with data can be difficult. It doesn't have to be.
We can use (read: CREATE) debugging tools, trace values and even other things like create graphs or charts. A lot of times your head will swim trying to figure out what kind of value you need. You can play with data to get an intuitive feel for it, and work it out by trial and error using debug tools, rather than constantly modifying the script.

We can pass on the result of a script or command as an argument to another script.
Super important! We can pass the result of a check or operation onto another script.
Last edited by SwordPlay on Sun Apr 10, 2022 9:25 am, edited 15 times in total.
"Imagination. Life is your creation."
ArtimusBena
Slime Knight
Posts: 251
Joined: Thu Nov 16, 2017 5:22 am

Post by ArtimusBena »

This is a much more constructive response than your last two. Good job, thank you.
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Post by SwordPlay »

ArtimusBena wrote:This is a much more constructive response than your last two. Good job, thank you.
Ta m'Bena

imho, the best tutorial for a newb is
https://rpg.hamsterrepublic.com/ohrrpgc ... g_Tutorial
and we should link to it often

I might be mistaken, but I think there is reasonably more demand for advanced programming concepts amongst the community.
The main separation between novices and experts (imo) is the usage of unusual techniques, rather than methodical working. Although it helps if you are methodical, for sure.

If anyone has questions about advanced concepts, that would be a good step forward for the community to get scripting POWAH

I have an idea that I will do a dissection of some games scripts, especially the systemic ones, to show how it can be done, and make it accessible to newbs
Last edited by SwordPlay on Wed Jul 08, 2020 8:52 am, edited 3 times in total.
"Imagination. Life is your creation."
ArtimusBena
Slime Knight
Posts: 251
Joined: Thu Nov 16, 2017 5:22 am

Post by ArtimusBena »

Sounds like a good idea for a thread
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Post by SwordPlay »

y-yeah, let's just see how it goes
Last edited by SwordPlay on Wed Jul 08, 2020 9:12 am, edited 1 time in total.
"Imagination. Life is your creation."
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Post by SwordPlay »

[yt]bVJ-mWWL7cE[/yt]

There's a lot of good tutorials online. Not sure how relevant this one is, but still, extremely interesting.
Last edited by SwordPlay on Sat Jul 18, 2020 8:40 am, edited 1 time in total.
"Imagination. Life is your creation."
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Post by SwordPlay »

note: I think of SWITCH and TAG as being interchangeable

USING VARIABLES INSTEAD OF TAGS

I see a lot of beginners use tags, and that's really the right way to start.

However, you eventually come across complicated scenarios which require a lot of tags, and it becomes a pain!

So I recommend you use (global) variables, and perhaps a bitmask.
We can combine various values (such as on/off, like a tag) in one variable, by using a bitmask, for example.
But this is rather complicated, so feel free to ignore it. You are probably better off using a combination of global variables and tags.

Say we just want to progress something, like a dialogue chain, or sequence of events.
You could use tags, but you would need 1 tag for each step.
Really you should use a variable and increase it appropriately.

There are some advanced techniques here, like being able to advance the chain from any point in the chain, and advancing the chain by any amount.
However, this can lead to breaking the chain, so try to understand which unique data has to be kept separate from others.

The key thing is that each value should have a unique meaning at the time you read it.
It's even okay if a value means more than one thing, but you have to be really careful to not mix up the meanings.

Say you want to use variables, then. That's a lot more complicated than tags, I admit.
But you can get around it by writing a script to do your checks/operations based on conditions.
You often also need to give contextual information to the script, which can be done through extra data/script arguments.
An important thing to note is that we can represent any COMBINATION of states as a SINGLE value. We can just do this by assigning each combination a value, procedurally, rather than by hand.

Instead of saying
1 = Blue Hat
2 = Blue Coat
3 = Red Ring
4 = Red Coat
etc.,

we can have all the values for Coat from 10 to 19, and all the values for Blue end in 2, and Red end in 1.
Then if we have "11" or "12" we automatically know this is Red Coat and Blue Coat respectively.
We can also do more complicated things to define these ranges with more freedom.

We can also use checks and conditions to make sure that data is not written incorrectly, to parse (decipher) the meaning of combined values, and to present parts of information rather than the whole thing.
e.g, checking if the equipment is red or blue

That would be a lot easier than having a list of every red or blue item and checking them each, wouldn't it??

USING SLICE EXTRA DATA, PRETEND THERE ARE ARRAYS, USE YOUR IMAGINATION

Something of an advanced technique, but admittedly, it just adds a few steps, which can easily be handled by a wrapper.
You don't need to use variables, you can use slice extra data, and they can work like arrays of data.
What's the point? Organisation, mainly. You can access and alter a range of data (variables, switches), and you can look for data attached to an object, like a hero, rather than looking in a table, or having to figure out where to look.

We can store data when we don't know how much data we need.
We can keep, add and extend lists of data.
It makes it useful to store and manage values!

I ALWAYS DREAMED OF BEING A WRAPPER

Wrappers are usually convenience functions that go around other scripts.
Their only purpose is to simplify or streamline other scripts/functions.
They are very useful in presenting, shuttling and accessing data.

Usually, you should try to write your scripts well enough not to need a wrapper, but sometimes you will want to use multiple wrappers and use them in complex ways.

You should think of wrappers as extensions of a script that go around it somehow, usually at the beginning or end, and feed into, or receive input from scripts.

In a sense they are convenience scripts, and don't actually do the main work.
They just make the work more manageable.

As far as I understand things, anyway.

Some things I forgot to add:

(A basic script might just be a single command. So it helps to think about your script as a new command that you are creating. But they can do anything, even complex sequences)

Why (global) variables instead of tags?

They can also store multiple states. As well as a chain, it can have branches.
We can also go back and forth along it, and jump to any position (value)

With tags we have to know them ahead of time :)
Tags only have binary states, ON or OFF (or true/false, or 1/0, or whatever)
There's also only 1 tag for each bit of data we want to represent.

Why Arrays?
They are containers for variables, and we can also consider them variables as well.
They have all the advantages of storing data that is implied, as well as our ability to manage it selectively.

Why slices instead of globals?
They can act as arrays! (for now)
When we use slices to store data, so they act as variables, we can create these data nodes (slices actin as arrays) on the fly and attach them ANYWHERE (e.g, to map, npc and hero slices, as well as our own slice structures).
It helps if you use your own organisation and wrappers.

You can use some of the data of a slice as binary switches, like tags, whilst the ones that allow you to input numbers can be used like variables. You could probably even store data in the align/anchor settings if you wanted.

This sounds like a lot of work, but you just write a script to do this for you.
You could write your command (script) however you like.
This is rather basic, so at least consider doing this if you want to improve your skills.

What?

You probably want to be able to read and write data at will.
Make debugging tools to help you check it's working as expected.
If you want to get fancy (read: intermediate), you will use more complex commands to handle various things at once, and have scripts that feed into each other.
You will find it easier to trigger parts of your scripts at will, or set their states. That's debugging for ya.

You might be tempted to create lots of commands (scripts), but you should think about giving them parameters to alter their behaviour, and save time.


Here's how I would write an introduction to scripting

NUMBERS AND WORDS
A variable is data which you store and recall. But only numbers!
We can use words as well, I'll come back to that.

It can represent any information, because we can assign meanings when the variable is at a certain value.
> The most common example is (1==True) and (0==False)
> A more advanced view is (0==False) and (0<>True)
> Also we can think about it as (False <= 0) and (True > 0) etc.,

All things in the engine are numbered, and when we refer to a hero, or slice, we are actually using their number.
Hence, when we assign a slice to a variable, we are actually storing its slice number, which we can easily access as a variable.

We operate on variables with
+= (add)
-= (subtract)
:= (set to)
and we can check conditions with
== (equals)
<> (not equal)
> (more than)
< (less than)

there are more operations and checks
(e.g,
division,
multiplication,
more or equal than,
less or equal than)
but thats the basic stuff.
You can see everything in the plotscripting dictionary.

Code: Select all

set slice visible(slice, on)
we can also write the number "1" or the word "true" instead of "on"

Code: Select all

IF(get slice visible(slice) == on) THEN (...
this checks if the condition is "true" (same as "on")

GLOBAL VARIABLES
If you wanted to store the health as a (global) variable, you could increase it when the player receives healing from a pickup or decrease it when they get bonked by a dinosaur.
You can check to see if the health is 0 (or less!) and make the player character die.

Code: Select all

Global Variable (100, Player Health)
Global Variable (101, Player Mana)
This declares the Global Variables

Code: Select all

Player Health += 1
Player Health -= Player Mana
Player Health := Maximum Health
Player Mana := 0
This adds 1 to Health,
decreases the value of Player Mana from Player Health,
sets the Health to the number in "Maximum Health"
and sets the Mana to 0, in that order.

Every Global Variable needs a unique number and name!
We can ask for Global Variables by their unique name or number.
Such as

Code: Select all

Read Global(100)

Code: Select all

Player Health

Both exactly mean the same thing in the script, which is the number stored in that Global, whatever it may be.

You usually won't use Read/Write Global, but it can be very useful because we can perform operations on any numbered list (more on that later)
Most importantly, we can use Read/Write Global to get the value from a Global when we don't know which Global is going to be needed, and we can store data in them like an array. (more on Arrays later on)


CONSTANTS
A constant must have a unique name.

Code: Select all

Define Constant (1000, Maximum Health)
So whenever we write "Maximum Health" the script will interpret that as "1000"

We can say

Code: Select all

IF(Player Health == Maximum Health)THEN(...
and it will check to see if the Health is at Max

However, if you want the player to be able to increase the Max Health, you need a (global) variable, and then be able to change this when they pick up a Health Powerup or whatever.

If you want to store text, like the name of something, or a description, you would use a string or text slice.
But you shouldn't use it to store something like the heroes health, because that would be more complicated than just using a number and representing it as text.
Also, we don't need to store text, because numbers are much, much quicker.

Variables are numbers is very important, because we can do things to numbers we can't do (easily) with words.

VARIABLES
You will usually use Global Variables for information that can be accessed anywhere, at any time, independently of other scripts.
It is usually saved when the game is saved.

Otherwise you use a Variable and pass it on to other scripts as needed. They only exist when the scripts are running.
They are temporary and will not be saved.
They do not have a unique number, but they must have a unique name.
Say we have a self-contained mini-game.

Example, say you want to count how many targets the player shoots, until they reach the limit, 20.

You can declare variables like so:

Code: Select all

Variable (high score, current score, target score)
So we count each successful shot as 1, until we reach the 20.

Code: Select all

IF(Check for Hit)THEN(score += 1)
"Check for Hit" is a check to see if the condition is met.
It can be the result of a command or script.

At some point, we can check the score:

Code: Select all

IF(score == 20)THEN(Player won)
"Player Won" is the victory script, where presumably the player gets cake

You probably want to check if the victory condition is met, whenever you check if a hit was successful. You can even put them in the same script.

Then the script will run all the time to check if the player has hit targets, and if the player reached the limit.

Then the script is over, and we don't need the variable anymore.

We can even name the target to reach as a variable, and change this based on the difficulty, for example.

Code: Select all

Variable (target score)
IF(score == target score) THEN(Player Won)
Note, this will work if score is changing 1 at a time.
Otherwise if you can score multiple points for a hit, you would use
Code:
IF(score >= target score)THEN(Player Won)


But say it was timed, and we want to keep the player's score.
You might want to pass on the score to another script that gives a reward (more on passing arguments to scripts later)
But when the scripts are done with this variable, it will no longer exist.
If you need to keep it around longer, put it in a global

Code: Select all

best score := targets hit

"best score" is a global variable that persists even when the script is not running.
It is being set to the value in "targets hit"
If we want the highest score (ever), we add a check

Code: Select all

IF(targets hit>best score)THEN(best score := targets hit)
If we use a Global Variable in place of a variable, we have to account for data we assigned to it already.

Say we want to use a global for "targets hit" so we can check how many we've hit so far.

Then next time we start the script, it will remember what was in the Global and continue counting from there.

If we want to a new count we must set it to 0 so it will start counting fresh.

Code: Select all

Targets Hit := 0
Then we put this before we start counting to make it start from 0 each time.

JOYS OF A NUMBERED LIST
Numbers, especially a numbered list, can correspond to text
For example, say we have a list of elemental types for our game,

1 - Water
2 - Earth
3 - Air
4 - Fire
etc.,


When we refer to element 1 (Water) we can represent this as text to the player, rather than a number.
I guess thats more complicated than using text, such as "Water" to refer to that element,
but we can do a LOT of clever tricks with a (numbered) list, especially working through them from start to finish, or taking sections of them.
If I want the 4 elements I can ask for elements 1 through 4, one by one.
That's much easier than asking for elements "Water" through "Fire", right?

Fear not, however, if you just want to ask for an element by name, you can do that too.
We do this by defining a constant (as above)
This helps us so we can use text in place of numbers.
We can ask for "Water" and the script will know this means "1" in our numbered list, and act accordingly.
You can only define each word once, but variations/permutations are okay.

NUMBERS, WHATS THE POINT

I mentioned that numbers can represent ANY information.
A numbered list can correspond to any number of states

For example Health;
0 - Dead
1 - Wounded
2 - Healthy
etc.,

We can think of all the states as corresponding to a number, even other things like "broken arm" or "broken leg"

However, if we store the states in a single variable, we can only store one state at a time, unless we use a bitmask.

Example,

we might track the player elemental resistances

we might have 1 global variable for each elemental resistance, and represent the states according to the following
-1 = vulnerability
0 = normal
1 = absorb

or we might have all the immunities in 1 number using a bitmask to read certain digits as on or off
(1011)
can be read as (on, off, on, on), so in other words, immune to water, earth and fire.
however, bitmasks have disadvantages. you can't say
(1 0 1 -1)
but you could say
(1 0 1 2) and use 2 in place of -1. Kinda complicated tho, isn't it?

please note you have to tell the script how to interpret each number, its just a number until you use it.. the computer/script does not know the meaning of each number, so make sure you give it the right one and tell it what it is supposed to mean

PLEASE NOTE THAT YOU CANNOT LEARN EVERYTHING FROM A TUTORIAL
There are COUNTLESS techniques which you can only learn by observing them, for example, in other people's scripts, figuring them out, or reading about them somewhere.
OTHERWISE YOU WILL CONTINUALLY BE DOING THINGS IN THE MOST BASIC WAYS ONLY

Most programmers admire the application of great techniques to perform nigh-impossible tasks, or to bring complex scripts to the level where we can easily modify, understand, manipulate etc., it

Advanced Techniques, or something like that:
Not an exhaustive or comprehensive list, by any means. Or accurate.

Operations. All of the operations.
Give them to me, your operations.
We can manipulate data various ways, including adding them together and splitting them apart. This also works with words (strings). Data can be scaled to reasonable values, clamped to a ceiling or floor, or interpreted into a manageable form. We don't have to work with raw data!

Loops and lines
We can work through data continuously, or make a pass over the sections we need.
It helps to understand recursion, and not creating infinite loops by accident. Kinda metal tho, right? We need to understand grasping sections of data, and understand that data might be comprised of dimensions, like X/Y for a position, or past/future for time. Other times, we want to keep going over something and changing it repeatedly, but we don't want to write it out manually. So we must loop over the data until it conforms to our expectations. Resistance is futile.

Data application. Customised Interpretation
Making numbers mean what you want them to mean.
You can use variables to store states of any kind. They can represent time, location, arbitrary values, etc., so don't be afraid! They are whatever you want them to be. Representing everything as a number is the main thing to grasp.
A single value can even represent more than one thing!

Data management. Storage, Presentation and piping.
Making it easy to access data wherever you want
As a beginner, you often find it difficult to access the data you want easily. You can set things up so that data requires minimum handling. You must master arguments and the flow of data between scripts. You also need to be able to parse data as a human, whilst not making it mechanically obtuse.

Data handling. Offsets etc.,. Pre/Post processing data.
Manipulating data more easily, and with less work.
Handling data can be arduous, but we can compensate by processing the data, rather than managing it by hand. We can clone the data and perform operations on it, whilst preserving the original data. Of course, we can modify the original data as well, but the original value will likely be lost.

Systematic handling. Creating your own system
Having the computer do the hard work
The computer can do almost everything if we set it up right. Otherwise we have to do practically everything! Once you know some advanced techniques, the amount of work can be minimised. Look at how other games have implemented systems to understand their workings. Often times its much simpler than it appears!

Visualisation and accessibility
Working with data can be difficult. It doesn't have to be.
We can use (read: CREATE) debugging tools, trace values and even other things like create graphs or charts. A lot of times your head will swim trying to figure out what kind of value you need. You can play with data to get an intuitive feel for it, and work it out by trial and error using debug tools, rather than constantly modifying the script.

We can pass on the result of a script or command as an argument to another script.
Super important! We can pass the result of a check or operation onto another script.
Last edited by SwordPlay on Tue Jul 14, 2020 8:26 pm, edited 3 times in total.
"Imagination. Life is your creation."
Post Reply