Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions manual/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
book
6 changes: 6 additions & 0 deletions manual/book.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[book]
authors = ["ISSOtm"]
language = "en"
multilingual = false
src = "src"
title = "evscript User's Handbook"
10 changes: 10 additions & 0 deletions manual/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Summary

[Quickstart](./quickstart.md)
[Pros and cons](./pros_and_cons.md)

- [How evscript works](./overview.md)
- [Writing scripts](./scripts.md)
- [Coroutines and you](./coroutines.md)
- [The generated file](./output.md)
- [Making a driver](./driver.md)
1 change: 1 addition & 0 deletions manual/src/bytecode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Writing bytecode
1 change: 1 addition & 0 deletions manual/src/coroutines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Coroutines and you
10 changes: 10 additions & 0 deletions manual/src/driver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Writing a driver (and teaching it to evscript)

An `env` block describes how the bytecode interpreter (or "driver") is set up.
Since a game may contain multiple kinds of bytecode, `evscript` supports multiple `env` blocks; each of them must be given a name.

```evscript
env script {
// TODO
}
```
5 changes: 5 additions & 0 deletions manual/src/output.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# The generated file

`__EVSCRIPT_FILE__`

`#asm` ... `#end` (no inline `#`!!)
17 changes: 17 additions & 0 deletions manual/src/overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# How evscript works

Think of `evscript` as a fancier (and far more comfortable!) way of writing a giant pile of `db`s (data).
`evscript` will not generate code as in assembly instructions; it is moreso a configurable tool for writing data that *your* game engine will interpret.

Thus, `evscript` input files contain descriptions of how your game engine is set up (mostly `env` blocks), and then... scripts!
As many scripts, of as many kinds as you want!

## Syntax basics

First off, like all languages that strive to be practical, `evscript` supports comments: everything between `//` and the end of the same line, or between `/*` and the next `*/` is completely ignored.
These are useful for the script programmer to take notes within the script file.

Also for convenience, file inclusion is supported: the `include "path/to/other.evs";` directive acts as if the contents of the file at `"path/to/other.evs"` were copy-pasted in place of the `include` directive.
Relative paths are evaluated relative to `evscript`'s own working directory.

Another thing to keep in mind: in evscript, identifiers (think "names") can contain letters, digits, underscores `_` and dots `.`, but they must begin with a letter or underscore.
19 changes: 19 additions & 0 deletions manual/src/pros_and_cons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Pros and cons

Should you use evscript?
These (non-exhaustive) lists of pros and cons may help you decide whether it's worth the effort for you.

## Pros

- Easier and faster to write than assembly.
- Lets people design some game logic even if they can't write assembly. (Think level designers?)
- Coroutine support.
- Typically smaller than equivalent assembly.
- Often easier to debug than equivalent assembly.
- "You only pay for what you use"—no need to define any bytecode functions that you don't use.

## Cons

- Far slower than directly writing the logic in assembly.
- One extra dependency in your build process, albeit no more than a single executable.
- Requires writing a bytecode driver, which can be a little tedious.
1 change: 1 addition & 0 deletions manual/src/quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Quickstart
156 changes: 156 additions & 0 deletions manual/src/scripts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Writing scripts

Let's begin by writing some scripts.

Since evscript supports several script kinds simultaneously, the script's kind must be specified; let's say it's `npc` for now.
(We will discuss how to define script kinds, or *environments*, after explaining what scripts can do.)
Obviously, the script must have a name as well.

```evscript
npc TheScriptName {
// ...
}
```

The script's contents will be written between the braces.
(Let's not worry about the functions we call for now; assume they exist.)
For example, we could make a NPC that simply walks right once.

```evscript
npc SingleStep {
move_right();
wait();
die();
}
```

Or a NPC that walks right twice:

```evscript
npc TwoSteps {
move_right();
wait();
move_right();
wait();
die();
}
```

## Repetition

The above is neat, but not very scalable.
Fortunately, evscript supports several kinds of loops!

The first one, `repeat`, simply repeats its contents a fixed amount of time:

```evscript
npc BabySteps {
repeat 42 {
move_right();
wait();
}
die();
}
```

The second one, `loop`, repeats its contents *forever*.

```evscript
npc ToInfinityAndBeyond {
loop {
move_right();
wait();
}
die(); // This will never be executed!
}
```

`do ... while` is a little more complex: its contents are repeated, until a certain expression becomes different from 0:

```evscript
// This is a more complicated version of `BabySteps` above,
// for demonstration purposes only; please use `repeat 42` instead.
npc BabyStepsAgain {
u8 nb_steps = 42;
do {
move_right();
wait();
nb_steps -= 1;
} while nb_steps;
}
```

Whereas `do ... while` always executes its contents at least once, `while` can have them never executed at all:

```evscript
npc LoopDemo {
do {
move_right();
wait();
} while 0;
while 0 {
move_left();
wait();
}
die();
}
```

This NPC will move right once, but won't move left.

## Variables

Those were already shown in the above `do ... while` example, so let's talk about them.
Variables are things that can be used to store things—primarily numbers.
There are two types of variables: `u8` ones can store integers from 0 to 255, `u16` from 0 to 65535 (both inclusive).

As you saw in that example, variables can be modified.
`nb_steps -= 1;` is a shorthand for `nb_steps = nb_steps - 1;`—which is to say, "read the number contained in `nb_steps`, subtract 1, and write that back into `nb_steps`".

(TODO: come up with a good example for variables?)

And, as you have seen, this brings us to...

## Expressions

Again as you've seen, evscript supports a little bit of calculus.
Specifically, the following mathematical operators are supported: `+`, `-`, `*`, `/`, `%` (modulo), with the usual precedence; `-` can be used for both subtraction and negation.
Comparison is also available: `==` (is equal to), `!=` (is different from), `<`, `>`, `<=`, and `>=`.

The elementary bitwise operators `&`, `|`, and `^` are supported, as well as the bitshift operators `<<` and `>>` (arithmetic/signed left shift); as is (one's) complement, notated `!`.
And finally, the two logic combinators `&&` (and) and `||` are supported, though neither is short-circuiting (if you don't know what that means: both sides are always computed).

Two extra operators are available: `&` can be used like in C to obtain the address of a variable, and `[...]` can be used to read memory at a certain address.

## A more complex example

Let's showcase everything we've seen so far!

```evscript
// “I will look for you, I will find you, and I will kill you.”
npc LiamNeeson {
u8 npcPos;
loop {
npc_x(npcPos); // Read the NPC's X coordinate into the `npcPos` variable.
if [wPlayerX] < npcPos {
move_left();
} else if [wPlayerX] > npcPos {
move_right();
} else {
npc_y(npcPos);
if playerCoord < npcPos {
move_up();
} else if playerCoord > npcPos {
move_down();
} else {
harm_player(5); // 5 HP damage.
}
}

yield;
}
}
```

...and you may be wondering what this `yield;` line is.
The answer lies in the next chapter!
Loading