import standard; import node; //constants var SPEED: int const = 4; var SPRITE_WIDTH: int const = 64; var SPRITE_HEIGHT: int const = 64; var TILE_WIDTH: int const = 32; var TILE_HEIGHT: int const = 32; //variables var parent: opaque = null; //cache the parent for quick access var gridX: int = 1; //position on the game grid var gridY: int = 1; var realX: int = null; //will change until realX = gridX * SPRITE_WIDTH var realY: int = null; var motionX: int = 0; //normalized movement direction var motionY: int = 0; var inputX: int = 0; //cache the keyboard input var inputY: int = 0; var direction: int = null; //BUGFIX: animation not looping properly var enableMovementCounter: int = 30 * 3; //BUGFIX: freeze while drones reach their starting spot var attackCounter: int = 0; //polyfills - animating different cycles on one image var stepCount: int = 0; fn faceDown(node: opaque) { if (direction == 0) return; direction = 0; node.setNodeRect(0, 0, 32, 32); node.setNodeFrames(4); } fn faceUp(node: opaque) { if (direction == 1) return; direction = 1; node.setNodeRect(32 * 4, 0, 32, 32); node.setNodeFrames(4); } fn faceRight(node: opaque) { if (direction == 2) return; direction = 2; node.setNodeRect(32 * 8, 0, 32, 32); node.setNodeFrames(4); } fn faceLeft(node: opaque) { if (direction == 3) return; direction = 3; node.setNodeRect(32 * 12, 0, 32, 32); node.setNodeFrames(4); } //accessors & mutators fn setGridPos(node: opaque, x: int, y: int) { gridX = x; gridY = y; if (realX == null) { realX = gridX * TILE_WIDTH; } if (realY == null) { realY = gridY * TILE_HEIGHT; } } fn setRealPos(node: opaque, x: int, y: int) { realX = x; realY = y; } fn getGridPos(node: opaque) { return [gridX, gridY]; } fn getRealPos(node: opaque) { return [realX, realY]; } //lifecycle functions fn onLoad(node: opaque) { node.loadNodeTexture("sprites:/lejana.png"); node.faceDown(); } fn onInit(node: opaque) { parent = node.getParentNode(); } fn onStep(node: opaque) { //initial freeze if (enableMovementCounter > 0) { enableMovementCounter--; return; } //process input when aligned to a grid if (realX / TILE_WIDTH == gridX && realY / TILE_HEIGHT == gridY && motionX == 0 && motionY == 0) { //facing if (inputY > 0) { node.faceDown(); } if (inputY < 0) { node.faceUp(); } if (inputX > 0) { node.faceRight(); } if (inputX < 0) { node.faceLeft(); } //disallow wall phasing if (inputX != 0 && parent.callNodeFn("getCollisionAt", gridX + inputX, gridY) != true) { inputX = 0; } if (inputY != 0 && parent.callNodeFn("getCollisionAt", gridX, gridY + inputY) != true) { inputY = 0; } //disallow diagonal movement if (abs(inputX) != 0) { gridX += inputX; } else { gridY += inputY; } //trigger the world if (inputX != 0 || inputY != 0) { parent.callNodeFn("runAI"); } } //actually animate if (++stepCount >= 5) { if (motionX == 0 && motionY == 0 && inputX == 0 && inputY == 0) { stepCount = 0; } if (attackCounter > 0) { attackCounter--; } node.incrementCurrentNodeFrame(); } //animation - standing still if (attackCounter == 0 && stepCount == 0) { //move to standing state if (node.getNodeRectY() != 0) { node.setNodeRect(direction * 32 * 4, 0, 32, 32); node.setNodeFrames(4); } } //animation - attacking if (attackCounter > 0 && stepCount == 0) { //move to attacking state if (node.getNodeRectY() != 32) { node.setNodeRect(direction * 32 * 4, 32, 32, 32); node.setNodeFrames(3); stepCount = 0; } } //calc movement var distX = gridX * TILE_WIDTH - realX; var distY = gridY * TILE_HEIGHT - realY; motionX = normalize(distX); motionY = normalize(distY); //make movement realX += abs(distX) > SPEED ? SPEED * motionX : distX; realY += abs(distY) > SPEED ? SPEED * motionY : distY; } fn onFree(node: opaque) { node.freeNodeTexture(); } fn onDraw(node: opaque) { var camera = parent.callNodeFn("getCameraPos"); node.drawNode(realX + camera[0] - SPRITE_WIDTH / 4, realY + camera[1] - SPRITE_HEIGHT / 2, SPRITE_WIDTH, SPRITE_HEIGHT); } //event functions fn onKeyDown(node: opaque, event: string) { //initial freeze if (enableMovementCounter > 0) { return; } if (event == "character_attack" && inputX == 0 && inputY == 0) { attackCounter = 3; return; } if (event == "character_up") { inputY -= 1; return; } if (event == "character_down") { inputY += 1; return; } if (event == "character_left") { inputX -= 1; return; } if (event == "character_right") { inputX += 1; return; } } fn onKeyUp(node: opaque, event: string) { if (event == "character_up" && inputY < 0) { inputY = 0; return; } if (event == "character_down" && inputY > 0) { inputY = 0; return; } if (event == "character_left" && inputX < 0) { inputX = 0; return; } if (event == "character_right" && inputX > 0) { inputX = 0; return; } } //polyfills - move these to standard fn normalize(x): int { if (x > 0) { return 1; } if (x < 0) { return -1; } return 0; }