Skip to content

epScript Basics

armoha edited this page May 6, 2022 · 4 revisions

Translation of https://cafe.naver.com/edac/book5103106/83509
Original author: trgk

[1] What is epScript?

abbreviation of eudplib Script -> epScript.
epScript allows you to write more readable code than Python code originally written in eudplib.

1. No concept of Trigger, only condition and action exist.

Variable comparison like a == b is same as Deaths condition.
Also treats as same function for dwread_epd function call and SetMemory action.

So you can code like this.

/**
 * Regenerate player, if player has sufficient life
 */
function regeneratePlayer(player: TrgPlayer) {
    // Regenerate player
    if(!Command(player, AtLeast, 1, "Avoider")
       && Accumulate(player, AtLeast, 1, Ore)) {
        createPlayer(player);
        SetCurrentPlayer(player);
        DisplayText("\x05  Retry...");
    }
}

(source: https://github.com/phu54321/bwpack/blob/master/src/player/lifesys.eps#L23-L35 )

You can mix action like DisplayText, and eudplib function like createPlayer.
You can put conditions in if statements without thinking and apply logical operations such as !(not), &&(and) ||(or).

You can code mindlessly and epScript will do everything for you.

2. Much simple syntax

In eudplib, you code using bizarre syntax like if EUDIf()(condition): EndIf().
In epScript, you just code it like usual programming language, like if (condition) {}.

Just var for variable declaration. No need for EUDVariable().

/**
 * Sort array
 * @param  {[type]} arr_ [description]
 * @param  {[type]} n    [description]
 * @return {[type]}      [description]
 */
function sortArray(arr_, n) {
    const arr = EUDArray(arr_);
    var t;
    for(var i = 0 ; i < n ; i++) {
        for(var j = 1 ; j < n ; j++) {
            if(arr[j - 1] > arr[j]) {
                t, arr[j], arr[j - 1] = arr[j], arr[j - 1], t;
            }
        }
    }
}

You can just implement bubble sort like this.
t, arr[j], arr[j - 1] ~ part is just swapping variables.

All variables like var t; are EUDVariable, and you need const for arrays and structs.

3. Easy to use Python items in eudplib, such as EUDArray

You can code like const arr = EUDArray(arr_); or code as follows:

const bgmContent = py_open('src/bgm22050.wav', 'rb').read();
function bgmloop() {
    MPQAddWave('staredit\\wav\\bgmmain.wav', bgmContent);
    if(isTimerHit()) {
        startTimer(54857);
        SetCurrentPlayer(getuserplayerid());
        PlayWAV('staredit\\wav\\bgmmain.wav');
    }
}

(source: https://github.com/phu54321/bwpack/blob/master/src/bgmplayer.eps )

You can open background music file with py_open, which is Python open function for opening file.
MPQAddWave adds this music file into mpq.

[2] Basic syntax of epScript

  1. File extension of all epScript files are .eps Just like .py files, you can deliberately load .eps files too.
    import a -> You can import a.eps in Python code too
    cf) Don't be confused with .eds euddraft config file.
  2. Most of syntaxes are adpoted from JavaScript.

(1) Function declaration

function [functionName] (argument1, argument2, ... , argumentn) {
    (functionContent)
    return x, y, z, 123;  // You can return multiple values from function
}

(2) if statement

    if ( ~ ) {
        ~
    } else if (~) {
        ~
    } else {
        ~
    }

(3) for loop

    for (var i = 0 ; i < 5 ; i++) {
        ~
    }

(4) foreach

    foreach(ptr, epd : EUDLoopUnit()) {
        ~
    }
  • cf) Same as following Python code:
        for ptr, epd in EUDLoopUnit():
           ~

(5) Variable

    var i = 0; i = 123;  // Assign a vlaue to variable. Same as `i << 123` in eudplib.
    var p1, p2 = 1, 2;  // initialize p1, p2 to 1, 2
    var w0, w1, b0, b1, b2, b3 = dwbreak(0x12345678);
    var w0, w1 = dwbreak(0x12345678)[[0, 1]];  // extract only 1st and 2nd results from `f_dwbreak`

    var x = dwbreak(0x12345678)[[0]];  // extract only 1st result of `f_dwbreak` (Don't write `[0]`)
    a, b, c = b, c, a  // syntactic sugar for `a = b; b = c; c = a;` Three substitution takes place in order.
    // **** This does not substitute original values of `a, b, c` respectively.

(6) Constant (const)

    const i = 0;  i = 1;  // Error - you can't substitue value for const again.
    // You can use `const` to use data type like EUDArray, other than EUDVariable.
    var arr_;
    const arr = EUDArray.cast(arr_);  // When `arr_` is address, `arr` represents `EUDArray` pointing the address.

(7) StarCraft constants

    $P1 // player id for Player1 (0)
    $Force1 // player id for Force1
    $Ore $Gas  // resource kind for Accumulate/SetResources

cf) $Kills - score kind Kills, not related to condition Kills.

(8) Scenario related constants

    $U("Terran Marine")  // unit id of Terran Marine (0)
    $L("Anywhere")  // location id of Anywhere - 64
    $S("Switch 1")  // switch id of Switch 1 (0)
    $T("Untitled scenario")  // map string id

(9) Condition

    Bring(~)  // Trigger condition Bring
    a == 1  // is variable `a` equal to 1?
    Bring(~) && a == 1  // satisfy both conditions at the same time
    Bring(~) || Command(~)  // satisfy at least one of conditions
    !Bring(~)  // if Bring is false

(10) import (Same as Python import)

import a;  // load module `a` (either `a.py` or `a.eps`)
import aa.bb;  // import module `aa.bb` under name `bb`
import a as t;  // import module `a` under name `t`

[3] Example code

import player.playerProc as pProc;
import bulletBase as bBase;

/**
 * Unit loop is very, very expensive. Condense all unit-related logic to here
 */
function mainUnitLoop() {
    // Kill clipped bullets
    KillUnitAt(All, '(any unit)', 'uclip', Force2);
    KillUnitAt(All, '(any unit)', 'lclip', Force2);
    KillUnitAt(All, '(any unit)', 'dclip', Force2);
    KillUnitAt(All, '(any unit)', 'rclip', Force2);
    foreach(ptr, epd : EUDLoopUnit2()) {
        const player = bread_epd(epd + (0x4C / 4), 0);
        if(player <= $P6) {
            // Player process
            const unitType = dwread_epd(epd + (0x64 / 4));
            if(unitType == $U("Avoider")) {
                pProc.processPlayerCUnit(player, ptr, epd);
                continue;
            }
        }
        else {
            const orderID = bread_epd(epd + (0x4C / 4), 1);
            // If halted -> kill it
            if(orderID == 156 || orderID == 160 || orderID == 2 || orderID == 3) {
                bwrite_epd(epd + (0x4C / 4), 1, 0);
            }
        }
    }
}

(source: https://github.com/phu54321/bwpack/blob/master/src/unitloop.eps )

You can code like this on unitloop.eps.
You can use this code on other eps/Python codes with import unitloop;.

  • In .eps file, call mainUnitLoop().
  • In .py file, call f_mainUnitLoop().

[4]

You can make euddraft plugin with .eps too.