Scripting Reference - Kagamma/satania-buddy GitHub Wiki

What is this?

Evil script is a simple and lightweight scripting language, designed specially for satania-buddy. It’s syntax is influenced by C, Pascal and Lua.

Hello World

talk('Hello, World!')

Libraries

  • Common libraries can be found in data/scripts/libs
  • Character’s specific libraries normally located in data/scripts/<character_directory_name>/libs

Language

Include other scripts / libraries

  • The script engine will first look for scripts at the absolute path, and if no script is found there, it will search for scripts in the character’s scripts directory.
using 'path/to/script.evil'

Types

string, number, boolean, map, buffer, function, null

Evil script is a dynamic language. This means that a variable can point to any type at runtime.

Numbers and Booleans are stored as 64-bit floating point number.

Strings are by default in UTF-8 format.

Maps are the only data structure available in evil script that helps us create different types like arrays and dictionaries. Maps can be indexed with both numbers and strings. Maps have no fixed size and can grow based on our need.

For those who familiar with Lua, maps are basically the same as Lua’s tables.

Buffers are used to interface with DLL libraries written in native languages like C or Pascal. It is basically a space within the system memory that is used to store raw data for just about anything. Underneath a buffer is just a pointer and you can perform pointer arimethic on it.

Strings, Maps and Buffers are subject to automatic memory management. You do not have to worry about allocation and deallocation of these data types.

Operators

Operator                                        Precedence
==============================================  ==========
 !, sign "-"                                     1
 *, /                                            2
 +, subtract "-"                                 3
 bitshift <<, >>                                 4
 equal "=", !=, <, <=, >, >=, &, |, ~, pow "^"   5
 assign "=", +=, -=, *=, /=                      6

Bitwise operator     Description
==================== =============
 <<                   Shift left
 >>                   Shift right
 &                    and
 |                    or
 ~                    xor
 !                    not

Evil script does not support logic operators, thus it does not distinguish between =, &, | and ==, &&, ||, allowing them to be used interchangeably.

Variable declarations / assignments

a = 5
// Assign 5 to a

a += 2 * 5
// a = a + (2 * 5)

a = 'a string'
// 'a' is now a string

b = 'this is ${a}'
// Replace ${a} with the content in variable a. The result will be 'this is a string'
// It is equivalent to: b = 'this is ' + string(a)

b = 'this is
a multi-line
string'

a[2] = 'S'
// Replace char "s" with "S" in string 'a'

c = []
// Create an empty map and store its reference in 'c'
// By default a newly created empty map is considered as a valid array. It will lose it's array status
// once we start adding entries that doesn't make sense to the map.
// Evil script optimizes maps with valid array status, by storing values in an actual array underneath
// for quick access.
// A nice trick to create array with size is to set the last index, for example: c[99] = null
// This will increase array size to 100

c = [ name: 'Satania', race: 'Demon' ]
// Create a map with 2 entries and store its reference in 'c'

c['item'] = 'orange'
// New entry, with key="item" and value="orange"

c.item = 'orange'
// Same as above, but use dot notation instead of square bracket notation

d = [2, 3, 4, 'a string', 'another string']
// Create a map as a valid array, with 5 items

d[1] = 'another string'
// The second element of array 'd' is replaced with 'another string'

d['a'] = 5
// 'd' is no longer a valid array
  • Strings are copy-on-write, while maps are passed by reference.

Statements

expressions = a + b * c / d + (5 - 2)

s_concat = 'a string ' + "another string"

array_concat = [1, 2, 'pine'] + [5, 7]
// Concat arrays. This only work correctly if both maps are valid array.
// Result in [1, 2, 'pine', 5, 7]

map_concat = ['a': 1, b: 1] + ['b': 2, 'c': 3]
// Concat maps. This only work correctly if both maps are not valid array.
// Result in ['a': 1, 'b': 2, 'c': 3]

and = a & b

or = a | b

not = !a

pow = a^b

bitwise_left_shift = a << b

bitwise_right_shift = a >> b

If block

if (a < b) & (c < d) {
  // Do something
} else if (a > b) {
  // Do something
} else {
  // Do something
}

While block

i = 0
while i < a {
  if b = i {
    break
  }
  if c = i {
    continue
  }
  i = i + 1
}

Do..while block

i = 0
do {
  if b = i {
    break
  }
  if c = i {
    continue
  }
  i = i + 1
} while i < a

For block

for i = 0 to 4 {
  if i < 2
    continue
  break
}

for i = 4 downto 0 {
  if i > 2
    continue
  break
}

For-in block

For-in block only work correctly with valid array.

for value in [1, 2, 5, 7, 9] {
  if value = 5
    break
}
for value, index in [1, 2, 5, 7, 9] {
  talk(string(index) + ": " + string(value))
}

Switch-case block

a = 5
switch a {
  case 4:
  case 5:
    talk('4,5')
    break
  case 6:
    talk('6')
    break
  default:
    talk('default')
}
  • Unlike C, Evil script’s switch case allows the use of expressions, so the above example can be written like this:
a = 5
switch true {
  case (a = 4) | (a = 5):
    talk('4,5')
    break
  case (a = 6):
    talk('6')
    break
  default:
    talk('default')
}
  • Strings are allowed:
s = 'alpha'
switch s {
  case 'alpha':
    talk('alpha')
    break
  case 'beta':
    talk('beta')
    break
  case 'gamma':
    talk('gamma')
}

Function declaration

fn foo() {
  fn this_is_a_nested_function() {
    return (true)
  }
  talk('Hello')
  return (this_is_a_nested_function())
  talk("This text won't show on screen")
}

fn add(a, b) {
  result = a + b
}

fn sub(a, b) {
  return (a - b)
}

foo()
c = add(5, 3)
  • Alternative way to declare a function is by returning a function reference:
add = fn(a, b) {
  result = a + b
}

There’re 2 ways to return a value:

  • Assign function result to result variable
  • Use return. Note that you need to wrap expression in brackets, for example return (true)

Note: While we allow the declaration of nested functions, the lack of closures mean they cannot access any local variables from the parent function if called outside of parent function.

Function reference

fn add(a, b) {
  result = a + b
}
add_ref = add
calc = []
calc.add = add

talk(add_ref(5, 3)) // Print "8"
talk(calc.add(2, 4)) // Print "6"
talk(calc.add = add_ref) // Print "true"

Anonymous function

fn test(func) {
  func('Satania')
}

test(fn(v) writeln('Hello, ${v}!'))
test(fn(v) {
  writeln('Goodbye, ${v}!')
})
  • The following function declarations are the same:
fn(n) = n + 1

fn(n) result = n + 1

fn(n) { result = n + 1 }

Self

fn obj_create() {
  fn hello() {
    result = 'Hello, ' + self.name + '!'
  }

  result = [
    name: '',
    hello: hello
  ]
}

another_obj = [
  hello: hello,
  name: 'Gabriel',
]

obj = obj_create()
obj.name = 'Satania'
writeln(obj.hello()) // obj will be passed to hello() as "self"
  • Because of the way we pass self, one function can be used in multiple object instances, for example:
fn test() {
  result = self.value
}

obj1 = [
  value: 1,
  test: test,
]

obj2 = [
  value: 2,
  test: test,
]

writeln(obj1.test())
writeln(obj2.test())
  • There are limitations in how self is passed to the calling function. Only a map returned from the nearest function call can be passed.
  • The following examples will work correctly:
obj.call() // obj is passed as self
obj.middle.call() // middle is passed as self
func().call() // Result from func() is passed as self
obj.func().func2().call()
  • However, the following example won’t work:
func().middle.call() // the result from func() will be passed as "self" instead of middle
  • Solution for this issue is to assign middle to a named variable:
mid = func().middle
mid.call()

Yield

  • Quit the script and returns to main process. When the process execute the script in next frame, it will continue at where yield’s called.
while true {
  yield
}

Try-catch

fn test() {
  throw 'Test exception'
}

try {
  writeln('start')
  test()
  writeln('finish')
} catch(e) {
  writeln('Exception: ', e)
}

Comment

// A comment

/*
  A
  multi-line
  comment
*/

Import external functions from dynamic libraries

import 'test.dll' {
  fn Add(i32, i32): i32
  fn AddDouble(f64, f64): f64
}
import 'user32.dll' fn MessageBox(i32, buffer, buffer, i32): void 'MessageBoxA' // Map MessageBoxA external function to MessageBox

MessageBox(0, 'Hello, World!', 'Message Box', 0) // Strings are automatically converted to null-terminated strings

List of supported data types:

  • i8: char
  • u8: unsigned char
  • i16: short
  • u16: unsigned short
  • i32: long
  • u32: unsigned long
  • i64: long long
  • u64: unsigned long long
  • f32: float
  • f64: double
  • buffer: char*
  • wbuffer: wchar*
  • void: This simply tell the app the function does not return any value.

By default, import supports Microsoft x64 calling convention on Windows, and System V AMD64 ABI on Linux. There’s no way to change calling convention at the moment.

Assert

assert(expr, 'Error message')

With assertions on, assert tests if expr is false, and if so, aborts the script with an EAssertionFailed exception. If expr is true, script execution continues normally. If assertions are not enabled at compile time, this routine does nothing, and no code is generated for the assert call. You can enable assertions globally in Settings, or locally in script editor.

Constants

PI: number

true: boolean

false: boolean

name: string deprecated, use charname instead

charname: string

  • Gets character’s name

username: string

  • Gets user’s name

character: string

  • Gets character’s directory name

meta: map

  • meta.json content

os: string

  • Gets OS name

Common functions

typeof(v: any): string

  • Returns type of variable (number / boolean / string / map / array / buffer / function / null).

string(n: number): string

  • Converts n to string.

number(s: string): number

  • Converts s to number.

write(…)

  • Writes to console.

writeln(…)

  • Writes to console. End with newline.

wait(seconds: number)

  • Wait in seconds. This won’t block the main process.

map_create(): map

  • Creates a new map. This function is comparable to [] syntax.

map_key_delete(a: map, key: number/string): map

  • Deletes map elements.

map_keys_get(a: map): map

  • Returns map contains all keys from map a.

array_resize(a: map, size: number): map

  • Resizes a valid array.

array_to_map(arr: array): map

  • Converts array arr to map. Note that arr itself will be converted.

length(a: map/string)

  • Returns length of string, map or buffer.

random(n: number): number

  • Returns a random integer number range from 0 - (n-1)

rnd: number

  • Returns a random number range from 0 - 1

sign(n: number): number

round(n: number): number

floor(n: number): number

ceil(n: number): number

sin(n: number): number

cos(n: number): number

tan(n: number): number

cot(n: number): number

sqrt(n: number): number

range(x, y: number): map

  • Returns [x..y] array with step = 1.

range(x, y, step: number): map

  • Returns [x..y] array.

min(…): number

max(…): number

chr(number): string

  • Typecasts a number (0..255) to equivalent char value.

ord(string): number

  • Typecasts a char to equivalent number value.

Buffers

buffer_create(size: number): buffer

  • Creates a new buffer. The result is a pointer points to the start of allocated memory.

buffer_length(buffer: buffer): number

  • Returns length of a buffer.

buffer_copy(dst, src: buffer, count: number): number

  • Copy count bytes from src to dst.

buffer_u8_fill(buffer: buffer, value, count: number): number

  • Sets the first count bytes of the block of memory pointed by buffer to the specified value (interpreted as an unsigned char).

buffer_u16_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 2 bytes of the block of memory pointed by buffer to the specified value (interpreted as an unsigned short).

buffer_u32_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 4 bytes of the block of memory pointed by buffer to the specified value (interpreted as an unsigned int).

buffer_u64_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 8 bytes of the block of memory pointed by buffer to the specified value (interpreted as an unsigned long long).

buffer_i8_fill(buffer: buffer, value, count: number): number

  • Sets the first count bytes of the block of memory pointed by buffer to the specified value (interpreted as an char).

buffer_i16_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 2 bytes of the block of memory pointed by buffer to the specified value (interpreted as an short).

buffer_i32_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 4 bytes of the block of memory pointed by buffer to the specified value (interpreted as an int).

buffer_i64_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 8 bytes of the block of memory pointed by buffer to the specified value (interpreted as an long long).

buffer_f32_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 4 bytes of the block of memory pointed by buffer to the specified value (interpreted as an float).

buffer_f64_fill(buffer: buffer, value, count: number): number

  • Sets the first count * 8 bytes of the block of memory pointed by buffer to the specified value (interpreted as an double).

buffer_u8_get(buffer: buffer): number

  • Gets 1-byte unsigned data from buffer.

buffer_i8_get(buffer: buffer): number

  • Gets 1-byte data from buffer.

buffer_u16_get(buffer: buffer): number

  • Gets 2-byte unsigned data from buffer.

buffer_i16_get(buffer: buffer): number

  • Gets 2-byte data from buffer.

buffer_u32_get(buffer: buffer): number

  • Gets 4-byte unsigned data from buffer.

buffer_i32_get(buffer: buffer): number

  • Gets 4-byte data from buffer.

buffer_u64_get(buffer: buffer): number

  • Gets 8-byte unsigned data from buffer.

buffer_i64_get(buffer: buffer): number

  • Gets 8-byte data from buffer.

buffer_f32_get(buffer: buffer): number

  • Gets float-type data from buffer.

buffer_f64_get(buffer: buffer): number

  • Gets double-type data from buffer.

buffer_u8_set(buffer: buffer, data: number): number

  • Writes 1-byte unsigned data to buffer.

buffer_i8_set(buffer: buffer, data: number): number

  • Writes 1-byte data to buffer.

buffer_u16_set(buffer: buffer, data: number): number

  • Writes 2-byte unsigned data to buffer.

buffer_i16_set(buffer: buffer, data: number): number

  • Writes 2-byte data to buffer.

buffer_u32_set(buffer: buffer, data: number): number

  • Writes 4-byte unsigned data to buffer.

buffer_i32_set(buffer: buffer, data: number): number

  • Writes 4-byte data to buffer.

buffer_u64_set(buffer: buffer, data: number): number

  • Writes 8-byte unsigned data to buffer.

buffer_i64_set(buffer: buffer, data: number): number

  • Writes 8-byte data to buffer.

buffer_f32_set(buffer: buffer, data: number): number

  • Writes float-type data to buffer.

buffer_f64_set(buffer: buffer, data: number): number

  • Writes double-type data to buffer.

string_to_buffer(s: string): buffer

  • Returns pointer point to the first element of the string.

buffer_to_string(b: buffer): string

  • Copies buffer content to string.

wbuffer_to_string(b: buffer): string

  • Copies wbuffer content to string.

buffer_to_array_f32(b: buffer, count: number): map

  • Converts count floats from buffer to valid array.

buffer_to_array_f64(b: buffer, count: number): map

  • Converts count doubles from buffer to valid array.

array_to_buffer_f32(a: map): buffer

  • Converts a valid array to a buffer. The buffer’s type of data is float.

array_to_buffer_f64(a: map): buffer

  • Converts a valid array to a buffer. The buffer’s type of data is double.

Strings

numbers(s: string): map

  • Converts words to map of numbers.
    • Input: two thousands five hundreds kg of stones arrived at ten o’clock
    • Output: [2500, 10]

months_to_numbers(s: string): map

  • Converts words to map of numbers represent month.
    • Input: february and november
    • Output: [2, 11]

string_concat(s, s1, s2: string)

  • Concatenates s1 and s2 and save result to s, without creating a new copy of s. Use this instead of s = s1 + s2 if you try to concatenate a lot of strings.

string_empty(s)

  • Empties string s. It is used to set a string built by string_concat() back to an empty string.

string_insert(source, substring: string, index: number): string

  • Inserts a string at index.

string_grep(s: string, subs: map of strings): string

  • greps a string

string_split(s, delimiter: string): map

  • Splits a string into multiple parts.

string_find(s, sub: string): number

  • Finds location of substring in a string. Return -1 if no substring is found.

string_delete(s: string, index, count: number): string

  • Deletes part of a string at index.

string_replace(s, old, new: string): string

  • Replaces all old with new in string s.

string_replace_ignorecase(s, old, new: string): string

  • Same as string_replace(), but ignore case.

string_uppercase(s: string): string

  • Returns uppercase string.

string_lowercase(s: string): string

  • Returns lowercase string.

string_trim(s: string): string

  • Trims string.

string_trim_left(s: string): string

  • Trims left of string.

string_trim_right(s: string): string

  • Trims right of string.

string_format(s: string, subs: map): string

  • Replaces a string with contents from map
    • Example: string_format('{0} is {1} gold', ['Key', 500]) => Key is 500 gold

string_find_regex(s, regex: string): map

  • Returns map of matched string + matched location.

Base64

base64_encode(buf: buffer): string

  • Encodes a given string to base64 string.

base64_decode(s: string): buffer

  • Decodes a given base64 string back to original string.

Datetime

ticks(): number

  • Returns system’s ticks, in miliseconds.

dt_now(): number

  • Returns current time in datetime format.

dt_year_get(dt: number): number

  • Returns year in number.

dt_month_get(dt: number): number

  • Returns month number.

dt_day_get(dt: number): number: number

  • Returns day number.

dt_hour_get(dt: number): number

  • Returns hour number.

dt_minute_get(dt: number): number

  • Returns minute number.

dt_day_add(dt, days: number): number

  • Increases dt by number of days.

dt_month_add(dt, months: number): number

  • Increases dt by number of months.

dt_year_add(dt, years: number): number

  • Increases dt by number of years.

dt_date_set(year, month, day: number): number

  • Encodes date from year, month and day.

dt_time_set(hour, minute, second, milisecond: number): number

  • Encodes time from hour, minute, second and milisecond.

File system

fs_directory_create(path: string)

  • Creates new directory.

fs_directory_delete(path: string)

  • Deletes directory.

fs_directory_find_all(path: string, is_subdir: boolean)

  • Performs search for directories in certain paths. Return map of paths.

fs_directory_exists(path: string): boolean.

  • Checks if a directory is exists.

fs_directory_config_get(): string

  • Returns satania-buddy’s config directory path.

fs_file_read_binary(filename: string): buffer

  • Reads content from file.

fs_file_write_binary(filename: string, buf: buffer, buf_size: number)

  • Writes content at the end file. If the file is not exist then a new file is created.

fs_file_read(filename: string): string deprecated, use fs_file_read_text() instead

fs_file_read_text(filename: string): string

  • Reads text from file.

fs_file_write(filename, text: string) deprecated, use fs_file_write_text() instead

fs_file_write_text(filename, text: string)

  • Writes text at the end of file. If the file is not exist then a new file is created.

fs_file_find_all(path, mask: string, is_subdir: boolean, attribute: number): map

  • Performs search for files in certain paths. Return map of paths.
  • List of attributes:
    • FA_DIRECTORY
    • FA_READONLY
    • FA_NORMAL
    • FA_ENCRYPTED
    • FA_COMPRESSED
    • FA_SYMLINK
    • FA_SYSFILE
    • FA_ANYFILE

fs_file_copy(src, dst: string): boolean

  • Copies src to dst, override if dst exists. Return true if success.

fs_file_exists(filename: string): boolean

  • Checks if a file exists.

fs_file_delete(filename: string)

  • Deletes a file.

fs_file_rename(oldname, newname: string)

  • Renames a file.

fs_file_size_get(filename: string): number

  • Returns size of file in bytes.

fs_file_age_get(filename: string): number

  • Returns the last modification Unix time of file.

Clipboard

clipboard_get(): string

  • Gets text from clipboard.

clipboard_to_file(filename: string)

  • Saves content (image, text) from clipboard to a file.

Process

process_run(process: string, show_window: boolean): string

  • Runs a process by name. Return process guid.

process_pipe_get(guid: string): map

  • Returns process’s actual id, status and stdout / stderr pipes: [ “process_id”: number, “running”: boolean, “output”: null / string ]

process_pipe_set(guid, s: string)

  • Writes s to process’s stdin pipe.

process_terminate(guid: string)

  • Terminates process.

HTTP requests

url_encode(s: string): string

  • Encodes URL element.

url_decode(s: string): string

  • Decodes URL element.

http_open(url: string)

  • Opens an URL using default web browser.

http_fetch(method, url: string, headers: map, data: string/map): string

  • Makes a request to URL. Return guid.

http_upload(url: string, headers: map, data: string/map, field, file: string): string

  • Uploads a file to URL. Return guid.

http_progress_get(guid: string): map

  • Gets current progress of HTTP request. Result map contains position and length: [ position: number, length: number ]

http_is_success(guid: string): boolean

  • Checks if url query (get, post, etc) is finished.

http_result_get(guid: string, force_buffer: boolean): map

  • Gets HTML result from url_fetch / url_upload. Result map contains status, headers and data. Depends on Content-Type, data can be either string or buffer: [ status: number, headers: map, data: string | buffer ]
  • force_buffer is optional. If it is set to true, then result data is always buffer.

http_query(data, xpath: string): map

  • Extracts data from HTML string.

Email

email_load(): boolean

  • Tells Satania to check for email’s connection.

email_unseen_count(): number

  • Returns number of unread emails.

email_sender_get(email_index: number): string

  • Gets email’s sender.

email_subject_get(email_index: number): string

  • Gets email’s subject.

email_is_loading(): boolean

  • Returns true if Satania is loading emails.

email_is_success(): boolean

  • Returns true if Satania is succeeded in loading emails.

email_is_configured(): boolean

  • Returns true if IMAP is configured in Settings.

JSON

json_parse(json: string): map

  • Converts a JSON string to map.
    • json = json_parse(‘{ “a”: 5, “b”: 2, “c”: { “d”: “a text”, “e”: [“another text”, 2] } }’) will return a map, which can be accessed for values for example: json.c.e[0] // another text

json_stringify(map: map): string

  • Converts a map to JSON string.

Workers

  • Please note workers run on the same thread as main script. Make sure to use yield to avoid infinite loop.

worker_create(worker_name: string, evil_script: string, interval: number, consts: map): string

  • Creates a new worker. Unlike main script, workers will automatically delete itself once its done executing.
  • Unless the worker is marked as persistent, workers will be deleted if user changes character.
    • worker_name: Name of worker.
    • evil_script: The script that will be executed by worker.
    • interval: Optional. Measure in seconds. This tells how frequent this worker run. By default this value is 0.
    • consts: Optional. Map of constant values that will be passed to worker.
    • Return: Worker name.

worker_persistent_set(worker_name: string, persistent: boolean)

  • Sets worker’s persistent flag.

worker_exists(worker_name: string): boolean

  • Checks if a worker exists.

worker_delete(worker_name: string)

  • Deletes a worker by name.

Other script-related functions

app_close_script_register(name: string, script: string)

  • Registers a script script that will be executed when the app is closed.

app_close_script_unregister(name: string)

  • Removes registered script by name.

Tools

tool_evilc_editor(filename: string)

  • Opens a file with built-in EvilC editor.

tool_hex_editor(filename: string)

  • Opens a file with built-in hex editor.

Memory management

mem_used(): number

  • Returns memory usage by script engine in bytes.

mem_object_count(): number

  • Returns number of objects allocated by script engine.

mem_gc()

  • Triggers garbage collection.

Satania-specific function

talk(message: string)

  • Tells Satania to talk.
  • The script engine will be blocked until all the text is shown on screen.
  • Calling this function will automatically disable streaming mode

stream_enable()

  • Enables streaming mode. Useful for integrating with chatbot backends

stream_disable()

  • Disables steaming mode.

stream(message: string)

  • Streams a text to chat window / speech bubble

notify(message: string)

  • Shows a notification at top-left of the screen.

ask(caption, message: string, width, height: number)

  • Shows asking dialog. Supports HTML 4.01. width and height are optional parameters allows to change dialog’s size. Satania will be blocked until one answer is provided so make sure to provide at least 1 way to answer the question. Look at examples below for ways to provide answers.
  • Example #1:
ask('', '
<font color="red"><b>Are you sure?</b></font><br />
<a href="Yes">Yes</a><br />
<a href="No">No</a><br />
', 250, 80)

  • Example #2:
ask('', '
What do you think about me?<br />
<form>
  <input style="width:100%" name="thought" value="Your answer" /><br />
  <input type="submit" value="Tell her!" />
</form>
')

answer(): any

  • Returns result value from ask(). If no answer is found, then it returns null.
  • For example #1, the result is a string, either Yes or No, taken from href attribute.
  • For example #2, the result is a map, which is [ “thought”: “Your answer” ].

sprite_animation_stop_all()

  • Stops all animations.

sprite_load(sprite: string)

  • Loads a model (supports X3D, Spine, images, glTF, Cocos2D, Starling) in data/sprites/current_character

sprite_animation_speed_set(animation_name: string, total_time: number) sprite_animation_exists(animation_name: string): boolean

  • Checks if an animation exists or not.

sprite_animation_speed_set(animation_name: string, time: number)

  • Sets animation’s interval in seconds.

sprite_animation_play(animation_name: string, loop: boolean = false)

  • Plays an animation by name
  • For skeletal animations, the animations are not override each other so you can play multiple animations at once.

sprite_animation_is_playing(animation_name: string): boolean

  • Returns true if animation is playing.

sprite_animation_stop(animation_name: string)

  • Stops an animation.

sprite_animation_talk_set(loop, finish: string, random_script_files: map of strings)

  • Sets default talking animations.
  • random_script_files is optional, which indicates which script to run when start talking. This is useful if you want your character to play different animations when start talking.

sprite_scale_set(scale: number)

  • Scales the sprite.

sprite_visible_set(visible: boolean)

  • Sets sprite visibility

sprite_visible_get(): boolean

  • Gets sprite visibility

sprite_other_create(name: string)

  • Creates a new sprite with name. Sprites created using this function can only be controlled by sprite_other_xxx() functions

sprite_other_render(name: string, source: string, format: string)

  • Renders sprite name with content from source. If name doesn’t exist, create a new one.
  • format accepts the following formats:
    • x3dv: Source is X3D with classic encoding string
    • wrl: Same as x3dv
    • x3d: Source is X3D eith XML encoding string
  • Example display a 3D yellow cube with a point light source, rotating at character’s feet, using x3dv format:
sprite_other_render('cube3d',
  '#X3D V3.0 utf8
  PROFILE Interchange

  PointLight {
    ambientIntensity 1
    location 0 0 100
    color 1 1 1
    radius 200
    global FALSE
  }

  DEF cube Transform {
    translation 0 30 -3
    scale 50 50 50
    children [
      Shape {
        geometry Box {}
        appearance Appearance {
          material Material {
            diffuseColor 1 1 0
          }
        }
      }
    ]
  }
  DEF interp OrientationInterpolator {
    key [ 0, 0.5 1 ]
    keyValue [
      1 1 1 0, 1 1 1 3.14, 1 1 1 6.28
    ]
  }
  DEF timer TimeSensor {
    loop TRUE
    cycleInterval 4
  }
  ROUTE timer.fraction_changed TO interp.set_fraction
  ROUTE interp.value_changed TO cube.rotation
}', 'x3dv')

sprite_other_delete(name: string)

  • Deletes other sprite with name

sprite_other_delete_all()

  • Deletes all other sprites

is_sow(): boolean

  • Returns true if Sit on Window is turned on.

is_lewd(): boolean

  • Returns true if Fanservice is turned on.

is_silent(): boolean

  • Returns true if Silent is turned on.

is_speech_to_text(): boolean

  • Returns true if Speech Recognition is turned on.

is_commands(): boolean

  • Returns true if Commands is turned on.

flag_global_get(flag: string): string

  • Gets a flag from configs.json. If no flag is found, the function return null instead.

flag_global_set(flag: string, value: string)

  • Sets a flag. Result stores in configs.json.

flag_local_get(flag: string): string

  • Gets a flag from scripts/<character directory>/flags.ini. If no flag is found, the function return null instead.

flag_local_set(flag: string, value: string)

  • Sets a flag. Result stores in scripts/<character directory>/flags.ini.

get(flag: string): any

  • Gets a flag from memory. If no flag is found, the function return null instead.
  • The data retrieved from get() is the same as the one set by the set() function.
  • You can use this function, combined with set(), to exchange data between multiple scripts.
  • A predefined flag global is available by default. This flag, which is a map, can be used as a common way to exchange data.
  • Example:
global = get('global') // Retrieve global flag
global.value = 'This is a string'
// No need to call set() to set the global flag back. global.value can now be accessed by any scripts.

set(flag: string, value: any)

  • Sets a flag. Result stores in memory.
  • You can use this function, combined with get(), to exchange data between multiple scripts.
  • Example:
set('new_flag', 'Data')
// 'new_flag' can now be retrieved from other scripts, by calling get('new_flag')

scheme_load(scheme_name: string)

  • Loads and execute an .evil scheme file in data/scripts/current_character. This will also stop the current script.

scheme_execute(script: string)

  • Executes script script. This will also stop the current script.

scheme_default(): string

  • Returns Default Evil Script.

delta_time(): number

  • Delta Time, in seconds.

sound_play(sound_name: string)

  • Plays a sound in sounds directory.

chat_mode_set(chatmode: number)

  • Set chat mode:
    • CHATMODE_CHAT
    • CHATMODE_SCRIPT: Tell Satania we will process chat messages in script.

chat_result_get(): string

  • This function only useful when chat mode = CHATMODE_SCRIPT.
  • Get chat message input by users, either via Speech Recognition or via Chat dialog. Chat message will be cleared once this function is called, so make sure to save the results somewhere.
  • If no chat message is found, an empty string will be returned.

chat_history_get(): array

  • Returns array of chat message. Each item has the following format: { name: string, message: string, timestamp: string }

chat_bubble_get(): string

  • Gets the current text in chat bubble.

About Evil script compiler

  • The compiler itself is a one-pass compiler. It follows Niklaus Wirth’s design, completely skips AST generation and generates binary directly.
  • Due to the lack of AST, only constant folding and peephole optimizations are implemented.
  • The performance of its virtual machine should be better than CPython.
⚠️ **GitHub.com Fallback** ⚠️