Skip to content

08. Moving pawn, Splitting script

phu54321 edited this page Feb 10, 2018 · 4 revisions

Table of Contents generated with DocToc

The material used in this chapter can be downloaded at here.

In this chapter, we will really move a pawn. Really. Also, we will split main.eps into multiple files to make our script easier to manage.

Moving a pawn

First we create a removePiece function, a counterpart of placePiece function.

function removePiece(x, y) {
    move1x1Loc(x, y);
    RemoveUnitAt(All, '(men)', '1x1', AllPlayers);
    setTile(x, y, 0);
}

Next we change the afterTriggerExec function. If the piece is selected and the selected piece is Scourge, then we move the previously selected pawn to the selected position.

var beforeUnitPlayer, beforeUnitType;
var beforeUnitX, beforeUnitY = -1, -1;

function afterTriggerExec() {
    const unitType, selX, selY = sel.getSelectedUnit();
    if (unitType != -1) {
        if(unitType == $U('Zerg Scourge')) {
            piece.removePiece(selX, selY);
            piece.placePiece(selX, selY, beforeUnitType, beforeUnitPlayer);
            piece.removePiece(beforeUnitX, beforeUnitY);
            RemoveUnit("Zerg Scourge", Force3);

            beforeUnitX = -1;
            beforeUnitY = -1;
        }
        else if(beforeUnitX != selX || beforeUnitY != selY) {
            const tileVal = tile.tile(selX, selY);
            beforeUnitPlayer = tileVal / 1000;
            beforeUnitType = tileVal % 1000;
            beforeUnitX = selX;
            beforeUnitY = selY;
            RemoveUnit("Zerg Scourge", Force3);
            pawn.getPossiblePawnDestination(beforeUnitPlayer, selX, selY);
        }
    }
    else {
        RemoveUnit("Zerg Scourge", Force3);
    }
    SetInvincibility(Enable, "(any unit)", AllPlayers, 'Anywhere');
}

When a Scourge is selected, selX and selY holds the position of the Scourge, so we need some way to know what piece was selected before the Scourge was selected. To do that we update beforeUnitX, beforeUnitY, beforeUnitPlayer, beforeUnitType for each piece selection, and use that info when the Scourge is selected.

Also, since it takes some time for unit selection pointer to update after we really select the unit, we shouldn't remove and re-create Scourge again and again while we're selecting a Scourge. To prevent Scourge from re-created every frame, we check beforeUnitX != selX && beforeUnitY != selY to make sure that the scourge gets updated only when a different piece gets selected.

Okay. Until this code, the gameplay looks like this.

Gameplay

Splitting a source file.

main.eps now became 171 lines. This is quite big, so we will split main.eps into multiple eps file.

If you're a map creator, you would probably have created a map with thousands of conditions and actions. Your small map's trigger may have spanned ten thousand of lines in text trigger. From a programmer's perspective, anything over 200 lines is big, and we always try to split our code to a manageable size. We always try to separate unrelated scripts from different functions and different files. In that way, we can make our projects more manageable.

We will split 'main.eps' into the following files.

  • loc.eps : Moving 1x1 location.
  • tile.eps : In-memory board goes to here.
  • selection.eps : Selection detection.
  • piece.eps : Placing/removing piece from the board.
  • folder 'pieceRule' : Each piece type's moving rule.
    • pawn.eps : Pawn's moving rule.
  • main.eps : This file only contains onPluginInit and afterTriggerExec.

Split files should reference functions from each other. To do that we use import. For example, piece.eps uses setTile in tile.eps like this.

import loc;
import tile;

function placePiece(x, y, unitType, player) {
    loc.move1x1Loc(x, y);
    CreateUnit(1, unitType, '1x1', player);
    tile.setTile(x, y, unitType + player * 1000);
}

function removePiece(x, y) {
    loc.move1x1Loc(x, y);
    RemoveUnitAt(All, '(men)', '1x1', AllPlayers);
    tile.setTile(x, y, 0);
}
  • import tile; means that 'piece.eps' will use function, variables, and constants from tile.eps.
  • piecePlace function can use function from tile.eps with tile.[function to use], like tile.setTile(x, y, unitType + player * 1000);.

Also, the eps file can be structured into folders. To use functions inside a folder, one should include folder name in the import statement. Like import pieceRule.pawn; in main.eps. pieceRule.pawn means 'pawn.eps inside pieceRule folder'. Likewise, import tile; in 'pieceRule/pawn.eps' means that 'pieceRule/pawn.eps' will use functions inside 'tile.eps'.

If you are coming from C, then you probably have found this similar to #include of C. #include uses a relative path to reference other files, but in epScript, we use an absolute path from the root 'main.eps' file to each eps file. So even 'pieceRule/pawn.eps' imports 'tile.eps' like import tile;, not import "../tile.eps";. Beware of that difference.

'main.eps' is our root script because that's what we've included in 'main.edd'.

See the completed material for more info. You can download the material here.

What we have done so far

Let's take a break and see what we have done so far. We have implemented a selection detection. We have a pawn's moving rule. This is chapter 8. We've learned a lot of things about euddraft function systems. Now we have to do this thing again for more piece types. Our course had been quite slow because we had to cover the very basics of euddraft.

We have enough basics covered until here, we still have many things to learn throughout this course, but I think we can speed things up a bit. In the next chapter, we will implement a knight and bishop's move.

Thanks for watching this course. See you soon.

Fixes

  • 2018-01-08: else if(beforeUnitX != selX && beforeUnitY != selY) {else if(beforeUnitX != selX || beforeUnitY != selY) {.