mirror of
https://github.com/polserver/polserver
synced 2026-08-13 08:23:08 -04:00
* implementation * tests * maybe fix windows compilation? * undo change of match_flag_type * switch to boost regex * move flags to BRegExp object * fix tests due to cmake 4 update * update grammar * update prettifier * move flag parsing to BRegExp ctor * add AST nodes, update instr generation and execution * copy tests but use regular expression literals * fix grammar for handling division correctly * modify return values a bit, update tests - string.match: make groups hold structs of matched, offset - string.match: add offset - string.replace: use a groups array like string.match vs individual arguments * bundle of changes - standardize error messages - add more tests for coverage - move BRegExp creation to static method: previous implementation had ctor throwing, which was no good inside executor since it didn't have a try/catch * more tests; add OT_REGEXP to basic.em * move string regex stuff to bregexp and support regex/wregex via std::visit * maybe fix compilation errors? * add unicode escape sequence handling * really maybe fix compilation error? * fix compiler warnings * refactor a bit to remove duplicate code * address discord comments - just return wstring, no need for vector<wchar_t> method * Add string.split by string and regexp * Use Max_Split instead of Limit This makes it match basic::SplitWords * add support for empty string delim in SplitWords * remove duplicate code across string.split and mf_SplitWords * Squashed commit of the following: commitb3148e069fAuthor: turleypol <turley@polserver.com> Date: Sat Sep 27 17:02:22 2025 +0200 memorylocation of input string is not allowed to changed, switched back to uniqueptr commit5a4d1c8fcbAuthor: turleypol <turley@polserver.com> Date: Sat Sep 27 10:18:01 2025 +0200 no need to use ptr for input commit90fa0edc66Author: turleypol <turley@polserver.com> Date: Sat Sep 27 09:56:29 2025 +0200 fixed typo commitbed4ff3ac9Author: turleypol <turley@polserver.com> Date: Sat Sep 27 09:47:36 2025 +0200 make Callback for BContinuation move only * use uninit when group isn't matched * fix multiline flag handling; add test * add docs and doc example tests * some cleanup * address review comments - allow move assignment * add core-changes
4280 lines
141 KiB
HTML
4280 lines
141 KiB
HTML
<h1>
|
||
Racalac's eScript Reference and Guide (POL 100.2.0)
|
||
<div style="font-size: 0.82em">(Last Updated: November 15, 2025)</div>
|
||
</h1>
|
||
<br/>
|
||
|
||
<!-- TODO:
|
||
- talk about ecompile.cfg and recursive compiling, mention POL ignores
|
||
files starting with '.'
|
||
- talk about escape sequences in string, do not forget "\xFF"
|
||
-->
|
||
|
||
<br/>
|
||
|
||
<p><b>Foreword:</b><br>This reference is targeted to be used and understood by
|
||
scripters who have at least a little experience in other procedural-type
|
||
languages. If you have never done any type of scripting or programming before,
|
||
I'd suggest that you look for a class on BASIC or Pascal in your school or
|
||
college. If you're not in college, think about buying a "dummies" book on
|
||
programming from your local book store. Any of these methods will make learning
|
||
and writing eScript easier and quicker for you. And on the other extreme, my
|
||
apologies if I explain some things in annoyingly simple terms.</p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3>Table of Contents</h3>
|
||
|
||
<p><b><a href="#chap1">Chapter 1:</a></b>
|
||
</p><ul>
|
||
<li><a href="#chap1a">Variable Declaration and Assignment</a>
|
||
</li><li><a href="#chap1aa">Sequence and Index Binding Statements</a>
|
||
</li><li><a href="#chap1b">Arithmetic</a>
|
||
</li><li><a href="#chap1c">Comments</a></li></ul>
|
||
<p></p>
|
||
|
||
<p><a href="#chap2"><b>Chapter 2: Brief Review of Data Structures </b></a>
|
||
</p><ul>
|
||
<li><a href="#chap2a">Arrays</a>
|
||
</li><li><a href="#chap2b">Structures</a></li><li><a href="#chap2c">Dictionaries</a></li></ul>
|
||
<p></p>
|
||
|
||
<p><b><a href="#chap3">Chapter 3: Conditionals and Iteration</a></b>
|
||
</p><ul>
|
||
<li><a href="#chap3a">If-statements</a>
|
||
</li><li><a href="#chap3b">Binary Operators</a>
|
||
</li><li><a href="#chap3b2">Conditional (Ternary) Operator</a>
|
||
</li><li><a href="#chap3c">Case (switch) statements</a>
|
||
</li><li><a href="#chap3d">Iteration</a></li></ul>
|
||
<p></p>
|
||
|
||
<p><b><a href="#chap4">Chapter 4:</a></b>
|
||
</p><ul>
|
||
<li><a href="#chap4a">Functions and Parameters</a>
|
||
</li><li><a href="#chap4b">Including Code from Other Files</a></li></ul>
|
||
<p></p>
|
||
|
||
<p><b><a href="#chap5">Chapter 5:</a></b>
|
||
</p><ul>
|
||
<li><a href="#chap5a">Scripts</a>
|
||
</li><li><a href="#chap5b">Compiling</a></li></ul>
|
||
<p></p>
|
||
|
||
<p><b><a href="#chap6">Chapter 6: Built-in Properties and the POL Object Reference</a></b></p>
|
||
|
||
<p><b><a href="#chap7">Chapter 7:</a></b>
|
||
</p><ul>
|
||
<li><a href="#chap7a">CProps</a>
|
||
</li><li><a href="#chap7b">CProps on Accounts</a></li></ul>
|
||
<p></p>
|
||
|
||
<p><b><a href="#chap8">Chapter 8: Config File Usage and Access</a></b></p>
|
||
|
||
<p><b><a href="#chap9">Chapter 9: Packages</a></b></p>
|
||
|
||
<p><b><a href="#chap10">Chapter 10: Debugging</a></b></p>
|
||
|
||
<p><b><a href="#chap11">Chapter 11: Advanced Data Types and Functions</a></b>
|
||
|
||
</p>
|
||
<ul>
|
||
<li><a href="#chap11a">Global Properties</a></li>
|
||
<li><a href="#chap11b">Arrays</a></li>
|
||
<li><a href="#chap11c">Structs</a></li>
|
||
<li><a href="#chap11d">Dictionaries</a></li>
|
||
<li><a href="#chap11e">Function Calls by Reference</a></li>
|
||
<li><a href="#chap11f">Interpolated Strings</a></li></li>
|
||
<li><a href="#chap11g">Function Objects</a></li></li>
|
||
<li><a href="#chap11h">Function Expressions</a></li></li>
|
||
<li><a href="#chap11i">Spread Operator</a></li>
|
||
<li><a href="#chap11j">Regular Expressions</a></li>
|
||
</ul>
|
||
|
||
<p><b><a href="#chap12">Chapter 12: Classes</a></b></p>
|
||
<ul>
|
||
<li><a href="#chap12a">Advanced Techniques</a>
|
||
</ul>
|
||
|
||
|
||
<p><b><a href="#app2">Appendix A: Gump Tag Descriptions</a></b></p>
|
||
|
||
<p><b><a href="#appB">Appendix B: Operator Precedence</a></b></p>
|
||
|
||
<p><b><a href="#appC">Appendix C: Functional Programming with Arrays</a></b></p>
|
||
|
||
<p><b><a href="#appD">Appendix D: Variadic User Functions</a></b></p>
|
||
|
||
<p><b><a href="#appE">Appendix E: Iterable Objects</a></b></p>
|
||
|
||
<p><b><a href="#appX">Appendix X: Revision History</a></b></p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap1">Chapter 1</a></h3>
|
||
<br/>
|
||
<p><b><a name="chap1a">Variable Declaration and Assignment; Arithmetic</a></b></p>
|
||
|
||
<p>There are no strict variable types in eScript, but there are a few types you
|
||
can cast (convert) to: integer (whole number), real (float; integer with decimal
|
||
part), and string (text). It is simple to declare a new variable:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var my_variable;</pre></div></p>
|
||
|
||
<p>Depending where you declare this in your program depends on when you can have
|
||
access to that variable. This is called the variable's scope. If you place the
|
||
above line outside a function block, it is visible to all functions in the
|
||
program (known as a 'global' variable). If you place that line inside a function
|
||
block, it is accessable no matter where you currently are in that function. If
|
||
you delcare it inside a code block (i.e. between if-endif, for-endfor, etc), it
|
||
is only usable inside that block. Note in older scripts you may see variable
|
||
declared with 'local' and 'global'. The first is the same as 'var' inside a
|
||
function and the second is the same as 'var' outside a function. You should
|
||
always use 'var' instead of these older keywords to declare your variables.</p>
|
||
|
||
<p>Okay, now we have some variables, but now to put some data into them so we
|
||
can use them in the script. You can do this either at declaration-time or later
|
||
in the script. The syntax for this in eScript is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>my_variable := 10;</pre></div></p>
|
||
|
||
<p>The ":=" (colon + equals) operator assigns the right-hand-value to the
|
||
left-hand variable. A lot of different expressions can be used on the
|
||
right-hand-side. Some of these include numbers (such as above), other variables,
|
||
mathematical expressions, function calls, and more. You can perform these at
|
||
declaration-time like: var number_of_pies := 15; </p>
|
||
|
||
<p>Variables that are not given any initializer will be set to the
|
||
"uninitialized value". This is equivalent to the concept of <code>NULL</code>,
|
||
<code>nil</code>, and <code>None</code> in other programming languages. Starting
|
||
from eScript Compiler version v1.17, the eScript keyword for the uninitialized
|
||
value is <code>uninit</code> and can be used in any place expressions are
|
||
used.</p>
|
||
|
||
<p>Additionally, starting from eScript Compiler version v1.17, eScript boolean
|
||
keywords `true` and `false` can be used, equivalent to `Boolean(1)` and `Boolean(0)`
|
||
respectively.</p>
|
||
|
||
<p>To declare a "constant," or a variable that you can only read its value from,
|
||
you must do it at the top of the file, before any of the functions, much like
|
||
declaring a global variable since constants are global themselves. Whenever the
|
||
compiler sees a constant in an expression, the value of that constant is
|
||
substituted instead. The syntax for this is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>CONST MY_CONSTANT := 47;</pre></div></p>
|
||
|
||
<p>The use of constants is key in well-written, readable code. They remove the
|
||
ambiguity of having raw numbers thrown around in a script by giving a meaning to
|
||
them. It is a good idea to use the convention of declaring constants in ALL CAPS
|
||
since most programmers are used to it.</p>
|
||
|
||
<p>Example snip of code (doesn't do much but show different ways of declaring
|
||
variables):</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>CONST SIZE_OF_TRAY := 15;<br>var pies_in_tray := SIZE_OF_TRAY;</pre></div></p>
|
||
|
||
<br/>
|
||
|
||
<p>Constants can be logically grouped using an <code>enum</code> declaration:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>enum Colors
|
||
RED := "#ff0000",
|
||
GREEN := "#00ff00",
|
||
BLUE := "#0000ff"
|
||
endenum
|
||
|
||
print( RED ); // prints "#ff0000"
|
||
</pre>
|
||
</div>
|
||
|
||
If not providing a value for an enum entry, the compiler will assign the next
|
||
available integer value, starting from 0. For example, the following enum
|
||
declaration will assign the values 0, 1, and 2 to the entries:
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>enum Numbers
|
||
ZERO,
|
||
ONE,
|
||
TWO
|
||
endenum
|
||
|
||
print( ZERO ); // prints 0
|
||
print( ONE ); // prints 1
|
||
print( TWO ); // prints 2
|
||
</pre>
|
||
|
||
</div>
|
||
<br/>
|
||
|
||
<p>Added in POL 100.2.0: An enum declaration can use the <code>class</code>
|
||
keyword to create a class-like enum, which allows the constants to be scoped to the
|
||
enum name:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>enum class Races
|
||
HUMAN := "Human",
|
||
ORC := "Orc",
|
||
ELF := "Elf"
|
||
endenum
|
||
|
||
print( Races::HUMAN ); // Prints: "Human"
|
||
</pre>
|
||
</div>
|
||
|
||
<br/>
|
||
<p><b><a name="chap1aa">Sequence and Index Binding Statements</a></b></p>
|
||
|
||
<br />
|
||
<p>Added in: POL 100.2.0</p>
|
||
<br />
|
||
|
||
<p>The binding statement syntax makes it possible to unpack values from into
|
||
distinct variables either sequentially or by index accessor.</p>
|
||
<br/>
|
||
|
||
<p>A binding statement loops over the object's <i>iterator</i>, so any object
|
||
<code>obj</code> that can be used in a <code>foreach value in obj</code>
|
||
statement is supported. See <a href="#appE">Appendix E: Iterable Objects</a> for
|
||
a list of supported iterable objects.
|
||
</p>
|
||
<br/>
|
||
|
||
<p>For arrays and other sequential objects, the <strong>sequence
|
||
binding</strong> syntax is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var [ a, b, c ] := array{1, 2, 3};
|
||
|
||
print( a ); // 1
|
||
print( b ); // 2
|
||
print( c ); // 3
|
||
</pre>
|
||
</div>
|
||
|
||
<p>This statement will iterate over the value on the right-hand side, and assign
|
||
each value to the corresponding variable on the left-hand side sequentially.</p>
|
||
<br/>
|
||
|
||
<p>For accessing objects via an index, the <strong>index binding</strong> syntax
|
||
is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var { a, b, c } := dictionary{ "a" -> 1, "b" -> 2, "c" -> 3 };
|
||
|
||
print( a ); // 1
|
||
print( b ); // 2
|
||
print( c ); // 3</pre></div>
|
||
|
||
<p>This statement will access the right-hand side, assigning each value to the
|
||
corresponding variable on the left-hand side using the the subscript operator
|
||
<code>[]</code> of the variable name.</p>
|
||
<br/>
|
||
|
||
<p>An index binding can be named differently than the accessing index. For
|
||
example, we can access <code>b</code> from the dictionary, but name it as
|
||
<code>b_value</code>:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var { a, b: b_value } := dictionary{ "a" -> 1, "b" -> 2, "c" -> 3 };
|
||
|
||
print( a ); // 1
|
||
print( b_value ); // 2</pre></div>
|
||
|
||
<p>This allows us to use <i>any expression</i> as the index accessor, as long as
|
||
we name it. For example, we want to access the the numeric <code>5</code> key in
|
||
a dictionary:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var { [5]: five_value } := dictionary{ 5 -> "five" };
|
||
print( five_value ); // "five"</pre>
|
||
</div>
|
||
|
||
<p>Binding statements can be nested:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var [ firstElement, { b, c } ] := array{ 1, struct{ b := 2, c := 3 } };
|
||
print( firstElement ); // 1
|
||
print( b ); // 2
|
||
print( c ); // 3</pre>
|
||
</div>
|
||
|
||
<p>A binding statement can have a <i>rest binding</i>, using <code>...</code> in
|
||
the variable binding. This will put all remaining elements in the rest variable.
|
||
For <strong>sequence bindings</strong>, the rest variable will be an array, and
|
||
can be placed anywhere within the variable binding list:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var [ first, middle..., last ] := array{ 1, 2, 3, 4, 5 };
|
||
print( first ); // 1
|
||
print( middle ); // {2, 3, 4}
|
||
print( last ); // 5
|
||
</pre></div>
|
||
<br/>
|
||
|
||
<p>For <strong>index bindings</strong>, the rest variable will be a dictionary,
|
||
and <strong>must</strong> be placed at the end of the variable binding list:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var { name, age, other_details... } := struct{
|
||
name := "John",
|
||
age := 30,
|
||
birthdate := "1990-01-01",
|
||
address := "123 Main St"
|
||
};
|
||
|
||
print( other_details ); // dict{ "address" -> "123 Main St", "birthdate" -> "1990-01-01" }
|
||
</pre></div>
|
||
<br/>
|
||
|
||
<p><b><a name="chap1b">Arithmetic</a></b></p>
|
||
|
||
<p>This stuff is easy, the expression on the left of the assignment operator is
|
||
evaluated and placed into the variable on the right side.</p>
|
||
|
||
<p>Arithmetic expressions are evaluated first inside parenthesis then from
|
||
left-to-right. Such as:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var pies_used := pies_used + 1; // Increment 'pies_used' by 1
|
||
var pies_left := number_of_trays * (pies_in_tray – pies_used);
|
||
</pre></div>
|
||
|
||
<p>The math operators in
|
||
eScript are:</p>
|
||
|
||
<table border="1" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" id="AutoNumber1">
|
||
<tr>
|
||
<td align="center">Operator</td>
|
||
<td align="center">Meaning</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="center">+</td>
|
||
<td align="center">Addition</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="center">-</td>
|
||
<td align="center">Subtraction</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="center">*</td>
|
||
<td align="center">Multiplication</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="center">/</td>
|
||
<td align="center">Division</td>
|
||
</tr>
|
||
<tr>
|
||
<td align="center">%</td>
|
||
<td align="center">Modulus</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">+=</td>
|
||
<td align="center">Addition Assign</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">-=</td>
|
||
<td align="center">Subtraction Assign</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">*=</td>
|
||
<td align="center">Multiplication Assign</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">/=</td>
|
||
<td align="center">Division Assign</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">%=</td>
|
||
<td align="center">Modulus Assign</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">++</td>
|
||
<td align="center">Unary Increment</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">--</td>
|
||
<td align="center">Unary Decrement</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">>></td>
|
||
<td align="center">Bit-Shift right</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center"><<</td>
|
||
<td align="center">Bit-Shift left</td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">&</td>
|
||
<td align="center">Bitwise <b>AND</b></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">|</td>
|
||
<td align="center">Bitwise <b>OR</b></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">^</td>
|
||
<td align="center">Bitwise <b>XOR</b></td>
|
||
</tr>
|
||
|
||
<tr>
|
||
<td align="center">~</td>
|
||
<td align="center">Ones Complement</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h3><b>Assign, Unary, and Bitwise Operators</b></h3>
|
||
<h4><b>The Assign Operators:</b></h4>
|
||
|
||
<p>These operators perform the mathematical operation and then assign the result to the variable
|
||
on the left. Using these operators simplifies coding. Instead of writing:</P>
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
x := x + 5
|
||
</pre></div>
|
||
you can write:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
x += 5.
|
||
</pre></div>
|
||
|
||
<h4><b>The Unary Operators:</b></h4>
|
||
|
||
<p>For those unfamiliar with the unary operators, a brief explanation of their
|
||
use is in order. Examples of unary operator syntax is, ++i, i++,--i, and i--.
|
||
The 'i' can be any named variable.
|
||
These function as another shorthand for incrementing and decrementing a variable.
|
||
They do act differently though depending on whether the operator, ++ or -- precedes or
|
||
follows the variable. If the operator precedes the variable, as in ++i, that
|
||
is equivalent to i += 1. If the operator follows the variable, as in i++, then
|
||
i is incremented after any assignment of the value of i might have taken place.</p>
|
||
Example:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var i := 5;
|
||
var j :=0;
|
||
j := i++;
|
||
...
|
||
</pre></div>
|
||
After executing that code snippet, j will be equal to 5 and i will be equal to 6.
|
||
|
||
As these are unary operators they can be used directly as a function parameter
|
||
or in loops, eg. the while loop example below.
|
||
Instead of writing:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
while (i<5)
|
||
i+=1;
|
||
...
|
||
</pre></div>
|
||
You can save a line of code by writing:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
while (++i<5)
|
||
...
|
||
</pre></div>
|
||
<p>I should note that the assign and unary operators were added after the majority of
|
||
this guide was written. So most, if not all, of the example code in
|
||
this guide will use the longer forms of expressions, for readability, but mostly because
|
||
we are too lazy to edit the entire guide.</p>
|
||
|
||
<h4><b>The Bitwise (sometimes called Logical) Operators:</b></h4>
|
||
|
||
<h4>Bitwise <b>AND</b></h4>
|
||
The single & (ampersand) symbol will perform a logical <b>AND</b> of the value on the left of the operator with the value on the right.
|
||
If we have a statement
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var value := 10 & 14;
|
||
</pre></div>
|
||
The result will equal 10. What is actually happening is that eScript will AND the binary value of 10, 1010, with the binary value of 14, 1110.
|
||
<p>Every 1 bit in the value on the left that corresponds to a 1 bit in the same position in the value on the right produces a 1 bit in that position in the result. You can see this visually in the table below.</p>
|
||
<table border="1" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||
<tr>
|
||
<td>Value: 10</td><td>1</td><td>0</td><td>1</td><td>0</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Value: 14</td><td>1</td><td>1</td><td>1</td><td>0</td>
|
||
</tr>
|
||
<tr>
|
||
<td><b>AND</b> (10)</td><td>1</td><td>0</td><td>1</td><td>0</td>
|
||
</tr>
|
||
</table>
|
||
<br>
|
||
<h4>Bitwise <b>OR</b></h4>
|
||
|
||
<p>The single | (bar) symbol will perform a logical <b>OR</b> of the value on the left of the operator with the value on the right. If we have a statement</P>
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var value := 10 | 6;
|
||
</pre></div>
|
||
<p>The result will equal 14. Escript will <b>OR</b> the binary value of 10, 1010, with the binary value of 6, 0110. Where there is a 1 bit in either the value on the left or the value on the right, or both bits are 1, produces a 1 bit in the result. The table below helps you visualize this.</p>
|
||
|
||
<table border="1" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||
<tr>
|
||
<td>Value: 10</td><td>1</td><td>0</td><td>1</td><td>0</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Value: 6</td>
|
||
<td>0</td>
|
||
<td>1</td><td>1</td><td>0</td>
|
||
</tr>
|
||
<tr>
|
||
<td><b>OR</b> (14)</td>
|
||
<td>1</td>
|
||
<td>1</td>
|
||
<td>1</td><td>0</td>
|
||
</tr>
|
||
</table>
|
||
<br>
|
||
<h4>Bitwise <b>XOR</b></h4>
|
||
<p>
|
||
The ^ (caret) will perform a logical <strong>XOR</strong>, or exclusive <strong>OR</strong>, of the value on the left of the operator with the value on the right. If we have a statement:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var value := 10 ^ 12;
|
||
</pre></div>
|
||
The result will equal 6. This time eScript will <strong>XOR</strong> the binary value of 10, 1010, with the binary value of 12, 1100. Where there is a 1 bit in either the value on the left or the value on the right produces a 1 bit in the result. Where there is a 0 or a 1 in both bits produces a 0. Again, see the table below.</p>
|
||
|
||
|
||
<table border="1" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||
<tr>
|
||
<td>Value: 10</td><td>1</td><td>0</td><td>1</td><td>0</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Value: 12</td>
|
||
<td>1</td>
|
||
<td>1</td>
|
||
<td>0</td>
|
||
<td>0</td>
|
||
</tr>
|
||
<tr>
|
||
<td><b>XOR</b> (6)</td>
|
||
<td>0</td>
|
||
<td>1</td>
|
||
<td>1</td><td>0</td>
|
||
</tr>
|
||
</table>
|
||
<br>
|
||
<h4><strong id="docs-internal-guid-f9b28dc1-7fff-cec3-02c5-0ed74c4fce53">Ones’ complement</strong></h4>
|
||
<p>
|
||
The ~ (tilde) symbol will perform a ones’ complement on the value to the right of the operator. A ones’ complement operation inverts all the bits in an integer. 1s are flipped to 0s and 0s are flipped to 1s. The following statement will return -2 or in hexadecimal 0xFFFFFFFE.
|
||
Var value := ~1;
|
||
In a 32 bit hexadecimal representation the value 1 is 0x00000001 or, in binary
|
||
0000 0000 0000 0000 0000 0000 0000 0001
|
||
If you invert the bits, ones’ complement, you end up with the result, in hexadecimal, of 0xFFFFFFFE or in binary
|
||
1111 1111 1111 1111 1111 1111 1111 1110
|
||
Quoting “The Book of Knowledge”, Wikipedia: <em>“The ones' complement of the number then behaves like the negative of the original number in some arithmetic operations. To within a constant (of -1), the ones' complement behaves like the negative of the original number with binary addition. However, unlike two's complement, these numbers have not seen widespread use because of issues such as the offset of -1, that negating zero results in a distinct negative zero bit pattern, less simplicity with arithmetic borrowing, etc.”</em>.
|
||
|
||
|
||
<h3>In Addition</h3>
|
||
<p>I should mention something about variable types in arithmetic, especially
|
||
division. If you divide two integers together such that the result would have a
|
||
decimal part, POL will only look at the whole number part. To make sure the
|
||
result is a real (integer+decimal part), make sure at least one of the operands
|
||
is a real. You can make sure of this by using a raw number with a decimal part
|
||
(such as 100.0), or "cast" it to a real (convert the type). There are a few
|
||
casting functions in eScript, CInt(), CStr(), CDbl().</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
CInt(100.3) // Results in 100
|
||
CStr(100); // Results in a string of "100"
|
||
// This now cannot be used in mathematical expressions.
|
||
CDbl(100); // Results in 100.0
|
||
</pre></div>
|
||
|
||
<p>Additional conversion functions in basic.em</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Hex(100); // Results in a string as "0x64"
|
||
Bin(100); // Results in a string as "1100100"
|
||
// CInt() will not properly convert this string to its decimal value.
|
||
CAsc("A"); // Results in an integer of 65
|
||
CChr(65); // Results in a string as "A"
|
||
</pre></div>
|
||
|
||
<p><b><a name="chap1c">Bonus Topic: Comments</a></b></p>
|
||
|
||
<p>Commenting your code is of utmost importance. Comments allow you to add
|
||
arbitrary text to explain whatever you need to without disrupting the script's
|
||
functionality. Comments are also used to remove code from execution without
|
||
actually deleting it (known as "commenting out code"). In eScript there are a
|
||
couple ways to comment your code:</p>
|
||
|
||
<ol>
|
||
<li>
|
||
<p>Any text after "//" will be considered a comment until the end of the line.
|
||
The next line will not be considered a comment. To make it a comment, add
|
||
another "//" before your comment. This is the best way to make short comments
|
||
because it allows you to comment out large block of code using "/* */"
|
||
(below).</p>
|
||
</li><li>
|
||
<p>Any text after "/*" and before "*/" is considered a comment. Using this,
|
||
you can comment out large blocks of code just by placing a /* at the beginning
|
||
and / at the end of the code. You cannot "nest" this type of comment, as the
|
||
next "*/" signals the end of the comment, even if another "*/" is found after
|
||
the first. This is why we recommend you comment most things with "//" to avoid
|
||
this.<br>
|
||
</p></li></ol>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap2">Chapter 2</a></h3>
|
||
<br/>
|
||
<p><b>Brief Review of Data Structures</b></p>
|
||
|
||
<p>Okay, so we can make integer, real, or string variables. To do any sort of
|
||
useful scripting, we also need some data structures. I will discuss arrays, structures
|
||
and dictionaries in this chapter.<br>
|
||
</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap2a">Arrays</a></b></p>
|
||
|
||
<p>Arrays are one-based, random access collections of objects. That means you
|
||
can access any place in the array from 1 (the first element) up to X (the last
|
||
element). Let's first look how you can declare an array. </p>
|
||
|
||
<p>To create an array variable, declare:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array; // empty array
|
||
var b := array{5, 32, "hello", "world"}; // initialized array
|
||
var c := array{array{1,2}, array{3,4,5}}; // array containing arrays
|
||
</pre></div>
|
||
|
||
<p>An array can be assigned to any other variable, even if that variable was not
|
||
declared an array:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array{2, 4, 6, 8};
|
||
var b;<br>b := a;</pre></div>
|
||
|
||
<p>Similarly, if a function returns an array (we will discuss this later), no
|
||
special declaration is needed:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a;
|
||
a := FunctionThatReturnsAnArray();</pre></div>
|
||
|
||
<p>In some other programming languages, you cannot access (read or write) past
|
||
the end of the declared size of the array. In eScript, arrays grow automatically
|
||
without access errors:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array;
|
||
a[1] := 4;
|
||
a[4] := 7;</pre></div>
|
||
|
||
<p>Arrays elements can be any type of object, including another array:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array{};
|
||
var b := array{};
|
||
a[1] := 5;
|
||
b[1] := a;
|
||
b[2] := 6;<pre></div>
|
||
|
||
<p>The following are equivalent methods of looping through an array. The
|
||
'foreach' method is much more efficient, as well as being more convenient. Note
|
||
that we will discuss these kind of loops and more next chapter.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array{2,4,6,8};
|
||
|
||
var i;
|
||
for(i:=1; i<=a.Size(); i:=i+1)
|
||
Print(a[i]);
|
||
endfor
|
||
|
||
foreach i in ( a )
|
||
Print(i);
|
||
endforeach</pre></div>
|
||
|
||
<p>You can then use the array for whatever you need, such as passing more
|
||
than one variable back to a function (functions explained later), or when a core
|
||
function requires it. <br><br>
|
||
|
||
<p>Suppose you want to find out if the value in the variable "name" exists in
|
||
an array named "people". You can do something like the following to:<br>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
foreach person in people
|
||
if(person == name)
|
||
return _person_iter;
|
||
endif</pre></div>
|
||
|
||
or you can do something even simpler:<br>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var in_array := name in people;</pre></div>
|
||
|
||
in_array will be set to the ordinal position where the value in name exists
|
||
in the array or if it is not in the array in_array will be set to 0.<br><br>
|
||
|
||
Also, there are a few array-specific functions that are
|
||
explained later (such as array.Insert() and others).</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap2b">Structures</a></b></p>
|
||
|
||
<p>Structures are an object-oriented data type with various members or
|
||
properties that are part of them that contain the actual data.</p>
|
||
|
||
<p>To access members, use the '<b>.</b>' operator:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Print(a.height);
|
||
Print(a.width);</pre></div>
|
||
|
||
<p>To create an structure variable, declare:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := struct; // empty struct
|
||
var b := struct{"height", "width"}; // struct with members that have no values.
|
||
var c := struct{"height":=5, "width":=100}; // struct with members and values.
|
||
</pre></div>
|
||
|
||
<p>To add new members, use the '<b>.+</b>' operator:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a:= struct;
|
||
a.+height := 7;
|
||
a.+width;
|
||
|
||
// Assign an existing member
|
||
a.width := 5;</pre></div>
|
||
<br/>
|
||
<p><a name="chap2c"><b>Dictionaries</b></a></p>
|
||
|
||
<p>Dictionaries are arrays whose elements are named. They are often referred to
|
||
as 'associative arrays'</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Print(a["height"]);
|
||
Print(a["width"]);</pre></div>
|
||
|
||
<p>To create an structure variable, declare:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := dictionary; // empty dictionary
|
||
var b := dictionary{"height", "width"}; // dictionary with indexes that have no values.
|
||
var c := dictionary{"height"->5, "width"->100}; // dictionary with indexes and values.
|
||
</pre></div>
|
||
|
||
<p>Dictionaries automatically add new indexes when they are set.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a:= dictionary;
|
||
a["height"] := 7;
|
||
a["width"] := 100;</pre></div>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap3">Chapter 3</a></h3>
|
||
<br/>
|
||
<p><b>Conditionals and Iteration</b></p>
|
||
|
||
<p>We'll cover two topics in this chapter: IF-statements and loops. </p>
|
||
<br/>
|
||
<p><b><a name="chap3a">If-statements</a></b></p>
|
||
|
||
<p>If-statements are absolutely needed in every script so it's necessary you
|
||
understand them. If statements simply let your script make decisions based on
|
||
the criteria you give it. The general syntax is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
if(statement)
|
||
// code
|
||
elseif(statement)
|
||
// code
|
||
elseif(statement)
|
||
// code
|
||
else
|
||
// code
|
||
endif</pre></div>
|
||
|
||
<p>Notice you can have any number of (optional)"elseif" statements between the
|
||
"if" and the (optional) "else".<br>
|
||
The key part in the syntax above is "statement".
|
||
When the script runs, it will check the first "statement" to see if it is true.
|
||
<br>
|
||
If it is not, it'll proceed to check the next "statement" until either it finds
|
||
one that is true, or hits the "else" statement (if any).</p>
|
||
|
||
<p>The syntax for "statement" is</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
variable1 {operator variable2} ...</pre></div>
|
||
<p>Some examples of evaluating to true expressions are:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var var1 := 10;
|
||
var var2 := 5;
|
||
|
||
if (var1 > var2) //TRUE
|
||
|
||
if ((var1 – 5) == var2) //TRUE
|
||
|
||
if (var2 < var1) //TRUE
|
||
|
||
if ((var2+5) >= var2) //TRUE<
|
||
|
||
if (var1 != var2) //TRUE
|
||
</pre></div>
|
||
|
||
<p>The logical operators in eScript are (evaluated left-to-right)</p>
|
||
|
||
<p>== equal-to<br>!= not-equal-to<br>> greater-than<br>< less-than
|
||
<br><= less-or-equal-to <br>>= greater-or-equal-to<br>is</p>
|
||
|
||
<p>Also, you can use the Boolean operators:</p>
|
||
|
||
<table border="0" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" id="AutoNumber2">
|
||
<tr>
|
||
<td> <b>||</b> or "<b>or</b>"</td>
|
||
<td> // <b>||</b> is the preferred method.</td>
|
||
</tr>
|
||
<tr>
|
||
<td> <b>&&</b> or "<b>and</b>" </td>
|
||
<td> // <b>&&</b> is the preferred method. </td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p>For example:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
if ( (var1 > var2) || (var1 == 5) )
|
||
// TRUE since at least one of the individual expressions is true. This is inclusive OR so all expressions may
|
||
// be true and the whole statement is true.
|
||
|
||
if ( (var1 > var2) or (var1 ==5) )
|
||
//this is same as above, except using "or" in place of "||" for readability.
|
||
|
||
if ( (var1 > var2) && (var1 == 5) )
|
||
//FALSE, since not ALL expressions are true.
|
||
|
||
if ( (var1 > var2) and (var1 == 10) )
|
||
//TRUE, since both expressions are true. Uses "and" in place of "&&"
|
||
</pre></div>
|
||
|
||
<p>You will use If statements in all but the most simple scripts you write. You
|
||
should understand what you want to do before throwing a conditional statement
|
||
together, as it is possible to mess it up:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
if ( score < 60 )
|
||
Print("You got less than 60");
|
||
elseif ( score == 50 )
|
||
Print("You got 50!");
|
||
endif</pre></div>
|
||
|
||
<p>This is poor scripting, as if your score was 50, the first statement would be
|
||
true (printing "You got less than 60"), and the elseif(score == 50) line would
|
||
never be printed, even though it is a more specific check than the previous
|
||
line. </p>
|
||
|
||
<p>Also, in eScript anything that is zero is considered to be false, and
|
||
anything non-zero is true. So you can have an if-statement without any logical
|
||
operators:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var valid := 1;
|
||
if( valid )
|
||
// do stuff
|
||
else
|
||
// do other stuff
|
||
endif</pre></div>
|
||
|
||
<p>Or:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
if ( !valid ) //same as "if valid is non-zero, then false"
|
||
// do stuff
|
||
endif</pre></div>
|
||
<br/>
|
||
<p><b><a name="chap3b">Binary Operators</a></b></p>
|
||
<br/>
|
||
<p><b>Elvis operator:</b></p>
|
||
<p>Short-circuit binary operator EXPR_LHS ?: EXPR_RHS<br/>
|
||
This operator evaluates the left-hand-side operand and keeps its value if it is a true value.<br/>
|
||
Otherwise, evaluates the right-hand side operand and uses its value instead.<br/>
|
||
This is a short-circuit operator: if EXPR_LHS is true, the code for EXPR_RHS won't be executed.<br/>
|
||
These can also be changed: A ?: B ?: C ?: D evaluates to the first true value from left to right.<br/>
|
||
It has lower precedence than the binary additive operators (+ -), and higher precedence than the binary comparison operators (> >= < <=).<br/>
|
||
These are equivalent with or without parenthesis:<br/>
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
a ?: b + c a ?: ( b + c ) // lower precedence than addition<br/>
|
||
a ?: b <= c (a ?: b) <= c // higher precedence than comparison<br/></pre></div>
|
||
See also https://en.wikipedia.org/wiki/Elvis_operator<br/>
|
||
For example, you could change this:<br/>
|
||
<div class="doc-guide-pre">
|
||
<pre>var difficulty;<br/>
|
||
if(targetsquare.objtype)<br/>
|
||
difficulty := GetHarvestDifficulty("fish", targetsquare.x, targetsquare.y, targetsquare.objtype, who.realm);<br/>
|
||
else<br/>
|
||
difficulty := GetHarvestDifficulty("fish", targetsquare.x, targetsquare.y, locinfo.landtile, who.realm);<br/>
|
||
endif<br/></pre></div>
|
||
to this:
|
||
<div class="doc-guide-pre">
|
||
<pre>var difficulty := GetHarvestDifficulty("fish",<br/>
|
||
targetsquare.x, targetsquare.y,<br/>
|
||
targetsquare.objtype ?: locinfo.landtile,<br/>
|
||
who.realm);</pre></div></p>
|
||
|
||
<p><b><code>is</code> operator:</b></p>
|
||
|
||
The <code>is</code> operator can be used to check if the left operand (typically
|
||
a class instance) is an instance of the right operand (typically a function
|
||
reference). See <a href="#chap12">Chapter 12</a> for more information.<br/>
|
||
|
||
<p><b><a name="chap3b2">Conditional (Ternary) Operator</a></b></p>
|
||
<br />
|
||
<p>Added in: POL 100.1.0</p>
|
||
<br />
|
||
<p>The conditional operator is a commonly used shortcut for the if statement, to
|
||
use one of two values depending on a conditional. The operator takes three
|
||
operands: a condition followed by a question mark (?), then an expression to
|
||
execute if the condition is true followed by a colon (:), and finally the
|
||
expression to execute if the condition is false.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
condition ? exprIfTrue : exprIfFalse
|
||
</pre></div>
|
||
|
||
The following two functions are equivalent in behavior:
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function example()
|
||
return condition1 ? value1
|
||
: condition2 ? value2
|
||
: condition3 ? value3
|
||
: value4;
|
||
endfunction
|
||
</pre></div>
|
||
<div class="doc-guide-pre"><pre>
|
||
function example()
|
||
if (condition1) return value1;
|
||
elseif (condition2) return value2;
|
||
elseif (condition3) return value3;
|
||
else return value4; endif
|
||
endfunction
|
||
</pre></div>
|
||
|
||
<p><b><a name="chap3c">Case (switch) statements</a></b></p>
|
||
|
||
<p>It is a common occurance in scripting when you need to make a equality
|
||
decision based on a large number of possibilities (and the possibilities are
|
||
known at compile-time). To do this kind of choice with if-elseif statements
|
||
would be ugly at best and slow at worst. Luckily, eScript provides a cleaner way
|
||
to do this:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
// declarations:
|
||
const BLUE := 1;
|
||
const YELLOW := 2;
|
||
const RED := 3;
|
||
const MAUVE := 4;
|
||
|
||
// The ugly if-elseif way:
|
||
|
||
function FunctionOne()
|
||
var answer := WhatIsYourFavoriteColor();
|
||
if ( answer == BLUE )
|
||
// do stuff
|
||
elseif ( answer == YELLOW )
|
||
// do stuff
|
||
elseif ( answer == RED )
|
||
// do stuff
|
||
elseif ( answer == MAUVE )
|
||
// do stuff
|
||
else
|
||
// do something else
|
||
endfunction
|
||
|
||
|
||
// The clean case Way:
|
||
|
||
function FunctionTwo()
|
||
var answer := WhatIsYourFavoriteColor();
|
||
case ( answer )
|
||
BLUE:
|
||
//do stuff
|
||
YELLOW:
|
||
//do stuff
|
||
RED:
|
||
//do stuff
|
||
MAUVE:
|
||
//do stuff
|
||
default:
|
||
//do something else
|
||
endcase
|
||
endfunction</pre></div>
|
||
|
||
<p>The general structure of a case statement is:<br>
|
||
|
||
<br>
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
case ( expression )
|
||
comparison_value:
|
||
//code
|
||
break;
|
||
comparison_value:
|
||
//code
|
||
break;
|
||
...
|
||
default:
|
||
//code if no match was found above (optional)
|
||
break;
|
||
endcase</pre></div>
|
||
|
||
<p>"expression" can be determined at run-time, but "comparison_value" cannot.
|
||
That means a case statement is really only good for making a decision based on
|
||
equality with any number of constant known values. "comparison_value" may not be
|
||
any type of expression that must be determined at run time, such as a
|
||
mathematical expression. Also, case statements cannot be used for non-equality
|
||
comparisons, such as greater-than, less-than, etc. The breaks are optional,
|
||
except under one circumstance- an empty case. If you have a comparison value
|
||
followed by no code (in other words, immediately followed by another comparison
|
||
value), and that comparison value is followed by code, then <i>both</i> of the
|
||
cases will execute that code. </p>
|
||
|
||
<p>For example:
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
function FunctionThree()
|
||
var answer := WhatIsYourFavoriteColor();
|
||
case ( answer )
|
||
BLUE:
|
||
YELLOW:
|
||
//do stuff
|
||
RED:
|
||
//do other stuff
|
||
default:
|
||
//do something else
|
||
endcase
|
||
endfunction</pre></div>
|
||
|
||
<p></p>
|
||
|
||
<p>In this situation, the both BLUE and YELLOW will cause it to do stuff. RED
|
||
will make it do other stuff, and anything else will make it do something else.
|
||
If you meant BLUE to do nothing at all, you must put <code>break;</code>
|
||
statements in the sections which you wish to have do nothing- this will tell the
|
||
program to skip to the end of the case block.</p>
|
||
|
||
<p>The behavior in the case of an empty block (like BLUE above) is known as
|
||
<b>fall through</b>.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap3d">Iteration</a></b></p>
|
||
|
||
<p>I mentioned "looping through an array" in the previous chapter. This is a
|
||
very common function is most scripts. There are two popular ways of doing this,
|
||
here are the code bits I used in the last chapter, one at a time:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array{2,4,6,8};
|
||
|
||
var i;
|
||
for ( i:=1; i<=a.Size(); i:=i+1)
|
||
Print(a[i]);
|
||
endfor
|
||
</pre></div>
|
||
The output of this code is:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
2
|
||
4
|
||
6
|
||
8</pre></div>
|
||
|
||
<p>The "for" loop should be familiar to anyone who has done programming before.
|
||
The syntax of a for-loop is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
for (initialization statement ; loop-if-true statement ; increment)
|
||
// code
|
||
endfor</pre></div>
|
||
|
||
<p>Though you can add any code you want in the initialization statement and the
|
||
increment statement, I've named them these because that is their most common
|
||
function. A for-loop normally is a count-checker. On each go around the loop, it
|
||
automatically performs the increment statement, and then checks the loop-if-true
|
||
statement to see if it should stop looping or go again. In the above example,
|
||
the variable "i" is declared. Before the first loop of the for-loop, i is
|
||
initialized to 1. If 'i' is less than or equal to the length of the array named
|
||
"a", the code in the for-block is executed. At the end of the for-loop block,
|
||
the increment statement is executed, adding 1 to 'i' and storing the new value
|
||
in 'i'. Then 'i' is again compared against the length of a (which is 4, using
|
||
the above example). 'i' is still less than that, so the code in the block is
|
||
executed again. This continues until 'i' is greater than the length of the
|
||
array. "endfor" signals the end of the for-loop block.</p>
|
||
|
||
<p>Another, more convenient method is shown in this example:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
foreach i in ( a )
|
||
Print(i);
|
||
endforeach</pre></div>
|
||
|
||
<p>Here, we don't need to initialize 'i', as the "foreach" loop does it for us.
|
||
This loop performs the same function as the for loop above, but in a much more
|
||
succinct (and efficient) manner. The general syntax is:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
foreach counter_variable in ( array_name )
|
||
{code}
|
||
endforeach
|
||
</pre></div>
|
||
|
||
<p>Bonus Variable:<br>
|
||
When you use a foreach loop, you get a _(var)_iter variable with it that tells
|
||
you what iteration you are on.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := array{"A", 1000};
|
||
foreach i in ( a )
|
||
|
||
Print(_value_iter);
|
||
Print(value);
|
||
endforeach</pre></div>
|
||
The output of this code is:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
1
|
||
A
|
||
2
|
||
1000</pre></div>
|
||
|
||
<p>The last type of for loop is the basic-style for loop.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
for i:=0 to 3
|
||
Print(i);
|
||
endfor
|
||
</pre></div>
|
||
The output of this code is:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
0
|
||
1
|
||
2
|
||
3</pre></div>
|
||
|
||
<p>Another loop type that eScript supports is the "while" loop
|
||
(it's a condition-is-true check to loop):</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
while ( expression )
|
||
// {code}
|
||
endwhile</pre></div>
|
||
|
||
<p>Pretty easy; until the expression is false, {code} is executed. You will
|
||
probably be changing one or more of the variables in "expression" or you will
|
||
never exit (there are exceptions to this rule, below).</p>
|
||
|
||
<p>Another loop type is the "repeat – until" loop. This is very similar to the
|
||
"while" loop, except that you are guaranteed for the code to be executed at
|
||
least once, since the conditional check is done at the bottom of the block
|
||
(it's a condition-is-false check to loop):</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
repeat
|
||
// {code}
|
||
until ( expression );</pre></div>
|
||
|
||
<p>You can use while-loop in similar style with conditional check after code
|
||
(it's a condition-is-true check to loop):</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
do
|
||
// {code}
|
||
dowhile ( expression );</pre></div>
|
||
|
||
<p>There may be times you want to exit a loop before the exit condition is
|
||
satisfied. To do this, you would put the "break" statement in your {code} block
|
||
(this works in the "for", "while", and "repeat until" loops). Also, if you want
|
||
to stop the execution of the code block, but remain in the loop, use the
|
||
"continue" keyword. This will return make the loop start from the top of the
|
||
code block again after checking the "condition" statement.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
while ( condition != 0 )
|
||
if ( condition == 42 )
|
||
//oh geez! breakout!
|
||
break;
|
||
elseif ( condition == 13 )
|
||
//don't do the code below the if-block
|
||
continue;
|
||
endif
|
||
condition:= condition * something;
|
||
endwhile</pre></div>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap4">Chapter 4</a></h3>
|
||
<br/>
|
||
<p><b><a name="chap4a">Functions and Parameters</a></b></p>
|
||
|
||
<p>So far, all I've shown here is code segments which cannot be used by
|
||
themselves. All code you write must be placed inside functions. If you are not
|
||
familiar with the concept of functions, they are one of the fundamental building
|
||
blocks of programming- potentially reusable sections of code. In eScript, there
|
||
are two types of functions: "function" and "program". If you have programmed
|
||
before, we can compare the "program" function to an application's "main"
|
||
function. This means when the script is executed, the entry-point (first
|
||
function run) is always the top of the function designated by the keyword
|
||
"program". Here's a general syntax for both:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
program ProgramName(parameter, ...)
|
||
// {yourcode}
|
||
endprogram
|
||
|
||
function FunctionName(parameter, ...)
|
||
// {your code}
|
||
endfunction</pre></div>
|
||
|
||
<p>The "endprogram" and "endfunction" keywords identify the end of that
|
||
function. These are absolutely necessary and you will get compiler errors if
|
||
they are not present (more on compiling later).</p>
|
||
|
||
<p>FunctionName can be anything, as long as it is one word and it starts with a
|
||
letter.</p>
|
||
|
||
<p>The parameter list is a little more difficult to explain. These are variable
|
||
names that were passed to this function from whatever the calling function was.
|
||
You can have any variable type as a parameter, even arrays and structures. I'll
|
||
show you some examples below. Note what makes the "program" (main function)
|
||
special is that you do not choose what gets passed to it. Since the "system"
|
||
(the POL core in this case) calls the "program" function, it chooses what
|
||
parameters to pass to it. The actual parameter list differs depending on what
|
||
type of script it is in (more on that later). But for the sake of showing you
|
||
the syntax of the program, let's assume nothing is passed to the main function.
|
||
The parameter list may have zero or more parameters in it.</p>
|
||
|
||
<p>Here's a simple example of how you can create your own functions:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
program Main()
|
||
var var1 := "dudes";
|
||
var var2 := "oingo";
|
||
var var3 := "boingo";
|
||
var var4 := "let's";
|
||
var var5 := 42;
|
||
|
||
MyFunction(var1, var4); // 1
|
||
MyFunction(var2, var3); // 2
|
||
MyFunction(var5, var1); // 3
|
||
MyFunction(var3); // 4
|
||
MyFunction(); // 5
|
||
endprogram
|
||
|
||
function MyFunction(a:= "Yo yo", b := "hey hey")
|
||
Print(a + " " + b);
|
||
endfunction</pre></div>
|
||
|
||
<p>Here is the output from the five calls to MyFunction:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
dudes let's
|
||
oingo boingo
|
||
42 dudes
|
||
boingo hey hey
|
||
Yo yo hey hey</pre></div>
|
||
|
||
<p>Notice in the declaration of the MyFunction function, we have a couple
|
||
variable names and an assignment for each. What this does is if no variable is
|
||
passed for that parameter, the value on the right side of that assignment is
|
||
used instead, as can be seen the 4th and 5th lines of output.</p>
|
||
|
||
<p>This is a very simple example, and does not really show why you should use
|
||
separate functions to do stuff rather in all one big function. It is good
|
||
programming style to split up tasks into separate functions, and it helps in the
|
||
areas of readability, code reuse and abstraction. </p>
|
||
|
||
<p>Functions may return one value to the calling function before they exit. This
|
||
is done with the "return" key word. The calling function receives this value by
|
||
having a variable on the left side of an assignment operator and the function
|
||
call on the right:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
program Main()
|
||
var hejaz;
|
||
hejaz := SmellsLike();
|
||
Print(hejaz);
|
||
endprogram
|
||
|
||
function SmellsLike()
|
||
var smell := "Teen Spirit";
|
||
return smell;
|
||
endfunction</pre></div>
|
||
|
||
Prints:
|
||
<div class="doc-guide-pre">
|
||
<pre>Teen Spirit</pre></div>
|
||
|
||
<p>To return more than one value from a function, assign those values to an
|
||
advanced data type (array, struct, dictionary) in the function and then return
|
||
the variable.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
program Main()
|
||
var hejaz;
|
||
hejaz := SmellsLike();
|
||
Print(hejaz[1]);
|
||
Print(hejaz[2]);
|
||
endprogram
|
||
|
||
function SmellsLike()
|
||
var smell := array{"teen", "spirit"};
|
||
return smell;
|
||
endfunction</pre></div>
|
||
Prints:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Teen
|
||
Spirit</pre></div>
|
||
<br/>
|
||
|
||
<p><b><a name="chap4b">Including code from other files</a></b></p>
|
||
|
||
<p>Up to this point, all the code we've been messing with has been in one file.
|
||
To import in code from other files (special files called "include files" whose
|
||
file extension is ".inc". They're special because they cannot contain a
|
||
"program" main function, only any number of normal functions), near the top of
|
||
your script, before any variable declarations or functions add the line:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>include "filename_without_.inc";</pre></div>
|
||
|
||
<p>Then you may call any function that is defined in that include file from your
|
||
script (.src) file. Note that any variables in the include files that are
|
||
declared at global scope also are at global scope in your script file. This
|
||
means you must be careful that you don't try to declare any variables with the
|
||
same names as those other global variables. If you do, it will result in
|
||
compiler errors that may be difficult to track down.</p>
|
||
|
||
<p>The above line will work if the include file is in the same directory as the
|
||
source file that includes it. If you want to use some of the more standard
|
||
include files (found in /scripts/include), you'd use the syntax:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>include "include/filename";</pre></div>
|
||
|
||
<p>If you want to include a file that is in a package you would use</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>include ":pkgName:filename";</pre></div>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap5">Chapter 5</a></h3>
|
||
<br/>
|
||
<p>REJOICE! Now for UO and POL stuff: *.em files and functions</p>
|
||
|
||
<p>I'm glad you stuck through all that syntax discussion and didn't skip ahead
|
||
to here. If you did skip ahead, good luck, because I won't be reviewing any of
|
||
that syntax.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap5a">Scripts</a></b></p>
|
||
|
||
<p>Okay, this is where we start learning to write real scripts for the UO-POL
|
||
environment. Up to this point, you can write scripts that do stuff, but probably
|
||
not anything useful. To be able to write really useful scripts that do
|
||
something, you need to be able to access data about the game world. POL provides
|
||
this interface through a number of "core-functions" that are defined in the
|
||
".em" files that can be found in your /pol/scripts directory. Note *.em files
|
||
are often referred to as 'modules'.</p>
|
||
|
||
<p>But first, I need to talk about the types of scripts in the POL environment,
|
||
when they are executed and with what parameters. Here is a quick list (note the
|
||
parameter names I use like 'clicker' are only an example, the actual parameter
|
||
names can be anything, but I'm trying to be descriptive. Only the order of the
|
||
parameters below is strictly enforced):</p>
|
||
|
||
<p>CharRef = Reference to character running the script<br>MobRef = Reference to
|
||
a mobile object (NPC, character)<br>ObjRef = Reference to an item</p>
|
||
|
||
<p>Use Scripts: Run when the associated item is double clicked in the UO
|
||
window.<br> Parameters: 1: CharRef clicker , 2: ObjRef
|
||
item_clicked</p>
|
||
|
||
<p>Walk-on Scripts: Run when a player walks on the associated
|
||
item.<br> Parameters: 1: CharRef walker , 2: ObjRef
|
||
item_walked_over</p>
|
||
|
||
<p>Text Command Scripts: Run when the player uses the command ".scriptname" and
|
||
has the appropriate privileges.<br> Parameters: 1: CharRef speaker ,
|
||
2: Text after the command. i.e. ".command blah" typed would give the text as
|
||
"blah"</p>
|
||
|
||
<p>Spell Scripts: Run when the player starts a spell from the
|
||
spellbook<br> Parameters: 1: CharRef caster</p>
|
||
|
||
<p>Control Scripts: Run on creation of the associated item and on server
|
||
reboot<br> Parameters: 1: ObjRef item_under_control</p>
|
||
|
||
<p>AI Scripts: Run on an NPC, controls behavior, should never
|
||
exit<br> Parameters: 1: MobRef the_NPC</p>
|
||
|
||
<p>Skill Scripts: Run when a player clicks on a skill gem in the skills scroll
|
||
gump<br> Parameters: 1: CharRef player_performing_skill</p>
|
||
|
||
<p>Let's start learning with Text Command scripts since they're the easiest to
|
||
get running. Text commands are only run if the player speaking the command has
|
||
the necessary command level. Make sure the player you're testing with has a
|
||
command level of "gm" (usually 4) or greater. We'll be placing all our scripts in the
|
||
/scripts/textcmd/gm directory.</p>
|
||
|
||
<p>Okay, let's start with a simple script. Say you want to write a script that
|
||
will broadcast a message to all players on the server. Here is the script
|
||
"bcast.src", I will explain each line:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
/*1*/ use uo;
|
||
/*2*/
|
||
/*3*/ program MyBroadcast(speaker, text)
|
||
/*4*/
|
||
/*4*/ foreach character in ( EnumerateOnlineCharacters() )
|
||
/*5*/ SendSysmessage(character,text);
|
||
/*6*/ endforeach
|
||
/*7*/
|
||
/*9*/ endprogram</pre></div>
|
||
|
||
<p>Line 1: the "use" keyword tells the compiler to look in the following .em
|
||
file for the definitions of any functions we may use out of that "module" (look
|
||
there now, you'll see EnumerateOnlineCharacters and SendSysmessage).</p>
|
||
|
||
<p>Line 3: Since this is a text command script, POL automatically passes a
|
||
reference to the character speaking the command, and the text after the command.
|
||
These are here as "speaker" and "text" respectively.</p>
|
||
|
||
<p>Line 4: The EnumerateOnlineCharacters function returns an array of Character
|
||
References. for each character logged into the server. The foreach loop gets the
|
||
next data element from this returned array and sticks it in the "character"
|
||
variable. </p>
|
||
|
||
<p>Line 5: The SendSysmessage function will send the "text" string to the lower
|
||
left hand corner of "character"'s UO window. </p>
|
||
|
||
<p>Line 6: Signals the end of the foreach block</p>
|
||
|
||
<p>Line 9: Signals the end of the function.</p>
|
||
|
||
<p>Here's how it goes in a sample run:</p>
|
||
|
||
<p>1. The GM player types in <i>.bcast Howdy Everyone!<br>
|
||
</i>2. POL looks in the bcast script for a "program" function and passes
|
||
a reference to the GM player as well as the text "Howdy Everyone!".<br>3.
|
||
EnumerateOnlineCharacters returns an array of 3 character references.<br>4.
|
||
SendSysmessage will send the text "Howdy Everyone!" to the lower-left-hand
|
||
corner of each of the 3 character's screens.</p>
|
||
|
||
<p>But now the GM doesn't like the fact the he receives his own broadcast. You
|
||
can edit the script so this won't happen by checking to see if the character
|
||
reference stored in the "character" variable is the same as the "speaker"
|
||
reference passed to the function by POL:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
/*1*/ use uo;
|
||
/*2*/
|
||
/*3*/ program MyBroadcast(speaker, text)
|
||
/*4*/
|
||
/*5*/ foreach character in ( EnumerateOnlineCharacters() )
|
||
/*6*/ if ( character!= speaker )
|
||
/*7*/ SendSysmessage(character,text);
|
||
/*8*/ endif
|
||
/*9*/ endforeach
|
||
/*10*/
|
||
/*11*/ endprogram</pre></div>
|
||
|
||
<p>Now the message won't be sent to who sent it.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap5b">Compiling</a></b></p>
|
||
|
||
<p>Alright, it's now time to get an actual running script. <i>POL cannot
|
||
directly read the source code you write,</i> it must be compiled into a readable format
|
||
before it can be executed. <br>
|
||
Note: This also means that if you chance a .inc file, you must compile all *.src
|
||
files that use it to update them.<br>
|
||
<br>
|
||
The included program "ecompile" is used for just
|
||
this. I will assume you have experience in the command shell that your operating
|
||
system of choice uses. <br>
|
||
I will use the Windows command line for reference.</p>
|
||
|
||
<p>First, take that code above and place it in a file called "bcast.src" and
|
||
place that file in the pol/scripts/textcmd/gm directory. Now go to your command
|
||
shell and change the directory to the /pol/scripts directory. Type "ecompile
|
||
/?". You should see it give you a list of usage options.</p>
|
||
|
||
<p>We don't need any of these fancy flags, just the basic usage of ecompile:
|
||
"ecompile <filename.src>"</filename.src></p>
|
||
|
||
<p>We need to tell ecompile where the file we want to compile is so at your
|
||
command line, type:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>ecompile.exe txtcmd/gm/bcast.src</pre></div>
|
||
|
||
<p>Since that's where we put the file. You should see something like:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
EScript Compiler v1.05<br>Copyright (C) 1994-2006 Eric N.Swanson
|
||
Compiling: D:\pol\scripts\textcmd\gm\bcast.src
|
||
Writing: D:\pol\scripts\textcmd\gm\bcast.ecl</pre></div>
|
||
|
||
<p>When ecompile tells you that it's writing a .ecl file, that means the
|
||
compiling was successful and the script can now be run.</p>
|
||
|
||
<p>To run, make sure POL is
|
||
running and you're logged in with a GM character (or higher, like admin). Now
|
||
type .bcast <message>. Now, if you did everything right up to here, you should
|
||
see nothing. That's because we made it so you wouldn't receive your own
|
||
broadcast. So to test, get a couple friends on your server and ask them if they
|
||
got the message. If they did, congrats, your very first script.</message></p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap6">Chapter 6</a></h3>
|
||
<br/>
|
||
<p><b>Built-in Properties and the POL Object Reference</b></p>
|
||
|
||
<p>Everything in POL is an object: characters, accounts, items, corpses, NPCs,
|
||
etc. </p>
|
||
|
||
<p>POL uses a class hierarchy to allow inherited properties between objects.
|
||
For example, in the UO world, everything in the world has an x, y, and z
|
||
coordinate property. This include both items on the ground, and mobiles (NPCs or
|
||
characters). You can see from the Object Reference Chart (Appendix A) that both
|
||
the Mobile object and Item object are children of the UObject Class. Notice in
|
||
the UObject class that there are a number of properties, including x y z,
|
||
serial, objtype, color, etc. These properties are inherited by all the other
|
||
class objects under UObject in the tree, thereby implicitly granting all these
|
||
basic properties to all objects in the UO world. </p>
|
||
|
||
<p>Some Classes even have functions as members (methods), an object-oriented type of
|
||
design, i.e. the Door class has the method door.Open() and door.Close() which
|
||
open and close the door, respectively. Notice how you access these methods or
|
||
"member functions" with the dot "<b>.</b>" operator. So depending on what type of
|
||
object you are working with, some members and methods may not exist to access. For example,
|
||
a door object would not have the "quality" member an Equipment object would
|
||
have, but you could access both their x-coordinates with object.x. Note that
|
||
some properties are read-only and some are read-write. The read-only props only
|
||
allow you to retrieve the value for that property, and not to change it.
|
||
Read-write props grant you all access to the property. It is for security
|
||
purposes that some built-in props are read-only. It would mess things up if you
|
||
were able to write to character.dead or character.acct (account)!</p>
|
||
|
||
<p>See the POL documenation for the object heirarchy for more information about
|
||
built-in properties and methods.</p>
|
||
|
||
<p>Please refer to the POL Object Reference Chart for all the details.</p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap7">Chapter 7</a></h3>
|
||
<br/>
|
||
<p><b><a name="chap7a">Much Ado about CProps and Stupid Chapter Names</a></b></p>
|
||
|
||
<p>CProps (Custom Properties) are what makes scripting with eScript so flexible.
|
||
In addition to all the built-in properties in Appendix A, CProps let you store
|
||
arbitrary amounts of arbitrary data to any object. This data can be stored by
|
||
any script and recalled by any script that has a reference to that object. You
|
||
can store any type of data: string, integer, real, arrays. You should be able to
|
||
see that this ability to store and retrieve arbitrary data is a powerful one.
|
||
I'll go through an example of a couple scripts that use CProps and touch on
|
||
other aspects of scripting.</p>
|
||
|
||
<p>Let's say you want to create a one-time use item that allows the player to
|
||
teleport back to their corpse after being resurrected. There are several things
|
||
that we need to do to make this happen: create the description for the custom
|
||
item that grants this ability, the script that controls the behavior of the
|
||
item, code to store the game coordinates of the player's corpse. First, a quick
|
||
lesson on creating a custom item:</p>
|
||
|
||
<p>Open up any itemdesc.cfg file you find. This file contains the definitions
|
||
for all the items that do something in the world. We need to add our item to one
|
||
of these files. For now, we'll use the file /config/itemdesc.cfg. Here's the
|
||
definition of our item and the descriptions of each parameter:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Item 0xABCD
|
||
{
|
||
Name ring_of_returning
|
||
Desc Ring of Returning
|
||
Graphic 0x108A
|
||
Script return_ring
|
||
}
|
||
</pre></div>
|
||
|
||
<p>Item 0xABCD : <br>Starts the definition of the new Item. The objtype number
|
||
is arbitrary, but must be unique. The range of numbers available for custom
|
||
items are 0x5000 to 0xFFFF.</p>
|
||
|
||
<p>Name ring_of_returning : <br>his is the internal name of the item,
|
||
so you could create one using the command ".create ring_of_returning" instead of
|
||
".create 0xABCD".</p>
|
||
|
||
<p>Desc Ring of Returning<br>This is the single-click description
|
||
shown when you click it.</p>
|
||
|
||
<p>Graphic 0x108A<br>This is the objtype of the art item to use to
|
||
represent this item. I got this number by looking in the InsideUO program for
|
||
the ring graphic and using it's objtype number.</p>
|
||
|
||
<p>Script return_ring<br>This is the name of the script that will run
|
||
when you double-click the item.</p>
|
||
|
||
<p>A short description of the CProp functions which we will be using all of,
|
||
found in the uo.em module header file:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
SetObjProperty(object, property_name_string, property_value);</pre></div>
|
||
|
||
<p>Stores a CProp on "object" of name "property_name_string" and value
|
||
"property_value".</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>GetObjProperty(object, property_name_string);</pre></div>
|
||
|
||
<p>Returns the value of the CProp "property_name_string" that is stored on
|
||
"object". If that CProp does not exist, returns an error.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>EraseObjProperty(object, property_name_string);</pre></div>
|
||
|
||
<p>Erases the CProp "property_name_string" that is stored on "object". If that
|
||
CProp was not found, returns an error.</p>
|
||
|
||
<p>Now, let's write some code that will store the player's position after s/he
|
||
dies. The script that is run when a player dies is /scripts/misc/chrdeath.src.
|
||
Let's look a bit at that one. There is probably a bunch of code already in there
|
||
used for other purposes, but you can ignore that for now. We see that the
|
||
function parameters looks like this:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>program ChrDeath(corpse, ghost)</pre></div>
|
||
|
||
<p>The 'corpse' parameter is an itemref to the corpse of the dead player.
|
||
Remember that an Item object inherits all the properties of the UObject class,
|
||
which includes the x,y,z coordinates. We access these by using the 'dot'
|
||
operator. We want to store the x,y,z coordinates of that corpse item on the
|
||
player so the ring item script we will create can read it. The "ghost" parameter
|
||
here is a mobileref to the character that just died. It doesn't matter that he's
|
||
a ghost, we can still access and store data as normal. In chrdeath.src, you
|
||
would add:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
SetObjProperty(ghost, "x_corpse", corpse.x);
|
||
SetObjProperty(ghost, "y_corpse", corpse.y);
|
||
SetObjProperty(ghost, "z_corpse", corpse.z);</pre></div>
|
||
|
||
<p>Okay, now everything is in place for us to write the ring of returning
|
||
script. We create a file named "return_ring.src" in the /scripts/items
|
||
directory. Here is the basic flow of the program:</p>
|
||
|
||
<ol>
|
||
<li>Check to see if those three cprops exist on the player using the ring.
|
||
<ul>
|
||
<li>if the cprops exist, store the values in three variables.
|
||
</li><li>if they don't exist, exit with an error message</li></ul>
|
||
</li><li>Move the player to those coordinates
|
||
</li><li>Erase the cprops on the player
|
||
</li><li>Destroy the ring item.</li>
|
||
</ol>
|
||
|
||
<p>Here's the code:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
use uo;
|
||
program ReturnRing(player, ring)
|
||
// remember this is a usescript, and the variables 'player' and 'ring'
|
||
// are the parameters passed to the script by the POL core.
|
||
var x,y,z;
|
||
|
||
x := GetObjProperty(player,"x_corpse");
|
||
y := GetObjProperty(player, "y_corpse");
|
||
z := GetObjProperty(player, "z_corpse");
|
||
|
||
if ( (x== error) or (y == error) or (z == error) )
|
||
SendSysMessage(player,"Could not find your corpse");
|
||
return 0; //exits the script
|
||
endif
|
||
|
||
|
||
// Note: Since pol97 MoveCharacterToLocation is depreciated use MoveObjectToLocation instead
|
||
MoveCharacterToLocation(player,x, y, z);
|
||
EraseObjProperty(player, "x_corpse");
|
||
EraseObjProperty(player, "y_corpse");
|
||
EraseObjProperty(player, "z_corpse");
|
||
DestroyItem(ring);
|
||
endprogram</pre></div>
|
||
|
||
<p>Easy stuff right? =) Now you'd just have to compile chrdeath.src and
|
||
return_ring.src, unload chrdeath if your server was already running (.unload
|
||
chrdeath), create the new item and test it all out. Now, you might be thinking,
|
||
"If the player was wearing this ring when he died, it would go on his corpse and
|
||
wouldn't help him getting back there." You'd be right, so there's a few things
|
||
you could do, if you wanted:</p>
|
||
|
||
<ol>
|
||
<li>Tell the player how stupid s/he is for not leaving it in his/her bank.
|
||
Then again, he s/he found a wandering healer, the ring would do no good in the
|
||
bank.
|
||
</li><li>Make the ring a "newbie" item (stays on the player's ghost, would be
|
||
usable after he resurrected).
|
||
</li><li>Change the item to be something non-wearable, to hint to the player that
|
||
it shouldn't be something to carry around.</li>
|
||
</ol>
|
||
|
||
<p>It is good to know how POL stored cprops on objects. If you use the ".props"
|
||
command on an object like our unfortunate player, you'd see something like:
|
||
<code><nobr>cprop x_corpse i300</nobr></code> the important part here is the 'i'
|
||
before the value. This denotes the type of the data stored. We will revisit this
|
||
next chapter.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap7b">Cprops on accounts</a></b></p>
|
||
|
||
<p>You can also apply properties to accounts themselves (rather than specific
|
||
characters in them), but you use a different syntax to do so. Rather than
|
||
SetObjProperty(account, "Propname", value), you use these methods to set and
|
||
read custom properties:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
account.SetProp("PropName",value);
|
||
account.GetProp("PropName");</pre></div>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap8">Chapter 8</a></h3>
|
||
<br/>
|
||
<p><b>Config File Usage and Access</b></p>
|
||
|
||
<p>Configuration files (cfg files) in POL hold static data that is read at
|
||
run-time and may be edited on the fly without any restarting or recompiling.
|
||
Because of this, they are good places to put data that may be changed often, or
|
||
for the ease of customization as you wouldn't have to edit and recompile the
|
||
script that uses it. There are two types of cfg files in POL: ones used directly
|
||
by the core executable, and ones that are read in by scripts. The former we
|
||
won't go into, but some examples include the system configuration, pol.cfg;
|
||
spell configurations, spells.cfg; skill configurations, attributes.cfg. There are
|
||
some cfg files that are used both by the core and other scripts, such as
|
||
itemdesc.cfg and npcdesc.cfg (both are read by their respective Create core
|
||
functions, but other scripts can access them for additional data, as we will
|
||
see).</p>Config files have several pieces to them which you should be familiar
|
||
with. A configuration file consists of zero or more elements, each element has a
|
||
type, a key, and zero or more properties. An example follows with the parts
|
||
labeled:
|
||
|
||
<p></p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
BowcraftData 0x13B2
|
||
{
|
||
Name Bow
|
||
Material 16
|
||
Difficulty 30
|
||
PointValue 20
|
||
}</pre></div>
|
||
|
||
<p>BowcraftData is the element type. It is not used by the system and only
|
||
serves to give the scripter an idea about what the element is related to.</p>
|
||
|
||
<p>0x13B2 is the element key or simply key. This must be a string (or number)
|
||
which is used to find the element of interest in a file with many elements like
|
||
the one shown above.</p>
|
||
|
||
<p>Name Bow<br>Material 16<br>Difficulty 30<br>PointValue 20 <br>
|
||
These above, are all the
|
||
element's properties. This is where the data you are interested lives.</p>
|
||
|
||
<p>So the steps to find a specific piece of data is as follows (must use
|
||
cfgfile.em):</p>
|
||
|
||
<ol>
|
||
<li>Read in the config file where the element is saved using
|
||
ReadConfigFile(filename).
|
||
</li><li>Find the specific element where the data lives by matching its key using
|
||
<br>FindConfigElem(cfgfile, key).
|
||
</li><li>Read in the data much like you would a cprop using
|
||
GetConfigXXXX(elem, propname), where <br>XXXX depends if the data is integer,
|
||
real, or string.</li>
|
||
</ol>
|
||
|
||
<p>As a quick example, let's suppose that element above is in a file called
|
||
"bowery.cfg" (in the /config directory) and we want the value of the "Material"
|
||
property of a normal bow.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
use cfgfile;
|
||
|
||
function GetMaterial(item)
|
||
// assume that 'item' is an itemref to a normal bow item
|
||
var cfgfile, element,propvalue;
|
||
cfgfile := ReadConfigFile("bowery");
|
||
element := FindConfigElem(cfgfile, item.objtype);
|
||
propvalue := GetConfigInt(element,"material");
|
||
endfunction</pre></div>
|
||
|
||
<p>What you put in a config file is up to you, but they are best suited for
|
||
large amounts of data that differs depending on the element key. The key is
|
||
often an objtype, or just sequentially numbered, or structured however you want.
|
||
</p>
|
||
|
||
<p>For config files that are used by both the core and other scripts, there are
|
||
properties that are expected to exist for both parts. For example, in an NPC
|
||
description, the core expects the normal properties of an NPC, like stats,
|
||
color, graphic, etc. You can also add other properties that are not read by the
|
||
core, but perhaps are read by the AI script to direct it exactly how to behave
|
||
(for example, to run away from players or to attack). There is a third option,
|
||
you can add CProps to config files. Look at this example of an NPC template:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
NpcTemplate shade
|
||
{
|
||
Name a shade
|
||
script killpcs
|
||
ObjType 0x1a
|
||
Color 0
|
||
.
|
||
.
|
||
.
|
||
lootgroup 29
|
||
Magicitemchance 1
|
||
provoke 67
|
||
CProp Undead i1
|
||
}</pre></div>
|
||
|
||
<p>Please note:</p>
|
||
|
||
<ol>
|
||
<li>'shade' is the key for this element. If you have a mobileref to a shade,
|
||
you could get its element in the npcdesc.cfg file by using shade.npctemplate
|
||
to match the key.
|
||
</li><li>The first four properties are used by the core to create the npc.
|
||
</li><li>The next three properties are not used by the core, but other
|
||
scripts. The first two are used by some loot creation script, the last by some provocation
|
||
script.
|
||
</li><li>The last property is a CProp which is added to every instance of this NPC
|
||
template.</li>
|
||
</ol>
|
||
|
||
<p>Number 4 is very important; if you define CProps in a config file like
|
||
npcdesc.cfg or itemdesc.cfg, that CProp is automatically set on every instance
|
||
of that item that is created. This brings up the age-old dilemma of "Space
|
||
versus Time". CProps in config files are set on every one of those items, which
|
||
takes up extra memory, but is faster to access. Reading the same data from a
|
||
config file takes a little more time to do, but the data is stored in only one place
|
||
instead of many. Using CProps in a file with those bowery entries, for example,
|
||
would not do anything, since no item is created from those elements.</p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap9">Chapter 9</a></h3>
|
||
<br/>
|
||
<p><b>Packages</b></p>
|
||
|
||
<p>You'll notice that up until now we've been putting files in the 'standard'
|
||
places, like /scripts/items for itemuse scripts, /config for config files, etc.
|
||
That's considered poor practice as it makes upgrading very difficult. To try to
|
||
help that problem, POL uses a package system where all the files to do a
|
||
specific purpose can be placed in a directory named for that purpose. For
|
||
example, if you wrote a system for a new skill, you could place all the files
|
||
needed for that new skill in a package: all the script source files, the
|
||
compiled source files, support config files, readme files, etc. In POL, there
|
||
are two types of packages, the 'standard' packages which are enabled by default
|
||
(in/pkg or, in some shards and older POL Distros, /pkg/std/), which are normal skill systems, spawner, spells, etc. Then there
|
||
are the 'optional' packages which are off by default, but can be used if desired
|
||
(in /pkg/optional or, in some shards and older POL Distros, /pkg/opt/). Normally, enabling an optional package requires some
|
||
instructions which are normally supplied with the package.</p>
|
||
|
||
<p>Each package must include a package descriptor file, pkg.cfg, which has the
|
||
following format (note # denotes a comment):</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
# Example package definition file
|
||
|
||
Enabled 1
|
||
#Enabled 0/1 Should this package be enabled?
|
||
|
||
Nam template
|
||
# Name of package,should match directory name
|
||
|
||
Version 1.3
|
||
# Version v0.v1..vn Version number for this package
|
||
|
||
Requires spawner 1.2
|
||
# Requires pkgname {version}
|
||
# Other package(s) other than this one are required
|
||
# in order to function
|
||
# More than one of these can occur.
|
||
# Format: requires package-name {version)
|
||
|
||
Conflicts some-package
|
||
# Conflicts pkgname
|
||
# This package cannot co-exist with a specific package.
|
||
# Note that version cannot be specified
|
||
|
||
### Everything below this line is currently ignored, but are a very
|
||
### good idea to include in your pkg.cfg for imformation to users
|
||
|
||
|
||
CoreRequired 96
|
||
#CoreRequired ver note no leading '0', which would indicate octal
|
||
|
||
Maintainer John Q. Public
|
||
# Your name
|
||
Email johnq@public.com
|
||
# Your email</pre></div>
|
||
|
||
<p>In the previous examples that use the ReadConfigFile function, the addition
|
||
of packages complicate things somewhat. How can you know if you want to read the
|
||
itemdesc.cfg in a specific package, the standard one in /config, or all of the
|
||
files combined into one (for easy searching) ? This is handled in the filename
|
||
format you pass to the ReadConfigFile function. The formats are:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
ReadConfigFile("cfgname")
|
||
- for a script not in a package, looks for /config/[cfgname].cfg
|
||
- for a script in a package, looks for [cfgname].cfg in the same package
|
||
|
||
ReadConfigFile(":*:cfgname")
|
||
- Reads in every config file that matches that name.
|
||
|
||
ReadConfigFile(":pkgname:cfgname")
|
||
- looks for [pkgdir]/[cfgname].cfg
|
||
|
||
ReadConfigFile("::cfgname")
|
||
- always looks in pol/config/[cfgname].cfg</pre></div>
|
||
|
||
<p>Note for the special files itemdesc.cfg, npcdesc.cfg, attributes.cfg, and
|
||
spells.cfg, the first of the three formats will return the "composite" config
|
||
file that includes the concatenation of the contents of all the files in all
|
||
enabled packages and the standard file.</p>
|
||
|
||
<p>There are a few other times this format is used, such as the start_script()
|
||
and the UnloadConfigFile functions. This is why the syntax for the .unloadcfg
|
||
command is ".unloadcfg :pkgname:cfgname". That brings up another point: config
|
||
files are cached by the system and must be unloaded for any online change to be
|
||
seen.</p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap10">Chapter 10</a></h3>
|
||
<br/>
|
||
<p><b>Debugging</b></p>
|
||
|
||
<p>Many books have been written on the subject of finding and fixing software
|
||
errors and it would be wasteful to repeat their content. This chapter will show
|
||
some POL/eScript specific ways of finding bugs in your scripts. Let's first look
|
||
at compile-time scripts. Ecompile, the eScript compiler does well at giving you
|
||
good hints to where your script's syntax errors are. I say hints because of one
|
||
of the rules of programming: never trust the compiler's error messages. They are
|
||
often very useful, but often can lead you astray if you take their messages as
|
||
gospel. The error message will contain a line number around where the error is.
|
||
It may be above, on or below that line. The rest of the error message is usually
|
||
correct, if not sometimes somewhat vague. Here are some examples:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Don't know what to do with Unknown Token: (280,8,'elseif') in SmartParser::parseToken
|
||
Error compiling statement at D:\pd\pol\scripts\items\torch.src, Line 4</pre></div>
|
||
- this error was from a
|
||
|
||
missing semicolon in an if-block on line 5</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Warning: Equals test result ignored. Did you mean := for assign?
|
||
near: item.graphic = 0xa12;
|
||
File: D:\pd\pol\scripts\items\torch.src, Line 5</pre></div>
|
||
- ecompile guesses right
|
||
|
||
here: we used an equals test when we wanted an assign statement</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Warning! possible incorrect assignment.
|
||
Near: if(item.graphic := 0x0f64)</pre></div>
|
||
|
||
<p>- ecompile catches this too, normally you wouldn't want to do
|
||
an assignment in an if-condition. It is not an illegal statement, so ecompile
|
||
completes the compile but warns you about it.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Unhandled reserved word: 'endprogram'
|
||
Error compiling statement at D:\pd\pol\scripts\items\torch.src, Line 7
|
||
Error in IF statement starting at File: D:\pd\pol\scripts\items\torch.src, Line 4</pre></div>
|
||
|
||
<p>- this error was we
|
||
forgot an 'endif' keyword. The compile ran into the 'endprogram' keyword before
|
||
'endif', which is a syntax error.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
|
||
Token 'item' cannot follow token ')'
|
||
Error compiling statement at D:\pd\pol\scripts\items\torch.src, Line 2</pre></div>
|
||
|
||
<p>- this error was from an
|
||
unmatched open-parenthesis in an if statement (on line 4)</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
Error compiling statement at D:\pd\pol\scripts\items\torch.src, Line 2
|
||
Error detected in program body.</pre></div>
|
||
|
||
<p>- this is a nasty one, because it
|
||
does not give you any idea what is wrong. I've only come across this error when
|
||
a variable is declared with the same name as a keyword, in this case, 'for'.</p>
|
||
|
||
<p>Run-Time errors are much harder to find. These are errors that are
|
||
syntactically correct, but produce incorrect results. The compiler will not
|
||
catch these, nor will it help you find them. Your best bet for finding these
|
||
errors is to notice where and when the script behaves incorrectly and go to that
|
||
portion of the source code and poke around. To nail down the specific problem,
|
||
you have several ways to go about it:</p>
|
||
|
||
<p>1. print() variables that you think are in doubt every now and then. Narrow
|
||
down the exact spot where the bug is.<br>2. Many core functions return 'error'
|
||
if something went wrong (i.e. tried to create an NPC in an illegal location). If
|
||
you test the return value of these functions against 'error', you can catch them
|
||
(i.e. if(CreateNPCAtLocation == error)...)<br>3. Some functions also return an
|
||
'.errortext' member that gives you additional information. Such as:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var house := CreateMultiAtLocation(...);
|
||
if(house == error)
|
||
Print(house.errortext);
|
||
endif</pre></div>
|
||
|
||
<p>4. If none of these work for you, you could build the script with debug
|
||
turned on. What this does is POL will print each line of code as it executes to
|
||
the console. This is not always helpful, because if many instances of that
|
||
script are running, they'll all print to the console. Best bet with this method
|
||
is to debug on a local server where a minimum of other scripts are running. To
|
||
turn on debug mode, make sure you 'use os;' before you add the line</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>set_debug(1);</pre></div>
|
||
|
||
<p>under the 'use' lines at the top of your function. Then, you need to tell
|
||
ecompile to compile with debug on. Do this with the '-i' switch. I.e. >
|
||
ecompile –i test.src .</p>
|
||
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap11">Chapter 11</a></h3>
|
||
<br/>
|
||
<p><b>Advanced Data Types and Functions</b></p>
|
||
|
||
<p>On the variable side, in this chapter we'll go into more detail on structs,
|
||
describe dictionaries and error types, explain the concept of persistance, and
|
||
define global properties. On the functions side, we'll describe pass by
|
||
reference and use of the "parms" array to get past limitations on what can be
|
||
passed.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap11a">Global Properties</a></b></p>
|
||
|
||
<p>By now, you're familiar with CProps- custom properties. You're an old hand at
|
||
applying them to items, to people, heck, even to accounts. But, what if you
|
||
don't want to apply it to anything at all? Is there a way to save information
|
||
and let it just float in space, accessible from everywhere?</p>
|
||
|
||
<p>Yes, you can, and to do so you use global properties, otherwise known as
|
||
GProps. You manipulate them in much the same way as you do CProps, except you
|
||
don't need to tell it where to go. These are the three fundamental functions
|
||
you'll need to use GProps:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
GetGlobalProperty("PropertyName");
|
||
SetGlobalProperty("PropertyName","PropertyValue");
|
||
EraseGlobalProperty("PropertyName");</pre></div>
|
||
|
||
<p>And as always, you can use variables to define the name or value of the
|
||
Global Property.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var globname := "Prop1";
|
||
SetGlobalProperty(globname ,"No");</pre></div>
|
||
|
||
<p>The above code would set the value "No" to the global property "Prop1". You
|
||
can also but more than just simple variables as the value, for both GProps and
|
||
CProps. Here's an example:</p>
|
||
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var propname := "Property1";
|
||
var propvalue := array{0 , 1 , "two"};
|
||
SetGlobalProperty(propname, propvalue);</pre></div>
|
||
|
||
<p>And viola, Property1 now has as its value an array containing 0, 1, and
|
||
"two". Later, if you were to do the following:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var ourprop := GetGlobalProperty("Property1");
|
||
Print(outprop[1]);</pre></div>
|
||
|
||
<p>the output would be "0". This also works for CProps.</p>
|
||
|
||
<p>So now we have an interesting question- if simple variables and arrays can
|
||
both be stored in props, what else can? To answer that question, we'll take a
|
||
look at the concept of <b>persistance</b>.</p>
|
||
|
||
<p>If a variable type can be stored in a prop, it is said to be Persistable. As
|
||
of POL090, there are no data types that cannot be persisted, so this section is
|
||
mostly so you'll know what was meant when you read old changes.txts and see
|
||
notices that certain things can now be persisted. In POL089, there was one type
|
||
of data that could not be persisted- the mysterious ERROR type. This was the
|
||
type you got if you tried to go something that should have returned a value but
|
||
failed- instead you got <error>or <uninitialized object="">or somesuch. This caused
|
||
a problem if you then tried to set the variable that just got assigned an error
|
||
as a CProp- it wouldn't stick. It wouldn't persist. Nowadays, error types do
|
||
persist, and they do so as though they were a struct.</uninitialized></error></p>
|
||
|
||
<p>I'll go into a little more detail on data types you've already seen, now.
|
||
</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap11b">Arrays</a></b></p>
|
||
<p>The prefered way to initialize an empty array is to use:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var a := array;</pre></div>
|
||
|
||
<p>This works the same as </p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var a := {};</pre></div>
|
||
|
||
<p>used to. </p>
|
||
|
||
<p>Arrays have a couple of methods that go with them- functions you can use to
|
||
manipulate them directly. They are:</p>
|
||
|
||
<p>array.Size() - This returns the number of elements in the
|
||
array.<br>array.Insert(index , value) - inserts a new element, value, at the
|
||
specified index.<br>array.Erase(index) - deletes the element with the
|
||
specified index.<br>array.Shrink(nelems) - erases all but the first nelems
|
||
elements in the array.<br>array.Append(value) - adds this element to the end
|
||
of the array.<br>array.Reverse() - reverses the order of the
|
||
array.<br>array.Sort() - sorts the array.</p>
|
||
|
||
<p>Here's an example:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
1 var colours := array;
|
||
2 colours[1] := "green";
|
||
3 colours[2] := "blue";
|
||
4 var csize := colours.Size();
|
||
5 colours[5] := "shiny";
|
||
6 csize := colours.Size();</pre></div>
|
||
|
||
<p>So, let's take this step by step. Line 1 defines the array. Lines 2 and 3 put
|
||
the first elements into it. At line 4, the variables look like this:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = "green"
|
||
colours[2] = "blue"
|
||
csize = 2
|
||
</pre></div>
|
||
|
||
<p>Line 5 adds a new elements at position 5, which EScript handles just fine
|
||
because it's cool like that. So what do the variables look like as of line 6?</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = "green"
|
||
colours[2] = "blue"
|
||
colours[3] = <uninitialized object> <--- this is one of those error types.
|
||
colours[4] = <uninitialized object>
|
||
colours[5] = "shiny"
|
||
csize = 5
|
||
</pre></div>
|
||
|
||
<p>Note that when it counts how many things are in the array, it includes the
|
||
"empty" spaces! In other words, array.Size() could more accurately be said to
|
||
return the last valid array index. I'll also point out that if you attempt to
|
||
look at an array position off the end of the array (colours[10], for instance)
|
||
it will also return <uninitialized object> on you.</p>
|
||
|
||
<p>Now, let's continue the previous example.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
7 colours.Insert(3, "bronze");
|
||
8 csize := colours.Size();</pre></div>
|
||
|
||
<p>What happens here? We're inserting the value "bronze" at position 3 in the
|
||
array. Here's what the array looks like after that:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = "green"
|
||
colours[2] = "blue"
|
||
colours[3] = "bronze"
|
||
colours[4] = <uninitialized object>
|
||
colours[5] = <uninitialized object>
|
||
colours[6] = "shiny"
|
||
csize = 6
|
||
</pre></div>
|
||
|
||
<p>Note that an insert pushes the remaining elements down one slot, EVEN IF it
|
||
is inserted into a position that was empty. If you don't want to push like that,
|
||
don't use insert, just use an assignment: colours[3] := "bronze".</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
9 colours.Erase(3);</pre></div>
|
||
|
||
<p>This will return the array to what it looked like before the insert.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>10 colours.Erase(3);</pre></div>
|
||
|
||
<p>This removes one of the empty slots in the array. Using the erase method
|
||
pulls everything up one slot- just the opposite of insert. So after line 10, we
|
||
have:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = "green"
|
||
colours[2] = "blue"
|
||
colours[3] = <uninitialized object>
|
||
colours[4] = "shiny"
|
||
csize = 6
|
||
</pre></div>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>11 colours.shrink(3);</pre></div>
|
||
|
||
<p>This will reduce the array to the first 3 elements- in this case,
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = "green"
|
||
colours[2] = "blue"
|
||
colours[3] = <uninitialized object>
|
||
</pre></div>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
12 colours.Append("brown");
|
||
13 colours.Reverse();</pre></div>
|
||
|
||
<p>This will end up yielding:
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = "brown"
|
||
colours[2] = <uninitialized object>
|
||
colours[3] = "blue"
|
||
colours[4] = "green"
|
||
</pre></div>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
14 colours.shrink(2);
|
||
15 colours.reverse();</pre></div>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
colours[1] = <uninitialized object>
|
||
colours[2] = "brown"
|
||
</pre></div>
|
||
|
||
<p>Quite frankly, I'm not entirely sure how sort works. I'll provide two
|
||
examples from my testing and let people experiment with it on their own.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
a := array;
|
||
a[1] := 4;
|
||
a[2] := 7;
|
||
a[3] := "show";
|
||
a[4] := "tunes";
|
||
a.Sort();</pre></div>
|
||
|
||
<p>printing out the array elements in order yielded:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>show tunes 4 7</pre></div>
|
||
|
||
<p>However...</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
a := array;
|
||
a[1] := 4;
|
||
a[2] := 7;
|
||
a[3] := "show";
|
||
a[5] := "tunes";
|
||
a.Sort();</pre></div>
|
||
|
||
<p>printing this out in order gave me:</p>
|
||
|
||
<p>printing out the array elements in order yielded:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>tunes <uninitialized object> show 4 7</pre></div>
|
||
|
||
<p>Note also that an array element can be any data type- I can hold a number
|
||
there, or a struct, or an error, or another array. Try to sort an array of
|
||
arrays at your own risk.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap11c">A Quick Review of Structs</a></b></p>
|
||
|
||
<p>A struct is similar to an array in that it contains a collection of values
|
||
rather than just one. However, rather than an ordered list, structs are stored
|
||
in, well, a structure. To create one, first you have to initialize it:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var a := struct;</pre></div>
|
||
|
||
<p>This lets the compiler know that it is going to be of data type struct and
|
||
treats it accordingly. The nice thing about structs is that they can be treated
|
||
like a lot of the internal objects. For instance, a player has certain elements,
|
||
like his position. These are accessed with the '.' - player.x, player.y, and
|
||
player.z, for instance. Similarly, we can assign the struct elements that are
|
||
accessed the same way. Here's an example:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var elevator := struct;
|
||
elevator.+floor;
|
||
elevator.+riders;
|
||
elevator.+shaft;
|
||
|
||
elevator.floor := 1; // It's on the first floor.
|
||
elevator.riders := array; // We'll keep an array of the people on it, using
|
||
// append and erase to keep track of them.
|
||
elevator.shaft := 3; // It's in the third shaft from the left.
|
||
</pre></div>
|
||
|
||
<p>So, someone gets on and pushes 3.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
elevator.riders.Append("John");
|
||
|
||
elevator.floor := 3; // Order of precidence on . is left to right, so
|
||
elevator.riders.Erase(1); // first it finds elevator.riders, sees that it is
|
||
// an array, and then appends.
|
||
// We've gone upstairs.
|
||
// John gets off the elevator.
|
||
</pre></div>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap11d">Dictionaries</a></b></p>
|
||
|
||
<p>Dictionaries are similar to both structs and arrays- they are, sort of, a
|
||
bridge between the two types. You create a dictionary, unsurprisingly enough,
|
||
with this syntax:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>var thing := dictionary;</pre></div>
|
||
|
||
<p>Then, you treat it like an array except, instead of just ordered numbers, a
|
||
dictionary can contains words or numbers as its keys.</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
thing["green"] := "blue";
|
||
thing["number"] := 4;
|
||
thing[3] := array{1 , 3};</pre></div>
|
||
|
||
<p>Internally, structs are actually dictionaries- so, basically, these do the
|
||
same thing:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var thing1 := struct;
|
||
thing.+first;
|
||
thing.first := "one";
|
||
|
||
var thing2 := dictionary;
|
||
thing2["first"] := "one";</pre></div>
|
||
|
||
<p>In addition, it means that the dictionary methods work equally well on both.
|
||
These methods are:</p>
|
||
|
||
<p>dictionary.Size() - returns the number of elements.<br>dictionary.Erase(key) - erases an element.</p>
|
||
|
||
<table border="0" cellpadding="0" cellspacing="0">
|
||
<tbody>
|
||
<tr>
|
||
<td valign="top">dictionary.Insert(key , value) - </td>
|
||
<td>adds an element. Dictionaries are not really ordered, so it's not
|
||
entirely accurate to say the item is "inserted".<br>This is the same as
|
||
doing dictionary["key"] := value;</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
|
||
<p>dictionary.Exists(key) - returns true if there that key exists.<br>
|
||
dictionary.Keys() - returns a
|
||
list of all the keys.</p>
|
||
|
||
<p>Functions, for the most part, return one value if any. Frequently, we want to
|
||
pass back more than one piece of data, we can return an array, or struct, or
|
||
dictionary.</p>
|
||
|
||
<p>This also works the other way. The start_script <code>os</code> method only
|
||
takes two parameters- the name of the script, and one thing to pass it. What if
|
||
you want the script to take in multiple variables for information? You send it
|
||
an array, of course, and custom has it that this array ends up getting named
|
||
"parms".</p>
|
||
|
||
<p>Here's an example. Let's say you have a script, called testscript. It wants
|
||
as parameters who called it as well as two items that the user has clicked on.
|
||
If you wanted to call it from another script, you could do the following:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>start_script("testscript" , array{who, target1, target2});</pre></div>
|
||
|
||
<p>or,</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var parms := array;
|
||
parms[1] := who;
|
||
parms[2] := target1;
|
||
parms[3] := target2;
|
||
start_script("testscript" , parms);</pre></div>
|
||
|
||
<p>Then, in testscript.src:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
program testscript(parms)
|
||
if ( parms[2] ) //tests if it got passed an array
|
||
char := parms[1];
|
||
firsttarget := parms[2];
|
||
secondtarget := parms[3];
|
||
else
|
||
char := parms;
|
||
endif
|
||
// do stuff
|
||
endprogram</pre></div>
|
||
|
||
<p>The program knows how to react whether it was simply sent a scalar or if it
|
||
was sent an array.</p>
|
||
|
||
<br/>
|
||
|
||
<p><b><a name="chap11e">Function Calls by Reference</a></b></p>
|
||
|
||
<p>The final section of this chapter will cover passing variables to functions
|
||
by reference rather than by value. What's the difference?</p>
|
||
|
||
<p>Normally, we pass variables by value. Which is to say, it sends the contents
|
||
of the original variable to the new one (copy), and the new one doesn't care anymore
|
||
about the old one. So, when we have:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var first := "one";
|
||
var second := 2;
|
||
FallFunction(first ,second);</pre></div>
|
||
|
||
<p>and...</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
function CallFunction (this, that)
|
||
print(this); // will print "one"
|
||
print(that); // will print "2"
|
||
this := "green";
|
||
endfunction</pre></div>
|
||
|
||
<p>when all is said and done, the values of first and second do not change.</p>
|
||
|
||
<p>However, if we pass by REFERENCE, what we are actually sending to the
|
||
function is the location in memory of the variable itself, rather than just
|
||
sending along its contents. You do this by prefixing the variable name with
|
||
"byref" in the function declaration. So for instance:</p>
|
||
|
||
<div class="doc-guide-pre">
|
||
<pre>
|
||
var a := 4;
|
||
var b := 6;
|
||
var c := 9;
|
||
Foo(a, b, c);
|
||
|
||
function Foo(pa, byref pb, pc)
|
||
pa := 3;
|
||
pb := 5;
|
||
pc := 8;
|
||
endfunction</pre></div>
|
||
|
||
<p>After the call to function foo is completed, a and c are unchanged but the
|
||
value of b has become 5, because pb is a reference to the variable b itself, not
|
||
a copy of its contents. </p>
|
||
|
||
<p>You have to be careful with this, as it is easy to change a variable you
|
||
didn't intend to, but it is very powerful. It is also more efficient than pass
|
||
by value, because it does not have to make and store a copy of the variable's
|
||
value, and then destroy it when the function is done.</p>
|
||
|
||
<p>
|
||
<br/>
|
||
<p><b><a name="chap11f">Interpolated Strings</a></b></p>
|
||
<br />
|
||
<p>Added in: POL 100.1.0</p>
|
||
<br />
|
||
<p>Interpolated strings provide a clean and concise way to construct a string
|
||
using multiple expressions. The following two statements are equivalent:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var a := 1, b := 2;
|
||
Print("The sum of " + CStr(a) + " and " + CStr(b) + " is " + CStr(a + b));
|
||
</pre></div>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var a := 1, b := 2;
|
||
Print($"The sum of {a} and {b} is {a + b}");
|
||
</pre></div>
|
||
|
||
<p>Interpolated strings allow <i>any</i> expression inside them, including other
|
||
interpolated strings. This might get messy to read though!</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
Print($"My master is: {master.name ?: $"({self.name} has no master)"}");
|
||
</pre></div>
|
||
|
||
<p>Interpolated strings also support an optional formatting string that mimics
|
||
the same format used in the String.format method. Specify the formatting string
|
||
via <pre>$"{expression : format}"</pre>. The following two statements are
|
||
equivalent:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
Print("Your graphic: " + Hex(who.graphic));
|
||
</pre></div>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
Print($"Your graphic: {who.graphic : #x}");
|
||
</pre></div>
|
||
|
||
<p>To use a normal brace inside an interpolated string (ie. "escape" the brace),
|
||
specify <i>two</i> of the same brace:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
Print($"{{ hello }}"); // will print "{ hello }"
|
||
</pre></div>
|
||
|
||
<br/>
|
||
<br/>
|
||
|
||
<p><b><a name="chap11g">Function Objects</a></b></p>
|
||
<br />
|
||
<p>A user function can be utilized as a value (eg. used as an argument to a
|
||
function) by referencing the function with a <code>@</code> prefix. The
|
||
referenced function can be executed via the 'call' method --
|
||
<code>value.call( arguments... )</code>.</p>
|
||
|
||
<p>Starting with POL 100.2.0, a function object can be executed via the regular
|
||
function call syntax -- <code>value( arguments... )</code>.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
use os;
|
||
use uo;
|
||
|
||
// A function that logs to the console
|
||
function ConsoleLogger( message )
|
||
Print( message );
|
||
endfunction
|
||
|
||
// A function that logs to all players via broadcast
|
||
function BroadcastLogger( message )
|
||
Broadcast( message );
|
||
endfunction
|
||
|
||
program main( who )
|
||
// Use a logger based on some runtime configuration
|
||
var logger := ( GetEnvironmentVariable( "POL_ENV" ) == "development" ) ?
|
||
@BroadcastLogger :
|
||
@ConsoleLogger;
|
||
|
||
logger.call( "Activity started". );
|
||
// Or in POL 100.2+: logger( "Activity started." );
|
||
|
||
// ...
|
||
endprogram
|
||
</pre></div>
|
||
|
||
<br/>
|
||
<br/>
|
||
|
||
<p><b><a name="chap11h">Function Expressions</a></b></p>
|
||
<br />
|
||
<p>Added in: POL 100.2.0</p>
|
||
<br />
|
||
<p>A function expression is a convenient way of defining an anonymous function
|
||
object (a closure) right at the location where it's invoked or created. A
|
||
function expression is created via the syntax <code>@(param1, param2, ...,
|
||
paramN) { ... }</code>. This will create a new Function Object, automatically
|
||
capturing any variables within the function body that are defined in the current
|
||
scope.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
|
||
program test_filter( who )
|
||
var items := EnumerateItemsInContainer( who.backpack );
|
||
|
||
var colored_items := items.filter( @( item ) {
|
||
var has_color := item.color > 0;
|
||
|
||
// Capture the 'who' variable
|
||
SendSysMessage( who, $"Is {item.desc} colored? {has_color}" );
|
||
|
||
return has_color;
|
||
});
|
||
|
||
SendSysMessage(who, $"You have {colored_items.size()} colored items.");
|
||
endprogram
|
||
</pre></div>
|
||
|
||
Variables are captured <i>by reference</i>, meaning that any modification to the
|
||
variable's value will reflect in any other locations that access the variable.
|
||
This is useful for creating closures that can be used to encapsulate stateful
|
||
behavior.
|
||
|
||
<br/>
|
||
<br/>
|
||
<!-- ====================================================================== -->
|
||
<p><b><a name="chap11i">Spread Operator</a></b></p>
|
||
|
||
<br/>
|
||
<p>Added in: POL 100.2.0</p>
|
||
<br/>
|
||
<p>
|
||
The spread operator is a convenient way to expand an array into individual
|
||
elements. This is useful when you want to pass an array as arguments to a
|
||
function. It can also be used in the array initializer when creating a new
|
||
array. The spread operator is denoted by the
|
||
<code>...</code> syntax.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function Sum( numbers... )
|
||
var total := 0;
|
||
foreach number in numbers
|
||
total += number;
|
||
endforeach
|
||
|
||
return total;
|
||
endfunction
|
||
|
||
program main( who )
|
||
var numbers1 := array{ 1, 2, 3 };
|
||
var numbers2 := array{ 4, 5, 6 };
|
||
var total := Sum( numbers1..., numbers2... );
|
||
Print( total ); // Output: 21
|
||
endprogram
|
||
</pre></div>
|
||
|
||
<p>
|
||
The spread operator can also be used in the array initializer to concatenate
|
||
multiple arrays into a single array.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
program main( who )
|
||
var numbers1 := array{ 1, 2, 3 };
|
||
var numbers2 := array{ 4, 5, 6 };
|
||
|
||
var numbers := array{ numbers1..., numbers2... };
|
||
Print( numbers ); // Output: { 1, 2, 3, 4, 5, 6 }
|
||
endprogram
|
||
</pre></div>
|
||
|
||
<p>
|
||
Additionally, it can be used in dictionary and struct initializers to take the
|
||
elements from one object and spread them into the target, new object. If the
|
||
key already exists in the target object, it will be overwritten with the new
|
||
value.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var dict1 := dictionary{ "a" -> 1, "b" -> 2 };
|
||
var dict2 := dictionary{ "b" -> 3, "c" -> 4 };
|
||
|
||
var dict := dictionary{ dict1..., dict2... };
|
||
Print( dict ); // Output: dict{ "a" -> 1, "b" -> 3, "c" -> 4 }
|
||
</pre></div>
|
||
|
||
<p>
|
||
For function calls, the spread operator can only be used on variadic functions,
|
||
ie. those that accept a variable number of arguments. Using the spread operator
|
||
with non-variadic functions will result in a compile-time error. To bypass this,
|
||
you can use the "expression-as-callee" syntax, calling the the function through
|
||
a function object via <code>@</code>. If the correct number of arguments are not
|
||
passed after spreading arguments, an error will be returned instead of executing
|
||
the function.
|
||
</p>
|
||
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function Sum( a, b, c )
|
||
return a + b + c;
|
||
endfunction
|
||
|
||
program main( who )
|
||
var numbers, total, sum;
|
||
|
||
numbers := array{ 1, 2, 3 };
|
||
|
||
// Compile-time error! Spread operator can only be used in variadic functions
|
||
// total := Sum( numbers... );
|
||
|
||
// Okay! Use the expression-as-callee syntax
|
||
total := (@Sum)( numbers... ); // Or: @Sum.call( numbers... )
|
||
Print( total ); // Output: 6
|
||
|
||
// Calling @Sum with the wrong number of arguments will result in an error:
|
||
numbers := { 1, 2 };
|
||
total := (@Sum)( numbers... );
|
||
Print( total ); // Output: Invalid argument count: expected 3, got 2
|
||
|
||
endprogram
|
||
|
||
</pre></div>
|
||
|
||
<p>
|
||
Using the spread operator on dictionaries and structs result in
|
||
expanding the values of that object:
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function Sum( numbers... )
|
||
var total := 0;
|
||
foreach number in numbers
|
||
total += number;
|
||
endforeach
|
||
|
||
return total;
|
||
endfunction
|
||
|
||
program main( who )
|
||
// Spread a dictionary's values into a function
|
||
var dict := dictionary{ "a" -> 1, "b" -> 2, "c" -> 3 };
|
||
var total := Sum( dict... );
|
||
Print( total ); // Output: 6
|
||
|
||
// Spread a struct's values into an array.
|
||
// `lastcoords` is a struct{ x := 123, y := 456, z := 789 }
|
||
var coords := array{ who.lastcoords... };
|
||
Print( ", ".join( coords ) ); // Output: 123, 456, 789
|
||
endprogram
|
||
</pre></div>
|
||
|
||
<br/>
|
||
<br/>
|
||
<!-- ====================================================================== -->
|
||
<p><b><a name="chap11j">Regular Expressions</a></b></p>
|
||
|
||
<br/>
|
||
<p>Added in: POL 100.2.0</p>
|
||
<br/>
|
||
|
||
<p>
|
||
Regular expressions provide a powerful way to search, match, and manipulate
|
||
strings based on specific patterns. EScript supports regular expressions via
|
||
the <code>RegExp</code> object type used in string methods like
|
||
<code>find</code>, <code>match</code>, and <code>replace</code>.
|
||
</p>
|
||
<br/>
|
||
|
||
<p>
|
||
<strong>NOTE:</strong> This guide will cover only the basics of regular
|
||
expressions and Escript-specific implementation details. For a comprehensive
|
||
reference on regular expression syntax and features, please refer to external
|
||
resources such as
|
||
<a href="https://www.regular-expressions.info/" target="_blank">regular-expressions.info</a>
|
||
or the
|
||
<a href="https://www.boost.org/doc/libs/1_86_0/libs/regex/doc/html/boost_regex/syntax/perl_syntax.html" target="_blank">Boost Regular Expression Syntax documentation</a>.
|
||
</p>
|
||
<br/>
|
||
|
||
<p>
|
||
To create a regular expression, use the either the <code>basic::RegExp(
|
||
pattern, flags )</code> module function or the EScript language syntax
|
||
<code>/pattern/flags</code>:
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
// Create a RegExp object using the module function
|
||
var regex1 := RegExp( "^hello", "i" ); // case-insensitive match for "hello" at start
|
||
|
||
// Create a RegExp object using the EScript syntax
|
||
var regex2 := /world$/i; // case-insensitive match for "world" at end
|
||
|
||
var test_string := "Hello, World";
|
||
|
||
// Test if the string matches the regex patterns
|
||
if ( test_string.match( regex1 ) )
|
||
Print( "The string starts with 'hello'." );
|
||
endif
|
||
|
||
if ( test_string.match( regex2 ) )
|
||
Print( "The string ends with 'world'." );
|
||
endif
|
||
</pre></div>
|
||
|
||
<p>
|
||
The following flags are supported:
|
||
</p>
|
||
<ul>
|
||
<li><code>i</code> - Case-insensitive matching</li>
|
||
<li><code>m</code> - Multi-line mode, where ^ and $ match the start and end of
|
||
lines in an input string that contains multiple lines</li>
|
||
<li><code>g</code> - Global matching for String methods <code>match</code> and <code>replace</code></li>
|
||
<li><code>u</code> - Unicode support</li>
|
||
</ul>
|
||
<br/>
|
||
|
||
<p><b>Example: Finding Matches with <code>String.match</code></b></p>
|
||
<p>
|
||
The <code>String.match</code> method can be used to find all occurrences of a
|
||
pattern in a string. Here's an example that finds all words starting with a
|
||
capital letter:
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var input := "Alice and Bob are members of the Council of Mages in Moonglow.";
|
||
var regex := /\b[A-Z]\w*\b/g; // Regular expression to match capitalized words. Note the 'g' to return all matches as an array.
|
||
|
||
foreach match_result in (input.match( regex ))
|
||
var { matched, offset } := match_result;
|
||
Print( $"Found {matched} at index {offset}" ); // Output: Found Alice at index 1
|
||
// Found Bob at index 11
|
||
// Found Council at index 28
|
||
// Found Mages at index 40
|
||
// Found Moonglow at index 48
|
||
endforeach
|
||
</pre></div>
|
||
<br/>
|
||
|
||
<p><b>Example: Using a User Function for Replacement in <code>String.replace</code></b></p>
|
||
|
||
<p>
|
||
The <code>String.replace</code> method can take a user-defined function as the
|
||
replacement argument. This function will be called for each match found, allowing
|
||
for dynamic replacement logic. Here's an example that will turn every number to a hex value:
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function NumberToHex( matched )
|
||
var number := CInt( matched ); // Convert matched string to integer
|
||
return Hex( number ); // Return the hexadecimal representation, prefixed with 0x
|
||
endfunction
|
||
|
||
var input := "The values are 10, 255, and 1024.";
|
||
var regex := /\d+/g; // Regex to match all numbers. Note the 'g' flag to replace all matches.
|
||
|
||
// Replace numbers with their hexadecimal representation
|
||
var output := input.replace( regex, @NumberToHex );
|
||
|
||
Print( output ); // Output: The values are 0xA, 0xFF, and 0x400.
|
||
</pre></div>
|
||
|
||
|
||
|
||
<!-- ====================================================================== -->
|
||
</p><h3><a name="app2">Appendix A: GUMP Tag Descriptions</a></h3>
|
||
<br/>
|
||
|
||
<table border="0" cellpadding="0" cellspacing="1">
|
||
<tbody>
|
||
<tr>
|
||
<td width="30%"><b>Tags</b></td>
|
||
<td width="30%"><b>Syntax/Description</b></td>
|
||
<td width="40%"> </td></tr>
|
||
<tr>
|
||
<td>----</td>
|
||
<td>------------------</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>noclose</td>
|
||
<td>[NONE]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> gump can't be closed by
|
||
clicking the right mousebutton. Selection via an exit enabled button must
|
||
be made.</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>nomove</td>
|
||
<td>[NONE]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> The gump can't be moved
|
||
around the screen.</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>nodispose</td>
|
||
<td>[NONE]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> The gump can't be closed
|
||
by hitting ESC. If this setting isn't specified and the user hits ESC,
|
||
then the dialog is closed but no message is sent to the server. The server
|
||
never thinks the player is done with the gump. Therefore ALL gump dialogs
|
||
should specify 'nodispose'.</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>tilepic</td>
|
||
<td>[X] [Y] [T]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> Displays a tile on the
|
||
gump.<br> [X] -> X coord of the
|
||
tile.<br> [Y] -> Y coord of the
|
||
tile.<br> [T] -> Tile (see insideUO)</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>resizepic</td>
|
||
<td>[X1] [Y1] [G] [X2] [Y2]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspsn="3"> Defines the gump
|
||
layout background.<br> [X1] -> Start
|
||
X coord of the gump.<br> [Y1] ->
|
||
Start Y coord of the gump.<br> [G]
|
||
-> Graphics to be used as gump
|
||
background.<br> [Y1] -> End X coord
|
||
of the gump.<br> [Y2] -> End Y coord
|
||
of the
|
||
gump.<br> Notes:<br> Be
|
||
careful, not all gumps 'stretch' and have to be
|
||
used<br> with the correct
|
||
sizing.<br> 5100 = stretchable gray
|
||
background gump.</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>page</td>
|
||
<td>[N]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> [N] ->
|
||
Pagenumber.<br> Notes:<br> Defines
|
||
the page layout. Page 0 affects all
|
||
following<br> pages (items will not be
|
||
removed when moving to<br> other
|
||
pages), i.e. the 'background' that is always displayed.
|
||
<br> page 1 is what will be displayed
|
||
when the gump first opens (on<br> top
|
||
of what is defined in page 0).</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>button</td>
|
||
<td>[X] [Y] [G1] [G2] [E] [P] [R]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> X -> X coord of the
|
||
button.<br> Y -> Y coord of the
|
||
button.<br> G1 -> Normal
|
||
graphics.<br> G2 -> Clicked
|
||
graphics.<br> E -> Exit? (10)<br> P -> Pagenumber
|
||
(jump to page)<br> R ->
|
||
Returnvalue.<br><br> [EXIT] = button
|
||
will make a menuexit and return a value.
|
||
(01)<br> [PAGENUMBER] = button will
|
||
change to page #. (#)<br> [RETURNVALUE]
|
||
= Returnvalue of button. (See EXIT)
|
||
(#)<br> if you have radio buttons on
|
||
the screen with return values,
|
||
<br> those return values will be used
|
||
instead.</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>radio</td>
|
||
<td>[X],[Y],[GUMPGFX],[CLICKGUMPGFX],[PREVALUE],[RETURNVALUE]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> Only one radio button
|
||
can be selected on a page. RETURNVALUE
|
||
<br> will be returned when the gump
|
||
exits.<br> (See also BUTTON).</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>tilepic</td>
|
||
<td>[X],[Y],[TILENUMBER]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> Display the selected
|
||
tile (normal item art).</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>text</td>
|
||
<td>[X],[Y],[COLORCODE],[STRINGNUMBER]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> Display
|
||
text<br> The string numbering requires
|
||
some thought however, UO <br> considers
|
||
the first string passed to it as 0 (zero) but POL considers the first one
|
||
in an array to be 1 (one) so this is the way to do
|
||
it:<br> text 0 0 32 0 <--->
|
||
array[1] := "This I want printed".</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>gumppic</td>
|
||
<td>[X],[Y],[GUMPGFX]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> Display the selected
|
||
gump.</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>textentry</td>
|
||
<td>[X] [Y] [WIDTH] [HEIGHT] [COLOR] [RETURNVALUE] [INITSTRINGNUMBER]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> Display an editable text
|
||
entry line<br> [RETURNVALUE] is the key
|
||
to use to retrieve the
|
||
string<br> [INITSTRINGNUMBER] is the
|
||
initial string to use, usual base
|
||
<br> 0<>1 stuff</td></tr>
|
||
<tr>
|
||
<td></td>
|
||
<td> </td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td>checkbox</td>
|
||
<td>[X],[Y],[GUMPGFX],[CLICKGUMPGFX],[PREVALUE],[RETURNVALUE]</td>
|
||
<td></td></tr>
|
||
<tr>
|
||
<td colspan="3"> RETURNVALUE of all the
|
||
checked boxes can be found in result.keys[].</td></tr></tbody></table>
|
||
<br/>
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="appB">Appendix B: Operator Precedence</a></h3>
|
||
<br/>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Precedence</th>
|
||
<th>Title</th>
|
||
<th>Symbols</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Highest</td>
|
||
<td>Subscript</td>
|
||
<td><code>[]</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Member Access</td>
|
||
<td><code>.</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Postfix</td>
|
||
<td><code>++</code>, <code>--</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Prefix</td>
|
||
<td><code>-</code>, <code>+</code>, <code>++</code>, <code>--</code>, <code>~</code>, <code>not</code>, <code>!</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Multiplicative, Shifts, Bitwise AND</td>
|
||
<td><code>*</code>, <code>/</code>, <code>%</code>, <code><<</code>, <code>>></code>, <code>&</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Additive, Bitwise OR/XOR</td>
|
||
<td><code>+</code>, <code>-</code>, <code>|</code>, <code>^</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Elvis</td>
|
||
<td><code>?:</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Named checks</td>
|
||
<td><code>in</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Comparison</td>
|
||
<td><code><</code>, <code>></code>, <code><=</code>, <code>>=</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Equality</td>
|
||
<td><code>==</code>, <code>!=</code>, <code><></code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Conjunction</td>
|
||
<td><code>&&</code>, <code>and</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Disjunction</td>
|
||
<td><code>||</code>, <code>or</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Conditional Operator</td>
|
||
<td><code>? :</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td> </td>
|
||
<td>Member Modification/Query</td>
|
||
<td><code>.+</code>, <code>.-</code>, <code>.?</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td>Lowest</td>
|
||
<td>Assignment</td>
|
||
<td><code>:=</code>, <code>+=</code>, <code>-=</code>, <code>*=</code>, <code>/=</code>, <code>%=</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br/>
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
<h3><a name="appC">Functional Programming with Arrays</a></h3>
|
||
<br/>
|
||
<p>Added in: POL 100.2.0</p>
|
||
<br/>
|
||
<p>
|
||
Arrays now offer several methods that accept a user function as an argument.
|
||
This allows better use of functional programming within Escript. Functional
|
||
programming is a way of writing code where you use functions to work with data.
|
||
This makes your code cleaner and easier to understand. One of the places where
|
||
this is really helpful is when working with arrays. Escript has some built-in
|
||
methods that make it easy to use functional programming with arrays. These
|
||
methods include <code>filter</code>, <code>map</code>, <code>find</code>,
|
||
<code>findIndex</code>, and <code>reduce</code>. Let's take a look at what
|
||
each of these does and how you can use them.
|
||
</p>
|
||
<br/>
|
||
|
||
<h4><code>filter</code></h4>
|
||
<br/>
|
||
<p>
|
||
The filter method lets you create a new array with only the elements that
|
||
pass a test you provide.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var hidden_players := EnumerateOnlinePlayers()
|
||
.filter( @( player ) {
|
||
return player.hidden;
|
||
});
|
||
</pre></div>
|
||
|
||
<p>
|
||
In this example, <code>filter</code> checks each player to see if it is hidden
|
||
and creates a new array with only the hidden players.
|
||
</p>
|
||
<br/>
|
||
|
||
<h4><code>map</code></h4>
|
||
<br/>
|
||
<p>
|
||
The <code>map</code> method creates a new array by applying a function to each
|
||
element of the original array.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var serials := ListItemsNearLocation( x, y, z, range )
|
||
.map( @( item ) {
|
||
return item.serial
|
||
});
|
||
</pre></div>
|
||
|
||
<p>
|
||
Here, <code>map</code> takes each item near location <code>(x, y, z)</code>
|
||
and gets its serial, then puts the results in a new array.
|
||
</p>
|
||
<br/>
|
||
|
||
<h4><code>find</code></h4>
|
||
<br/>
|
||
<p>
|
||
The <code>find</code> method returns the first element in the array that
|
||
passes a test you provide. If no elements pass the test, it returns
|
||
<code><uninitialized object></code>.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var locked_item := EnumerateItemsInContainer( container )
|
||
.find( @( item ) {
|
||
return item.locked;
|
||
});
|
||
</pre></div>
|
||
|
||
<p>This example finds the locked item in the container.</p>
|
||
<br/>
|
||
|
||
<h4><code>findIndex</code></h4>
|
||
<br/>
|
||
<p>
|
||
The <code>findIndex</code> method works like find, but instead of returning
|
||
the element, it returns the index (position) of the first element that passes
|
||
the test. If no elements pass the test, it returns <code>0</code>.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
// Get a list of quests
|
||
var quests := array{
|
||
struct{ completed := true, name := "Quest 1" },
|
||
struct{ completed := false, name := "Quest 2" },
|
||
// ...
|
||
};
|
||
|
||
var incomplete_quest_index := quests
|
||
.findIndex( @( quest ) {
|
||
return !quest.completed;
|
||
});
|
||
</pre></div>
|
||
|
||
<p>
|
||
In this example, <code>findIndex</code> gives the position of the first
|
||
incomplete quest in the array.
|
||
</p>
|
||
<br/>
|
||
|
||
<h4><code>reduce</code></h4>
|
||
<br/>
|
||
<p>
|
||
The <code>reduce</code> method combines all elements in the array into a
|
||
single value by applying a function you provide. This is useful for tasks like
|
||
summing up values. It behaves differently depending on if an optional initial
|
||
value is provided.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var total_arrows = EnumerateItemsInContainer( who.backpack )
|
||
.reduce( @( sum, item ) {
|
||
return item.objtype == 0x0f3f ? ( sum + item.amount ) : sum;
|
||
}, 0);
|
||
</pre></div>
|
||
|
||
<p>
|
||
Here, reduce calculates the total number of arrows by adding the item amount,
|
||
only if the item's object type is <code>0x0f3f</code> -- arrows. <code>0</code>
|
||
is passed as the initial value parameter to <code>.reduce()</code>, meaning that
|
||
the sum starts at <code>0</code> and <code>item</code> will be the first item in
|
||
the list of items inside the container. If the item is an arrow, we return
|
||
<code>sum</code> plus the item's amount. Otherwise, we return <code>sum</code>
|
||
as is.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var total = array{ 1, 5, 12, 4 }
|
||
.reduce( @( sum, element ) {
|
||
return sum + element
|
||
});
|
||
</pre></div>
|
||
|
||
<p>
|
||
Here, reduce calculates the sum of the elements. Since no initial value is
|
||
provided, the first element in the array is used as the initial value for
|
||
<code>sum</code>. The second element is passed as <code>element</code>. The
|
||
function returns the sum of the two elements. This sum is then used as the
|
||
new <code>sum</code> for the next iteration, and so on.
|
||
</p>
|
||
<br/>
|
||
|
||
<h4><b>Advanced Techniques</b></h4>
|
||
<br/>
|
||
<p>
|
||
Each of the functional array methods receive two additional arguments: the
|
||
index of the current element and the array itself. This allows you to write more
|
||
complex functions that depend on the position of the element in the array or the
|
||
array itself.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var players_with_ranking := "".join(
|
||
EnumerateOnlinePlayers()
|
||
.map( @( player, index, arr ) {
|
||
return $"{index} / {arr.size()} -> {player.name}";
|
||
})
|
||
);
|
||
</pre></div>
|
||
|
||
<p>
|
||
This example uses <code>map</code> to create a new array of strings, each
|
||
containing a player's name and their position in the array. Since the original
|
||
array is passed as a parameter (as <code>arr</code>), you do not need to call
|
||
<code>EnumerateOnlinePlayers()</code> again to find their position!
|
||
</p>
|
||
|
||
<br/>
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
<h3><a name="appD">Variadic User Functions</a></h3>
|
||
<br/>
|
||
<p>Added in: POL 100.2.0</p>
|
||
<br/>
|
||
<p>
|
||
User functions can accept any number of arguments by using the 'rest
|
||
parameter' syntax. This allows you to write functions that can take a variable
|
||
number of arguments, making your code more flexible and easier to use. To
|
||
create a variadic user function, you use the <code>...</code> syntax in the
|
||
function definition. The rest parameter is an array that contains all the
|
||
arguments passed to the function. Here's an example of a variadic user
|
||
function that calculates the sum of all its arguments:
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function Sum( numbers... )
|
||
var total := 0;
|
||
|
||
foreach number in numbers
|
||
total += number;
|
||
endforeach
|
||
|
||
return total;
|
||
endfunction
|
||
</pre></div>
|
||
|
||
<p>You can call this function with any number of arguments:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var sum1 := Sum( 1, 2, 3 ); // sum1 = 6
|
||
var sum2 := Sum( 1, 2, 3, 4, 5 ); // sum2 = 15
|
||
</pre></div>
|
||
|
||
<p>
|
||
The rest parameter can be used with other parameters as well. The rest
|
||
parameter must be the last parameter in the function definition. When calling
|
||
a variadic user function with multiple parameters, each parameter prior to the
|
||
rest parameter <b>must</b> be provided. The rest parameter will then capture
|
||
any remaining arguments.
|
||
</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
function SendMessageToPlayers( message, players... )
|
||
foreach player in players
|
||
SendSysMessage( player, $"[Server] {message}" );
|
||
endforeach
|
||
endfunction
|
||
|
||
SendMessageToPlayers( "Hello!", player1, player2, player3 );
|
||
</pre></div>
|
||
|
||
<br/>
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="chap12">Chapter 12</a></h3>
|
||
<br/>
|
||
<p>Added in: POL 100.1.0</p>
|
||
<br/>
|
||
<p>Classes in EScript are a powerful feature that allows you to create custom
|
||
data structures with encapsulated behaviors, following an object-oriented
|
||
programming (OOP) paradigm. Similar to Python and other object-oriented
|
||
languages, classes in EScript provide a way to bundle data (members) and
|
||
functions (methods) that operate on that data into cohesive units called
|
||
objects. This makes it easier to model real-world entities and complex systems
|
||
by representing them as objects with properties and behaviors.</p>
|
||
<br/>
|
||
|
||
<p><b>Key Concepts</b></p>
|
||
<br/>
|
||
|
||
<ul>
|
||
<li><strong>Class Definition</strong>: A class in EScript is defined using the
|
||
<code>class</code> keyword followed by the class name. A class can include methods, which
|
||
define the behaviors, and members, which store the state of an object.</li>
|
||
<li><strong>Constructor Method</strong>: The constructor method in EScript is a
|
||
special function that is called when a new object of the class is created. In
|
||
EScript, the constructor has the same name as the class itself. This method is
|
||
typically used to initialize the object's members.</li>
|
||
<li><strong>Object Creation and Usage</strong>: To create an object in EScript,
|
||
simply call the class like a function, passing any required arguments to the
|
||
constructor. Once created, you can interact with the object's methods and
|
||
members using dot notation, like other built-in objects.</li>
|
||
<li><strong>Instance Methods</strong>: These are functions defined within a
|
||
class that operate on the instance of the class. They are defined with the
|
||
<code>function</code> keyword and take <code>this</code> as the first parameter,
|
||
which refers to the current instance of the class.</li>
|
||
<li><strong>Inheritance</strong>: EScript supports inheritance, allowing you to
|
||
create new classes based on existing ones. This feature promotes code reuse and
|
||
the creation of hierarchical relationships between classes. EScript also
|
||
supports multiple inheritance, where a class can inherit from more than one base
|
||
class. The <code>super</code> keyword is used to call the constructors of parent
|
||
classes.</li>
|
||
<li><strong>Scoped Global Variables</strong>: A class can have a global
|
||
variables and user functions that do not interfere with others of the same name.
|
||
This allows implementations, for example to use global variables without
|
||
worrying about clashing names from other included files, or define a user
|
||
function that has the same name as a module function.</li>
|
||
<li><strong>Reference Type</strong>: A class in EScript is a reference type,
|
||
meaning that when you assign an object to a variable, you are assigning a
|
||
reference to the object, not the object itself. This means that changes made to
|
||
the object's members will affect all references to that object. This is
|
||
similar to other built-in reference types, like <code>ItemRef</code>: every
|
||
script that has variables for the same <code>Item</code> object will access the
|
||
same item.</li>
|
||
<li><strong>Uninitialized Functions</strong>: [Added in POL 100.2.0] A class can
|
||
declare <i>uninitialized</i> functions, requiring any constructed descendant
|
||
class to define the functions' implementation. This is a similar concept to
|
||
"abstract methods" in other programming languages like Java or C#. Uninitialized
|
||
functions can only be used with class methods, ie. functions that have a first
|
||
parameter named <code>this</code>.</li>
|
||
</ul>
|
||
<br/>
|
||
|
||
<p><b>Example: Creating a Simple Class</b></p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Person()
|
||
function Person( this, name, age )
|
||
this.name := name;
|
||
this.age := age;
|
||
endfunction
|
||
|
||
function greeting( this )
|
||
return $"Hello, my name is {this.name} and I am {this.age} years old.";
|
||
endfunction
|
||
|
||
function rename( this, new_name )
|
||
this.name := new_name;
|
||
Print( $"Name changed to {this.name}" );
|
||
endfunction
|
||
endclass
|
||
|
||
var john := Person( "John", 30 );
|
||
var greeting := john.greeting();
|
||
|
||
Print( greeting ); // Output: Hello, my name is John and I am 30 years old.
|
||
|
||
john.rename( "Johnny" ); // Output: Name changed to Johnny
|
||
</pre></div>
|
||
<br/>
|
||
|
||
<p>The example above defines a class <code>Person</code> with a constructor that
|
||
initializes the <code>name</code> and <code>age</code> attributes. It also
|
||
includes two instance methods: <code>greeting</code> and <code>rename</code>. An
|
||
object <code>john</code> is created from the <code>Person</code> class, and its
|
||
methods are called to interact with the object's state.</p>
|
||
<br/>
|
||
|
||
<p>A class that does not define a constructor <strong>cannot</strong> be
|
||
instantiated.</p>
|
||
<br/>
|
||
|
||
|
||
<p><b>Example: Scoped Variables and Functions</b></p>
|
||
<br/>
|
||
|
||
<p>Similar to scoping a module function call (eg. <code>basicio::Print</code>),
|
||
a class' global variables and user functions are accessed with <code>::</code>.
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Animal()
|
||
var animal_count := 0;
|
||
|
||
function Animal( this, type )
|
||
this.type := type;
|
||
this.id := ++animal_count;
|
||
endfunction
|
||
|
||
function Print( this )
|
||
basicio::Print( $"Animal {this.id} is a {this.type}" );
|
||
endfunction
|
||
endclass
|
||
|
||
var dog := Animal( "dog" );
|
||
print( dog.id ); // Output: 1
|
||
|
||
dog.Print(); // Output: Animal 1 is a dog
|
||
Animal::Print( dog ); // Output: Animal 1 is a dog
|
||
|
||
print( Animal::animal_count ); // Output: 1
|
||
|
||
var cat := Animal( "cat" );
|
||
cat.Print(); // Output: Animal 2 is a cat
|
||
|
||
// print( animal_count ); // Compiler error!
|
||
</pre></div>
|
||
<br/>
|
||
|
||
<p><b>Example: Inheritance in EScript</b></p>
|
||
<br/>
|
||
|
||
<p>EScript supports inheritance, allowing you to create new classes based on
|
||
existing ones. Inheritance is a way to create new things by building on what's
|
||
already there.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Person()
|
||
function Person( this, name )
|
||
this.name := name;
|
||
endfunction
|
||
|
||
function Say( what )
|
||
Print( what );
|
||
endfunction
|
||
endclass
|
||
|
||
class Wizard( Person )
|
||
function Wizard( this, name )
|
||
super( name );
|
||
endfunction
|
||
|
||
function Attack( this )
|
||
Say( $"{this.name} casts a spell!" );
|
||
endfunction
|
||
endclass
|
||
|
||
class Fighter( Person )
|
||
function Fighter( this, name )
|
||
super( name );
|
||
endfunction
|
||
|
||
function Attack( this )
|
||
Say( $"{this.name} swings a sword!" );
|
||
endfunction
|
||
endclass
|
||
|
||
var gandalf := Wizard( "Gandalf" );
|
||
var aragorn := Fighter( "Aragorn" );
|
||
|
||
gandalf.Attack(); // Output: Gandalf casts a spell!
|
||
aragorn.Attack(); // Output: Aragorn swings a sword!
|
||
</pre></div>
|
||
|
||
<p><b>NOTE:</b> It is important to call <code>super()</code> within your constructor to
|
||
ensure the base class constructor(s) are called to set the attributes for the
|
||
instance!</p>
|
||
<br/>
|
||
|
||
|
||
<p><b>Example: Uninitialized Functions</b></p>
|
||
<br/>
|
||
|
||
<p>To declare an uninitialized function within a class body, use the
|
||
<code>uninit</code> keyword, providing no body for the function, and instead
|
||
ending it with a semi-colon:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
// All classes that inherit `Shape` must implement class methods `area` and
|
||
// `scale` with the given signature (ie. number of parameters).
|
||
class Shape()
|
||
uninit function area( this );
|
||
uninit function scale( this, factor );
|
||
endclass
|
||
|
||
class Circle( Shape )
|
||
function Circle( this, radius )
|
||
this.radius := radius;
|
||
endfunction
|
||
|
||
function area( this )
|
||
return 3.14159 * this.radius * this.radius;
|
||
endfunction
|
||
|
||
function scale( this, factor )
|
||
this.radius *= factor;
|
||
endfunction
|
||
endclass
|
||
|
||
class Rectangle( Shape )
|
||
function Rectangle( this, width, height )
|
||
this.width := width;
|
||
this.height := height;
|
||
endfunction
|
||
|
||
function area( this )
|
||
return this.width * this.height;
|
||
endfunction
|
||
|
||
function scale( this, factor )
|
||
this.width *= factor;
|
||
this.height *= factor;
|
||
endfunction
|
||
endclass
|
||
|
||
var circle := Circle( 5 );
|
||
print( circle.area() ); // Output: 78.53975
|
||
circle.scale( 2 );
|
||
print( circle.area() ); // Output: 314.159
|
||
|
||
var rectangle := Rectangle( 4, 6 );
|
||
print( rectangle.area() ); // Output: 24
|
||
rectangle.scale( 3 );
|
||
print( rectangle.area() ); // Output: 216
|
||
</pre></div>
|
||
|
||
<p>A compilation error will occur if any class does not define, or implements a
|
||
method with a different signature than, all uninitialized functions declared in
|
||
its base classes. For example, if <code>Circle</code> did not implement
|
||
<code>area( this )</code> and forgot to include the <code>factor</code>
|
||
parameter in <code>scale( this, factor )</code>:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
test.src:6:1: error: Class 'Circle' does not implement uninitialized function 'Shape::area'
|
||
See also: test.src:2:3
|
||
test.src:11:3: error: Class method 'Circle::scale' does not correctly implement uninitialized function 'Shape::scale':
|
||
Expecting class method with 2 parameters, got class method with 1 parameters.
|
||
See also: test.src:3:3
|
||
test.src: 2 errors, 0 warnings.
|
||
</pre></div>
|
||
|
||
<p>Classes with uninitialized functions can themselves inherit from classes with
|
||
their own uninitialized functions, which would "bubble up" the requirement of
|
||
implementation to the child class.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Colorable()
|
||
uninit function color( this, color );
|
||
endclass
|
||
|
||
class ColorableShape( Colorable )
|
||
uninit function area( this );
|
||
endclass
|
||
|
||
// A Circle is a ColorableShape, so it must implement both `area` (directly from
|
||
// ColorableShape) and `color` (indirectly from Colorable through ColorableShape).
|
||
class Circle( ColorableShape )
|
||
function Circle( this, radius, color )
|
||
this.radius := radius;
|
||
this.color := color;
|
||
endfunction
|
||
|
||
function area( this )
|
||
return 3.14159 * this.radius * this.radius;
|
||
endfunction
|
||
|
||
function color( this, new_color )
|
||
this.color := new_color;
|
||
endfunction
|
||
endclass
|
||
|
||
var circle := Circle( 5 );
|
||
circle.color( "red" );
|
||
print( circle.color ); // Output: red
|
||
print( circle.area() ); // Output: 78.53975
|
||
</pre></div>
|
||
|
||
<p>Additionally, the child class can inherit the implementation of an
|
||
uninitialized function from another class.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Loggable()
|
||
uninit function log( this, message );
|
||
endclass
|
||
|
||
class ConsoleLogger()
|
||
function log( this, message )
|
||
basicio::Print( $"[LOG] {message}" );
|
||
endfunction
|
||
endclass
|
||
|
||
// Application inherits the uninitialized `log` function from Loggable,
|
||
// and uses the implementation from ConsoleLogger.
|
||
class Application( Loggable, ConsoleLogger )
|
||
function Application( this, name )
|
||
this.name := name;
|
||
endfunction
|
||
|
||
function run( this )
|
||
this.log( $"{this.name} is running." );
|
||
endfunction
|
||
endclass
|
||
|
||
var app := Application( "MyApp" );
|
||
app.run(); // Output: [LOG] MyApp is running.
|
||
</pre></div>
|
||
|
||
<p>To specify that a child class must implement the constructor in a certain
|
||
way, declare an uninitialized function with the same name as the class
|
||
containing the uninitialized function:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class FormattedValueHolder()
|
||
// All classes that inherit from FormattedValueHolder
|
||
// must implement a constructor that takes two parameters.
|
||
uninit function FormattedValueHolder( this, value );
|
||
|
||
uninit function getValue( this );
|
||
endclass
|
||
|
||
class UppercaseValueHolder( FormattedValueHolder )
|
||
function UppercaseValueHolder( this, value )
|
||
this.value := Upper( value );
|
||
endfunction
|
||
|
||
function getValue( this )
|
||
return this.value;
|
||
endfunction
|
||
endclass
|
||
|
||
class LowercaseValueHolder( FormattedValueHolder )
|
||
function LowercaseValueHolder( this, value )
|
||
this.value := Lower( value );
|
||
endfunction
|
||
|
||
function getValue( this )
|
||
return this.value;
|
||
endfunction
|
||
endclass
|
||
|
||
var holders := array{ @UppercaseValueHolder, @LowercaseValueHolder };
|
||
|
||
foreach holder_constructor in holders
|
||
// Since all classes that inherit from FormattedValueHolder must
|
||
// implement a constructor that takes one parameter (excluding
|
||
// `this`), we can safely call the constructor with just one argument.
|
||
var holder := holder_constructor.new( "Hello World!" );
|
||
|
||
print( holder.getValue() );
|
||
endforeach
|
||
|
||
// Output:
|
||
// HELLO WORLD!
|
||
// hello world!
|
||
</pre></div>
|
||
|
||
<p>To declare that a function <i>must</i> have a default value, use the
|
||
<code>default</code> keyword in front of the parameter:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Greeter()
|
||
uninit function greet( this, name, default greeting );
|
||
endclass
|
||
|
||
class FriendlyGreeter( Greeter )
|
||
function FriendlyGreeter( this )
|
||
endfunction
|
||
|
||
function greet( this, name, greeting := "Hello" )
|
||
Print( $"{greeting}, {name}!" );
|
||
endfunction
|
||
endclass
|
||
|
||
var greeter := FriendlyGreeter();
|
||
|
||
greeter.greet( "Kevin" ); // Output: Hello, Kevin!
|
||
greeter.greet( "Kevin", "Salutations" ); // Output: Salutations, Kevin!
|
||
</pre></div>
|
||
|
||
<p><b>Example: Multiple Inheritance</b></p>
|
||
|
||
<p>A class can have multiple base classes in which it inherits from. When using <code>super()</code>,
|
||
the constructors of the base classes are called in the order they are listed in the class definition. Likewise, the arguments passed to <code>super()</code>
|
||
are passed to the base class constructors in the same order.</p>
|
||
</p>
|
||
<br/>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Colorable()
|
||
function Colorable( this, color )
|
||
this.color := color;
|
||
endfunction
|
||
endclass
|
||
|
||
class Drawable()
|
||
function Drawable( this, x, y )
|
||
this.x := x;
|
||
this.y := y;
|
||
endfunction
|
||
endclass
|
||
|
||
class Shape( Colorable, Drawable )
|
||
function Shape( this, color, x, y )
|
||
super( color, x, y );
|
||
endfunction
|
||
endclass
|
||
|
||
var shape := Shape( "red", 1, 2 );
|
||
print( $"{shape.color} {shape.x} {shape.y}" ); // Output: red 1 2
|
||
</pre></div>
|
||
|
||
<p><b><a name="chap12a">Advanced Techniques</a></b></p>
|
||
<br/>
|
||
|
||
<p><b>Method versus Function Call</b></p>
|
||
<br/>
|
||
|
||
<p>There are multiple ways to call class instance methods in EScript. The most
|
||
common way is to use the dot notation as a <i>method call</i>, as shown in the examples above. However,
|
||
you can also use a <i>function call</i> on the instance, which is useful when you want to use named arguments.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
var john := Person( "John", 30 );
|
||
john.rename( "Johnny" ); // Method call
|
||
Person::rename( john, "Johnny" ); // Function call
|
||
</pre></div>
|
||
|
||
<p>This may be useful when you want to use named arguments, as named arguments
|
||
cannot be used in a method call.</p>
|
||
<br/>
|
||
|
||
<p><b><code>super()</code> and Constructor Order</b></p>
|
||
<br/>
|
||
|
||
<p>When a class inherits from another class, using <code>super()</code> is a
|
||
convenient way to call the constructor of the base class(es). Each base class
|
||
constructor will be called in the order they are listed in the class definition.</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class A()
|
||
function A( this )
|
||
Print( "A constructor" );
|
||
endfunction
|
||
endclass
|
||
|
||
class B()
|
||
function B( this )
|
||
Print( "B constructor" );
|
||
endfunction
|
||
endclass
|
||
|
||
class C( A, B )
|
||
function C( this )
|
||
super();
|
||
Print( "C constructor" );
|
||
endfunction
|
||
endclass
|
||
|
||
var c := C(); // Output: A constructor, B constructor, C constructor
|
||
</pre></div>
|
||
|
||
<p>If you want to change the order of constructor calls done by
|
||
<code>super()</code>, then you must change the order of the base classes in the
|
||
declaration. It is possible to explicitly use a <i>function reference call</i> to a
|
||
specific constructor for even greater control of constructor call order:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class C( A, B )
|
||
function C( this )
|
||
@B::B( this );
|
||
@A::A( this );
|
||
Print( "C constructor" );
|
||
endfunction
|
||
endclass
|
||
|
||
var c := C(); // Output: B constructor, A constructor, C constructor
|
||
</pre></div>
|
||
|
||
<p><b><code>super()</code> and Argument Order</b></p>
|
||
<br/>
|
||
|
||
<p>Arguments used to a <code>super()</code> call are passed in order of the base
|
||
classes listed in the class definition. Additionally, you can use named
|
||
arguments to specify each base class constructor's arguments, allowing you to
|
||
not worry about the argument order:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class GreenShape( Colorable, Drawable )
|
||
function GreenShape( this )
|
||
super( color := "green", x := 10, y := 20 );
|
||
endfunction
|
||
endclass
|
||
|
||
var shape := GreenShape();
|
||
print( $"{shape.color} {shape.x} {shape.y}" ); // Output: green 10 20
|
||
</pre></div>
|
||
|
||
<p>If multiple base classes define the same parameter, you must specify the scope for each argument:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Item()
|
||
function Item( this, name )
|
||
this.description := name;
|
||
endfunction
|
||
endclass
|
||
|
||
class Color()
|
||
function Color( this, name )
|
||
this.color := name;
|
||
endfunction
|
||
endclass
|
||
|
||
class RedDagger( Item, Color )
|
||
function RedDagger( this )
|
||
super( Item::name := "dagger", Color::name := "red" ); // Using only `name` would give an ambiguous error!
|
||
endfunction
|
||
endclass
|
||
|
||
var item := RedDagger();
|
||
|
||
print( $"{item.color} {item.description}" ); // Output: red dagger
|
||
</pre></div>
|
||
|
||
<p><b><code>is</code> Operator</b></p>
|
||
<br/>
|
||
|
||
<p>You can use the <code>is</code> binary operator to check if a class instance
|
||
is of the class type provided (via function reference). The test includes any
|
||
ancestor class. Continuing the above example with <code>A</code>,
|
||
<code>B</code>, and <code>C</code>:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class A()
|
||
function A( this )
|
||
endfunction
|
||
endclass
|
||
|
||
class B()
|
||
function B( this )
|
||
endfunction
|
||
endclass
|
||
|
||
class C( A, B )
|
||
function C( this )
|
||
super();
|
||
endfunction
|
||
endclass
|
||
|
||
var c := C();
|
||
Print( c is @C ); // Output: 1
|
||
Print( c is @A ); // Output: 1 (since C is a subclass of A)
|
||
|
||
var b := B();
|
||
Print( b is @C ); // Output: 0
|
||
</pre></div>
|
||
|
||
<p><b>Class Instance <code>function</code> Member</b></p>
|
||
<br/>
|
||
|
||
<p>A class instance has a <code>function</code> member that is a function
|
||
reference to its constructor. To construct a new instance, use the
|
||
<code>new()</code> method on the function reference. This allows creating new
|
||
objects of the same class type as the instance without knowing what the instance
|
||
is at compile-time:</p>
|
||
|
||
<div class="doc-guide-pre"><pre>
|
||
class Person()
|
||
function Person( this, name, age )
|
||
this.name := name;
|
||
this.age := age;
|
||
endfunction
|
||
endclass
|
||
|
||
var person := Person( "Alice", 25 );
|
||
var other_person := person.function.new( "Bob", 30 );
|
||
|
||
print( $"{other_person.name} is {other_person.age} years old." ); // Output: Bob is 30 years old.
|
||
</pre></div>
|
||
|
||
<br/>
|
||
<br/>
|
||
|
||
<!-- ====================================================================== -->
|
||
|
||
<h3><a name="appE">Iterable Objects</a></h3>
|
||
<br/>
|
||
|
||
<p>The following objects are <i>iterable</i>, meaning they can be used in the following contexts:</p>
|
||
<ul>
|
||
<li><a href="#chap3d"><code>foreach</code> loops</a></li>
|
||
<li><a href="#chap1aa">binding statements</a></li>
|
||
<li><a href="#chap11i">spread operator</a></li>
|
||
</ul>
|
||
<br/>
|
||
|
||
<table border="1" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||
<thead>
|
||
<tr>
|
||
<th>Object</th>
|
||
<th>Key</th>
|
||
<th>Iterator Value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Array</td>
|
||
<td>Index (number)</td>
|
||
<td>Element at index</td>
|
||
</tr>
|
||
<tr>
|
||
<td>ClassInstanceRef</td>
|
||
<td>Member (string)</td>
|
||
<td>Value of member</td>
|
||
</tr>
|
||
<tr>
|
||
<td>ConfigFileRef<sup>*</sup></td>
|
||
<td>Config element key (string)</td>
|
||
<td>ConfigElemRef for that key</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Dictionary</td>
|
||
<td>Key (any script object)</td>
|
||
<td>Value at key</td>
|
||
</tr>
|
||
<tr>
|
||
<td>SQLResultSet<sup>*</sup></td>
|
||
<td>Current index of row being processed (number)</td>
|
||
<td>Current SQLRow</td>
|
||
</tr>
|
||
<tr>
|
||
<td>SQLRow<sup>*</sup></td>
|
||
<td>Column name (string)</td>
|
||
<td>Column value</td>
|
||
</tr>
|
||
<tr>
|
||
<td>String<sup>*</sup></td>
|
||
<td>Index (number)</td>
|
||
<td>Character at index</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Struct</td>
|
||
<td>Member (string)</td>
|
||
<td>Value of member</td>
|
||
</tr>
|
||
<tr>
|
||
<td>XMLAttribute</td>
|
||
<td>Current index of XML attribute being processed (number)</td>
|
||
<td>A <code>struct</code>, having a member with the attribute's name storing the attribute's value</td>
|
||
</tr>
|
||
<tr>
|
||
<td>XMLFile</td>
|
||
<td>Current index of XML node being processed (number)</td>
|
||
<td>XMLNode</td>
|
||
</tr>
|
||
<tr>
|
||
<td>XMLNode</td>
|
||
<td>Current index of XML node being processed (number)</td>
|
||
<td>XMLNode</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<br/>
|
||
|
||
<p>*: Iterator support added in POL 100.2.0</p>
|
||
|
||
<br/>
|
||
<br/>
|
||
<!-- ====================================================================== -->
|
||
<h3><a name="appX">Appendix X: Revision History</a></h3>
|
||
<br/>
|
||
|
||
<p>
|
||
v0.1: 6/27/2000<br>
|
||
Initial preliminary document<br>
|
||
v0.2: 7/19/2000<br>
|
||
Added sections on Case, built-in props, Object Ref chart<br>
|
||
v0.3: 7/21/2000<br>
|
||
Added Gump Tag descriptions, CProp Chapter, Package Chapter<br>
|
||
v0.4: 7/22/2000<br>
|
||
Added Debugging Chapter<br>
|
||
v0.5: 7/25/2000<br>
|
||
Cleaned up, added contact info, first public version.<br>
|
||
v0.6: 11/01/2000<br>
|
||
Turned into HTML.
|
||
Corrected an error in the CASE section.
|
||
Added info about CProps and accounts.
|
||
Added Chapter 11. -Madman<br>
|
||
v0.6a: 11/06/2000<br>
|
||
Added Table of Contents, cell borders on some tables. -Madman<br>
|
||
v0.6b: 15/06/2006<br>
|
||
Fixed some eScript comparisons and assignments.
|
||
Removed some 'local's. Added 'do..dowhile()'. -Shinigami<br>
|
||
v0.6c: 7/07/2006<br>
|
||
Removed object property/method lists,
|
||
updated data structures and iterations and trillions of smaller things. -Austin<br>
|
||
v0.6d: 19/02/2009<br>
|
||
Reformated. -Turley<br>
|
||
v0.6e: 12/10/2015<br>
|
||
Cleaned HTML code. - Bodom</p>
|
||
<p>v0.7: 07/09/2018<br/>
|
||
Added additional information regarding AND, OR, XOR, Ones Compliment operators supplied by Yukiko<br>
|
||
</p>
|
||
<p>v0.8: 01/11/2019<br/>
|
||
Added documentation for finding the ordinal location of an element in an array by ThisIsMe<br>
|
||
</p>
|
||
<p>v0.9: 05/01/2020<br/>
|
||
Added documentation for Elvis Operator by Syzygy<br>
|
||
<p>v0.10: 11/03/2020<br/>
|
||
Added documentation for Interpolated Strings by Kevin<br>
|
||
<p>v0.11: 14/03/2020<br/>
|
||
Added documentation for Conditional Operator, Operator Precendences by Kevin<br>
|
||
</p>
|
||
<p>v0.12: 29/07/2024<br/>
|
||
Added documentation for Function Expressions by Kevin<br>
|
||
</p>
|
||
<p>v0.13: 02/08/2024<br/>
|
||
Added documentation for Functional Programming with Arrays by Kevin<br>
|
||
</p>
|
||
<p>v0.14: 04/08/2024<br/>
|
||
Added documentation for Variadic User Functions by Kevin<br>
|
||
</p>
|
||
<p>v0.15: 05/08/2024<br/>
|
||
Added documentation for Spread Operator by Kevin<br>
|
||
</p>
|
||
<p>v0.16: 16/02/2025<br/>
|
||
Added documentation for Sequence and Index Binding Statements; Iterable Objects by Kevin<br>
|
||
</p>
|
||
<p>v0.17: 17/08/2025<br/>
|
||
Added documentation enum declarations by Kevin<br>
|
||
</p>
|
||
<p>v0.18: 05/09/2025<br/>
|
||
Added documentation for class uninitialized functions by Kevin<br>
|
||
</p>
|
||
<p>v0.19: 06/09/2025<br/>
|
||
Added documentation for defaulted parameters in class uninitialized functions by Kevin<br>
|
||
<p>v0.20: 15/11/2025<br/>
|
||
Added documentation for regular expressions by Kevin<br>
|
||
</p>
|