NoxScript

Данная документация покрывает движек NoxScript реализованный в OpenNox.

Runtimes

На данный момент, список поддерживаемых скриптовых движков включает:

Для быстрого ознакомления с NoxScript, см как начать.

Некоторые из вопросов могут быть уже покрыты в Q&A. Так же доступны примеры.

Если вопросы не нашли ответа, можно задать их здесь или в нашем Discord.

Подразделы NoxScript

Как начать

Это руководство поможет создать ваш первый скрипт используя интерфейс скриптов OpenNox на языке Go.

Первые шаги

Заметка

Удостовертесь что у вас установлен OpenNox. Оригинальный Nox, Reloaded или иная версия не будут работать!

Чтобы создать ваш первый скрипт, скопируйте существующую папку одной из карт, либо создайте новую карту в редакторе. Если карта была скопирована, удостоверьтесь что файл карты внутри папки тоже был переименован.

Затем, создайте следующие файлы в папке карты:

script.go (любое имя с *.go будет работать):

package <mapname>
	
func init() {
	println("hello!")
}

go.mod:

module <mapname>

go 1.22

К примеру, оригинальная карта:

maps/
  estate/
    estate.map
    estate.nxz

И скопированная, включая новые файлы:

maps/
  example/
    example.map
    example.nxz
    script.go
    go.mod

В файле script.go:

package example

func init() {
	println("hello!")
}

В файле go.mod:

module example

go 1.22

Готово! Теперь запустите карту в OpenNox, откройте консоль и вы должны увидеть там сообщение hello!.

Информация

Вам не нужно устанавливать Go или какой-либо другой компилятор чтобы писать скрипты для OpenNox.

Тем не менее, правильная настройка Go поможет включить поддержку IDE, проверку типов в скриптах, автодополнение и т.д. По этому, мы крайне советуем это сделать.

Полная настройка

Для полной настройки нам понадобиться:

  1. Go 1.20+ (для проверки типов, работы с зависимостями)
  2. Git (для Windows)
  3. GoPls (для интеграции с VSCode)
  4. VSCode (сама IDE)
  5. Расширение Go для VSCode (включает документацию для gopls)

Когда все установлено, мы можем создать новый проект. Для это нужно:

  1. Скопировать существующую карту или создать новую через редактор карт.
  2. Открыть папку карты через VSCode.
  3. Открыть терминал (Terminal -> New Terminal в верхнем меню VSCode).
  4. go mod init <mapname> (например go mod init example). Это создаст готовый go.mod.
  5. Создать новый Go файл, например script.go с package <mapname> (например package example).
  6. Добавить какой-либо код в этот файл, например func init() { println("hello!") }.
  7. Сохранить все файлы, запустить OpenNox и проверить карту.

Скриптовые движки

Существует несколько доступных версий скриптовых движков (полный список здесь), к примеру:

Скриптовые движки работают следующим образом: обычно один из движков явлется остновным (NS4 в данном случае), который предоставляет весь функционал доступный в OpenNox. Остальные движки являются лишь слоем поверх него. Тем не менее эти слои важны! Они предоставляют уже знакомый интерфейс для разработчиков карт (например NS3 или EUD).

Благодаря этому, полность безопастно использовать несколько движков в одной карте. Если есть опыт в NS3 - лучше начать с него. Если вы только начинаете разбираться с Nox скриптами - выбирайте последний NS движек (NS4).

Ссылки выше ссылаются на документацию языка Go для каждого из движков - это основной источник документации
по функциям и классам доступным в каждом из движков. Это руководство даст лишь базовое знание про настройку скриптов.

Использование движков

Тогда, как использовать эти движки?

Если вы пропустили полную настройку, то для это нужно лишь добавить import в Go файл и использовать его:

package example

import (
    "fmt"
    
    "github.com/noxworld-dev/noxscript/ns/v4"
)

func OnFrame() {
	fmt.Println("players:", len(ns.Players()))
}

Несколько моментов которые стоит отметить:

  • Мы подключили стандартный пакет Go fmt используемы для вывода в консоль. Вы можете свободно использовать и другие стандартные Go пакеты.
  • Мы подключили NS через github.com/.../ns/v4, но мы ссылаемся на него как ns.* (например в ns.Players). Суффикс v4 является версией пакета.
  • Функция OnFrame будет вызываться OpenNox каждый кадр (или “тик сервера”). Так что мы должны увидеть множество сообщений в консоли!

Это все что нужно знать чтобы использовать один из движков. Но что если мы хотим использовать и NS3 и NS4, к примеру?

Подключение обоих пакетов не сработает - ведь у них одинаковое имя. Так что мы присвоим псевдоним для каждой версии:

package example

import (
    "fmt"
    
    ns3 "github.com/noxworld-dev/noxscript/ns/v3"
    ns4 "github.com/noxworld-dev/noxscript/ns/v4"
)

func OnFrame() {
	fmt.Println("players:", len(ns4.Players()))
	fmt.Println("talking:", ns3.IsTalking())
}

Если вы привыкли к NoxScript 3 и не хотите указывать ns. или ns3. повсюду, можно так же указать псевдоним как точку:

package example

import (
    "fmt"
    
    . "github.com/noxworld-dev/noxscript/ns/v3"
    ns4 "github.com/noxworld-dev/noxscript/ns/v4"
)

func OnFrame() {
	fmt.Println("players:", len(ns4.Players()))
	fmt.Println("talking:", IsTalking())
}

Можно заметить что мы вызываем IsTalking без префикса ns3. Это, тем не менее, не типично для Go, т.к. из кода не понятно объявлена ли функция IsTalking в карте или в другом пакете.

Теперь, возвращаясь к полной настройке IDE, вы могли заметить что импорты не были опознаны. Это происходит потому что нам нужно обновить зависимости проекта в go.mod. Мы можем сделать это двумя способами:

  • go mod tidy в терминале (требует Git).
  • Либо навести мышку на нераспознанное имя импорта, выбрать Quick fix..., и далее go get ....

В обоих случаях зависимости должны загрузиться (то есть тот NS движек который вы выбрали) и добавиться в go.mod.

Теперь автодополнение должно работать корректно для пакетов движка.

Обновление движков

Скриптовые движки периодически обновляются в OpenNox чтобы добавить новые возможности или исправить ошибки.

Это делаться автоматически, новый релиз OpenNox подключит новый движек без каких либо действий со стороны разработчика карт.

Тем не менее, IDE не будет распознавать новые функции движка до тех пор пока они не обновяться в проекте карты.

Самый простой способ обновить это открыть файл go.mod в папке карты и найти строку с движком который нужно обновить:

require (
    github.com/noxworld-dev/noxscript/ns/v4 v4.3.0
    // ... other lines
)

Просто обновите версию в нем, и запустите go mod tidy. Полный список версий доступен при нажатии на версию в документации пакета скриптов а так же на GitHub.

Пакеты

Теперь мы знаем как подключить движки скриптов и запускать скрипты. Как же лучше структурировать код?

В Go, единичным проектом является “пакет” (package): директория с одним или несколькими Go файлами. Имена самих Go файлов не имеют значения, единственное требование это то что все файлы в директории должны иметь одинаковую строку package в начале файла. OpenNox так же добавляет ещё одно ограничение: package должен совпадать с именем карты.

В остальном, организация кода полностью зависит от вас. Все функции и переменные обхявленные в одном файле доступны во всех других файлах в этой директории.

Как я могу …

Это руководство лишь поверхностно, в паре шагов показывает как работать со скриптами.

Если вы уже знакомы с оригинальным NoxScript 3, стоит просмотреть руководство по миграции для NS3.

Возможно вам так же интересно поближе познакомиться с языком Go. Язык очень простой, по этому это не должно составить труда. Интерактивный Go тур является хорошим местом чтобы начать.

Некоторые из вопросов могут быть уже покрыты в Q&A. Так же доступны примеры.

Если вопросы не нашли ответа, можно задать их здесь или в нашем Discord.

Примеры

На этой странице приведен список примеров скриптов для OpenNox.

НазваниеДвижекКомментарии
КомпанияNS3Скрипты компании переведеныне в NS3
Ephreaym/Nox-AI-scriptNS4Боты для Arena и CTF от @Ephreaym
mogushanNS4Пример боя с боссом от @dennwc и Garett
NoxWorldNS4Карты и скрипты для NoxWorld: Сервер Nox с открытым миром

NoxScript 4

Reference

Here you can find a full list of functions provided by NS4 runtime.

NS4 runtime

This is the current script runtime in OpenNox based on Go programming language.

See quickstart for a tour, or see NS3 for conversion from vanilla scripts and some history.

Подразделы NoxScript 4

Миграция с NS3

NS4 provides the same functionality as NS3, but uses object-oriented approach. It also supports a few unique features which are not available in NS3.

Changes

Objects

The ns3.ObjectID is replaced with ns4.Obj type. The main difference is that ns4.Obj is opaque and can no longer be used or stored as an integer.

It is possible to convert ns4.Obj to/from ns3.ObjectID using the following code:

ns4.AsObj(obj)
ns3.ObjectID(obj.ObjScriptID())

Similar functions are available for ns4.ObjGroup and ns3.ObjectGroupID:

ns4.AsObjGroup(group)
ns3.ObjectGroupID(group.ObjGroupScriptID())

Most object-specific functions are now available on the object itself, instead of a top-level library function:

obj.Enable(false)
obj.Delete()
ns3.ObjectOff(obj)
ns3.Delete(obj)

Object position is now available as a point type, instead of separate X and Y coordinates:

pos := obj.Pos()
x, y := pos.X, pos.Y
x, y := ns3.GetObjectX(obj), ns3.GetObjectY(obj)

Most functions can now accept this new position type instead of a coordinate pair:

pos := obj.Pos()
obj2.HitMelee(pos)
x, y := ns3.GetObjectX(obj), ns3.GetObjectY(obj)
ns3.HitLocation(obj2, x, y)

Position can also be constructed from X and Y values:

obj.HitMelee(ns4.Ptf(10, 20))
ns3.HitLocation(obj, 10, 20)

Waypoints

Similar to objects, waypoints are also represented with opaque ns4.WaypointObj type.

Conversion to/from ns3.WaypointID is still available:

ns4.AsWaypoint(wp)
ns3.WaypointID(wp.WaypointScriptID())

Waypoints now also have methods instead of top-level library functions:

wp.Enable(false)
ns3.WaypointOff(wp)

Position is also returned as a point data type:

pos := wp.Pos()
x, y := pos.X, pos.Y
x, y := ns3.GetWaypointX(obj), ns3.GetWaypointY(obj)

This, in turn, allows using any type that has Pos() method (also known as ns4.Positioner) in places where position is expected:

ns4.CreateObject("Beholder", ns4.Ptf(10, 20))
ns4.CreateObject("Beholder", ns4.GetHost())
ns4.CreateObject("Beholder", ns4.Waypoint("Spot"))
ns3.CreateObject("Beholder", ns3.Waypoint("Spot"))

NoxScript 3

Reference

Here you can find a full list of functions provided by NS3 runtime.

History

Vanilla Nox has its own script runtime based on compiled source files. Since original Nox editor was never released, community recreated the script compiler from scratch.

Since there’s no official version, the scripts had different dialects, one of the latest is known as NoxScript 3.

There’s also a Panic’s EUD compiler that uses memory manipulation to extend script functionality.

OpenNox supports vanilla scripts with no changes required. Additionally, it implements a more advanced script runtime.

New runtime

To make the transition to the new script runtime smoother, OpenNox provides a compatibility layer for NoxScript 3.

The idea is that all the functions from NoxScript 3 should work exactly the same, accept same arguments, etc. This way all existing functions can be copied with almost no changes (only syntax will vary).

To avoid confusion, we usually refer to vanilla scripts as “NoxScript 3”, while the new compatibility layer is called NS3.

If you have existing scripts you want to migrate, see our migration guide.

Otherwise, it’s better to start directly from the NS4, which is our current script version.

Подразделы NoxScript 3

Миграция с оригинала

Это руководство поможет перенести существующие NoxScript 3 карты на NS3 в OpenNox.

В этом руководстве мы будем называть оригинальные скрипты Nox как “NoxScript 3”, в то время как “NS3” будет обозначать новые Go скипты для OpenNox.

Зачем?

Первый логичный вопрос: зачем? OpenNox хорошо работает с NoxScript 3 скриптами.

Есть пара причин перейти на скрипты OpenNox:

  • NoxScript 3 ограничен ровно тем что оригинальный Nox движек открывает. Возможностей не много. И никаких обновлений не будет.
  • NS3 в OpenNox является прямой заменой. Абсолютно те же функции доступны в нем.
  • Мы предоставляем инструмены для перевода 90% кода скрипта автоматически. Только мелкие правки необходимы.
  • NS4 (и далее) будут иметь всё больше и больше возможностей в будущем, включая поддержку модов.
  • Не нужен отдельный компилятор скриптов. Скрипты запускаются напрямую из кода.
  • Более полная система типов: настоящие массивы, словари (map), стркутуры, классы.
  • Доступны библиотеки: работа со строками, полная поддержка UTF8, математика, сортировка, и т.д.
  • Лучшая производительность: все библиотеки скомпилированы в OpenNox и запускаются нативно.
  • Лучшая отладка: если скрипт “падает”, выведется трасировка. Скрипты так же могут самостоятельно справиться с ошибкой!
  • Язык Go используемый в скриптах так же используется в самом OpenNox. Возможно однажды будет желание присоединиться?

Было бы несправедливо не упоминуть про недостатки:

  • Скрипты работают только в OpenNox.
  • Нужно изучить новый язык для скриптов.
  • Скриптам возможно необходимо делать больше для правильного сохранения/загрузки.

Если вы знакомы с EUD компилятором от Panic и возможно рассматривали его, см это руководство.

In general, we believe that OpenNox is the future of Nox modding, thus porting your map may give it an entirely new life!

How?

There are two path currently: converting the compiled script from the map or converting the source.

Converting the map script

You’ll need a recent noxtools installed (assuming you have Go 1.20+ installed):

go install github.com/noxworld-dev/opennox-lib/cmd/noxtools@latest

From the map directory:

noxscript ns decomp <mapname>.map

It will print a decompiled source code converted to Go and NS3 runtime.

Because of the limitation of Nox script assembly:

  • All variable names will be lost.
  • Some control flow may be replaced with goto.

But after fixing these issues, you should be ready to go!

Converting the source

TODO: Add a guide for using cxgo to automate it.

Currently, you’ll have to manually convert the source. Until we automate it as well, please consider converting the extracted map script, as shown above.

NoxScript 3 is similar to C, which has a lot in common with Go. However, Go syntax is slightly different in regard to types.

Conversion steps will include:

  • Swapping argument and variable names with types: int a -> a int.
  • Adding either var or const to variable definitions: int a -> var a int.
  • Moving function return type to the end: int foo() -> func foo() int.
  • Moving { to the previous line. E.g. func foo()\n{ -> func foo() {. Same for if, else, for.
  • Adding { ... } to if and else which do not have them: if (1) foo() -> if (1) { foo() }.
  • Removing void from returns.
  • Fixing variable types (Go doesn’t allow implicit type conversion).

After this, add the following header to your file:

package example

import (    
    . "github.com/noxworld-dev/noxscript/ns/v3"
)

Dot import should automatically resolve all references to NS3 functions.

After conversion

Limitations

There are some temporary limitations you should be aware of:

  • Timers will stop each time the map is reloaded. You’ll need to restart them from the script.
  • All callbacks will reset when map is reloaded. You’ll need to set them again from the script.

These issues will be resolved eventually.

New: Syntax

We highly recommend checking our Go tour to get familiar with the syntax, but we’ll give a short recap here.

File structure

All files must start with package <mapname>:

package example

It can be followed by one or more package imports:

import "fmt"
import "strconv"
// it is typical to group them:
import (
	"fmt"
	"strconv"
)

Then global variables and/or functions follow. Order of declarations doesn’t matter.

Variables and types

Most notable syntax distinction: in Go, the type name is on the right side, instead of on the left as in NoxScript 3:

var x int
int x;

Note that ; is no longer needed, and variable declaration must start with var (or const).

There’s a very good reason why types are on the right: it makes reading complex types more natural. Just read them left to right!

For example, array: var x [3][2]int simply reads left to right as “array of 3 elements, each containing 2 int values”. Much better than a random order of int x[2][3];.

Same for pointers: *[2]int reads “pointer to an array of 2 ints”. Compare it to int* x[2];.

Functions

Function declarations are also different:

  • They must start with func.
  • Types for arguments are on the right.
  • Return type is after the arguments.
  • Void return type must be omitted.
  • The opening { must be on the same line as the function header.
  • Arguments with the same types can be grouped.
  • Multiple returns are supported.
func foo(a int) {
}

func bar(x, y int, s string) int {
}
void foo(int a)
{
}

int bar(int x, int y, string s)
{
}

Control flow

All control flow structures require the opening { to be on the same line, for example:

if (x) { foo() }

if (y) {
    bar()
}
if (x) foo();

if (y)
{
    bar();
}

The () in the condition is also optional:

if x { foo() }

if y {
    bar()
}
if (x) foo();

if (y)
{
    bar();
}

Same rules for { apply for else:

if x {
    foo()
} else {
    bar()
}
if (x) foo()
else bar()

Loops

Loops must not include ( and have same rules in regard to {:

var i int
for i = 0; i < 10; i++ {
}
int i;
for (i = 0; i < 10; i++)
{
}

Loop that use while must use for keyword:

for x {
}
while (x)
{
}

New: Core types

In original NoxScript 3, there were only a few types available: int, float, string, object.

In NS3 the list is much longer: bool, int, uint, float32 (analog of float), string, any, etc. The object type is replaced with more specific types from NS3 package: ObjectID, ObjectGroupID, WaypointID, etc.

An important distinction is that Go doesn’t allow implicit type conversion. For example, in NoxScript it was okay to have an int variable and put an object there. In NS3, this is requires an explicit type conversion: int(x). But, of course, it’s better to have correct types for your variables.

Another distinction of NS3 is the support of direct conversions between int and float. It is done the same way: int(x) or float32(x).

Converting between int and string is supported via IntToString, but it’s better to use Go’s standard library instead: strconv.Itoa.

It also supports conversion from string to int via Go’s standard library: strconv.Atoi. Note, that this function may return an error, which you are free to ignore (with _):

x, _ := strconv.Atoi("1")

New: Strings

NoxScript 3 had a limitation that a frequent + operation on strings overflows a string table.

There’s no such limitation in NS3: any number of strings can be created.

Printing to strings is also supported with Go’s fmt.Sprintf:

s := fmt.Sprintf("Hello player %d!", n)

There are quite a few more string functions available in strings, https://pkg.go.dev/strconv and unicode packages.

Even though strings can be created with + and individual bytes can be accessed with s[i], strings are immutable in Go! This means, once created, they cannot be edited, only new ones can be created. If you need to change a few characters, consider converting to byte array, making changes, and converting back:

s := "Gello"
b := []byte(s) // type: []byte
b[0] = 'H'
s = string(b) // "Hello"

New: Variable type inference

NoxScript 3 requires a type for new variables to be set explicitly. NS3 allows automatic inference of variable type:

a := 10 // int
b := false // bool
x := ns.Object("Bob") // ObjectID
int a = 10; // int
int b = 0; // bool 
int x = Object("Bob"); // object

The := operator does two things: defines a new variable (similar to var) and infers a type for it.

But note that using float values produces a float64 type, not float32:

x := 0.0 // float64!
y := float32(0.0) // float32
x = y // error!

However:

const x = 0.0 // untyped float
var y float32 = x // no error

Constants are “untyped” and infer the type automatically from a variable they assigned to.

New: Range loop

In NS3 a new type of loop is available: for range, which allows to loop over all values in an array.

var arr [3]int
// writing: loop over indexes only
for i := range arr {
    arr[i] = i+1;
}
cnt := 0
// reading: loop over values
for _, v := range arr {
    cnt += v
}
int i;
int arr[3];
int cnt = 0;
for (i = 0; i < 3; i++) // writing
{
    arr[i] = i+1;
}
for (i = 0; i < 3; i++) // reading
{
    cnt += arr[i];
}

New: Dynamic arrays (slices)

In NoxScript 3, only fixed arrays are supported. NS3 has support for Go slices, which are arrays with dynamic length:

var arr []int
for i := 0; i < 3; i++ {
    arr = append(arr, i+1) // adds elements to the end
}
// len(arr) == 3
int i;
int arr[3];
for (i = 0; i < 3; i++)
{
    arr[i] = i+1;
}

New: Structures

NS3 completely supports custom struct types. They are very similar to classes in other programming languages.

Let’s say we want to build an RPG map, and we want to record a new character class for all player units:

type MyUnit struct {
	ID ns.ObjectID // types on the right: field "ID" with type "ns.ObjectID"
	Class string
}

func init() {
    unit := ns.Object("Bob")
    // creates a new struct instance, takes pointer to it
    myUnit := &MyUnit{ID: unit, Class:"archer"}
    changeClass(myUnit, "shaman")
}

// changeClass accepts a pointer to struct be able to change fields.
// Removing the pointer will make a copy of the struct for this function!
func changeClass(unit *MyUnit, cl string) {
    unit.Class = cl
}

The changeClass function can also be rewritten as a method on MyUnit struct:

type MyUnit struct {
	ID ns.ObjectID // types on the right: field "ID" with type "ns.ObjectID"
	Class string
}

// changeClass is a method on MyUnit struct pointer.
// Removing the pointer will make a copy of the struct for this function!
func (u *MyUnit) changeClass(cl string) {
    u.Class = cl
}

func init() {
    unit := ns.Object("Bob")
    myUnit := &MyUnit{ID: unit, Class:"archer"}
	// now changeClass is available as a method on the struct instance
    myUnit.changeClass("shaman")
}

For developer coming from C, new structs always have their fields initialized to zero vales.

New: Dictionaries (maps)

NS3 support dictionaries/sets, which are unordered collections of values indexed by a key of any type.

For example, we made a MyUnit struct in the previous example. But how to quickly find MyUnit for ns.ObjectID?

type MyUnit struct {
	ID ns.ObjectID // types on the right: field "ID" with type "ns.ObjectID"
	Class string
}

// mapUnits maps ns.ObjectID to *MyUnit.
// All maps must be created with make before use!
var mapUnits = make(map[ns.ObjectID]*MyUnit)

func init() {
	createMyUnits()
	findAndChangeClass()
}

func createMyUnits() {
    unit := ns.Object("Bob")
    myUnit := &MyUnit{ID: unit, Class:"archer"}
    // add new record to the map, index by ID
    mapUnits[unit] = myUnit
}

func findAndChangeClass() {
    unit := ns.Object("Bob")
	// find by ID
	myUnit := mapUnits[unit]
	if unit == nil {
	    return // not found	
    }
	myUnit.Class = "shaman"
}

Keys can also be deleted from the map:

delete(mapUnits, unit) // delete by unit ID

EUD от Panic'а

History

Vanilla Nox has its own script runtime based on compiled source files. Since original Nox editor was never released, community recreated the script compiler from scratch.

Since there’s no official version, the scripts had different dialects, one of the latest is known as NoxScript 3.

However, the script runtime of Nox was very limited. Eventually the community found a way to inject custom code into the game, which lead to a new kind of map scripts, usually referred as “memhacks”.

Panic’s EUD is the most advanced project of this kind. It uses memory manipulation to implement a lot of new functionality for the scripts.

Unfortunately, memory manipulation usually targets a single binary version (vanilla Nox), and thus cannot run on other versions such as OpenNox. Because of this OpenNox does not support EUD scripts.

New runtime

Even though OpenNox cannot support scripts that use memory manipulation, we still can provide similar functions in out own script runtime. Thus, OpenNox provides a compatibility layer for EUD scripts.

The idea is that all the functions from Panic’s EUD which do not expose the memory directly should work exactly the same, in OpenNox This way all existing functions can be copied with almost no changes (only syntax will vary).

If you have existing scripts you want to migrate, see our migration guide.

Otherwise, it’s better to start directly from the NS4, which is our current script version.

Подразделы EUD от Panic'а

Миграция с EUD

This guide will help migrate existing Panic’s EUD maps to NS3 and EUD layer in OpenNox.

First, it’s important to understand that “memhacks” and direct memory access is technically not possible in OpenNox.

Here are a few reasons why:

  • Memhacks target a specific binary. This means it only works on one Nox version. OpenNox constantly evolves, thus we cannot guarantee any specific memory layout.
  • Memhacks usually inject assembly code that targets a specific CPU architecture (Intel/AMD x86). OpenNox can be potentially compiled for ARM (e.g. MacBooks, Android, RPi), thus script will stop working there.

We attempted to resolve these issues with EUD developer Panic, but we don’t see any willingness for collaboration from his side. If you really want EUD to be supported directly in OpenNox, please reach out to Panic. Resolving these technical challenges is possible, but requires tight collaboration, and will to do so from him, first and foremost.

Why?

First logical question: why bother with converting to OpenNox? EUD works great in original Nox.

A few reasons to migrate to OpenNox scripts:

  • OpenNox is evolving and supports new features that are impossible in vanilla (e.g. HD, better multiplayer, modding, etc).
  • EUD library in OpenNox is a drop-in replacement. Same functions will be supported.
  • NS4 (and beyond) will have even more features going forward.
  • You won’t need a separate script compiler. Scripts are run directly from source.
  • More comprehensive type system: proper arrays, dictionaries (map), structures, classes.
  • A lot more libraries included: string manipulation, full UTF8 support, math, sorting, etc.
  • Better performance: all libraries are compiled into OpenNox and run natively.
  • Better debugging: if script crashes, there’s a stack trace. Scripts can recover from it as well!
  • Go language used in scripts is used in OpenNox itself. Maybe one day you’ll decide to contribute?

In general, we believe that OpenNox is the future of Nox modding, thus porting your map may give it an entirely new life!

How?

At this point, we are still working on improving the EUD compatibility layer, so quite a few functions might still be unavailable. Please talk to us for more details.

In general the conversion process is very similar to the one for converting NS3 source manually. Same changes must be done to the source to align the syntax. We are working on a more automated process.

You need to be aware that all functions using GetMemory and SetMemory must be rewritten in any case. The first thing to do is to check if functions you are using are already available in Panic’s EUD library. If so, updating your EUD script to using these function will help you convert to our EUD library later as well.

We aim to provide a good migration path for well-known EUD libraries, so if you copied code from another EUD project, there’s a high chance we support it in one of the libraries.

Still, if you cannot find anything similar, talk to us. We will help convert your code and include necessary functionality into next OpenNox release.

After conversion

The NS3 guide applies here as well, so make sure to check it out!