import standard; import random; import runner; import node; import music; //persistent members of the scene node var rng: opaque = null; //map data var tilemap: [int] = null; var metadata: [[[string: any]]] = null; var mapGridWidth: int = null; var mapGridHeight: int = null; //entities var player: opaque = null; var renderer: opaque = null; //lifetime functions fn onLoad(node: opaque) { //init the rng with a seed (random) if (rng != null) { rng.freeRandomGenerator(); } rng = createRandomGenerator(clock().hash()); //generate the child node to render the map renderer = node.loadChildNode("scripts:/tilemap/renderer.toy"); //load the music loadMusic("music:/Music_Skylands_placeholder.ogg"); playMusic(); } fn onInit(node: opaque) { //generate the level, filling out the entity data node.generateLevel(rng); //update the visible area from the player's perspective updateVisible(); } fn onStep(node: opaque) { for (var i: int = 0; i < node.getChildNodeCount(); i++) { var child = node.getChildNode(i); if (child != null) { if (child.callNodeFn("isRequestingFree") == true) { node.freeChildNode(i); } } } node.sortChildrenNode(depthComparator); } fn onFree(node: opaque) { if (rng != null) { rng.freeRandomGenerator(); } freeMusic(); } //debugging fn onKeyDown(node: opaque, event: string) { //test the music if (event == "music_toggle") { if (checkMusicPaused() == false) { pauseMusic(); } else { unpauseMusic(); } } if (event == "music_up") { setMusicVolume(getMusicVolume() + 16); } if (event == "music_down") { setMusicVolume(getMusicVolume() - 16); } } //scene loading fn generateLevel(node: opaque, rng: opaque) { print clock() + " - begin generating level"; //load and run the generator script var generatorScript: opaque = loadScript("scripts:/tilemap/generator.toy"); generatorScript.runScript(); //call the functions generatorScript.callScriptFn("generateTilemapData", rng); //get the resulting blobs of data for processing tilemap = generatorScript.getScriptVar("tilemap"); metadata = generatorScript.getScriptVar("metadata"); mapGridWidth = generatorScript.getScriptVar("MAP_GRID_WIDTH"); //cache these for lookups mapGridHeight = generatorScript.getScriptVar("MAP_GRID_HEIGHT"); //free the generator generatorScript.freeScript(); //spawn && position the player player = node.loadChildNode("scripts:/entities/player.toy"); var w: int const = metadata.length(); var h: int const = metadata[0].length(); var room = metadata[rng.generateRandomNumber() % w][rng.generateRandomNumber() % h]; player.callNodeFn("setGridPosition", room["doorX"], room["doorY"]); //spawn && position the enemies for (var i: int = 0; i < 20; /* EMPTY */) { //get random position within a room random room var room = metadata[rng.generateRandomNumber() % w][rng.generateRandomNumber() % h]; var x = rng.generateRandomNumber() % room["w"]; var y = rng.generateRandomNumber() % room["h"]; if (!node.getWalkableAt(room["x"] + x, room["y"] + y)) { continue; } var drone: opaque = node.loadChildNode("scripts:/entities/drone.toy"); drone.callNodeFn("setGridPosition", room["x"] + x, room["y"] + y); //increment here i++; } print clock() + " - end generating level"; } //to allow the game to progress fn runAI(node: opaque) { //player attacking the drones var attackPositionX: int = player.callNodeFn("getAttackPositionX"); var attackPositionY: int = player.callNodeFn("getAttackPositionY"); //if the player is attacking... if (attackPositionX != null && attackPositionY != null) { //for each child node for (var i = 0; i < node.getChildNodeCount(); i++) { var child = node.getChildNode(i); //find the target if (child.callNodeFn("getGridPositionX") == attackPositionX && child.callNodeFn("getGridPositionY") == attackPositionY) { child.callNodeFn("applyDamage", 1); //just 1 damage for now } } } //run normal routines for (var i: int = 0; i < node.getChildNodeCount(); i++) { node.getChildNode(i).callNodeFn("runAI", rng); } } //update the visible portions of the map fn updateVisible() { var playerX: int = player.callNodeFn("getGridPositionX"); var playerY: int = player.callNodeFn("getGridPositionY"); renderer.callNodeFn("updateVisble", playerX, playerY, tilemap); } //for collisions fn getWalkableAt(node: opaque, x: int, y: int) { if (tilemap == null || x == null || y == null) { return false; } //entities if (x == player.callNodeFn("getGridPositionX") && y == player.callNodeFn("getGridPositionY")) { return false; } for (var i = 0; i < node.getChildNodeCount(); i++) { var child = node.getChildNode(i); if (x == child.callNodeFn("getGridPositionX") && y == child.callNodeFn("getGridPositionY")) { return false; } } //default return tilemap[y * mapGridWidth * 3 + x * 3 + 2] == 1; // 1 = walkable } //for sorting by depth fn depthComparator(lhs: opaque, rhs: opaque) { var lhsPositionY = lhs.getNodeWorldPositionY(); var rhsPositionY = rhs.getNodeWorldPositionY(); if (lhsPositionY == null || rhsPositionY == null) { //BUGFIX: children without that function return true; } if (lhsPositionY == rhsPositionY) { //BUGFIX: prevent z-fighting var lhsPositionX = lhs.getNodeWorldPositionX(); var rhsPositionX = rhs.getNodeWorldPositionX(); return lhsPositionX < rhsPositionX; } return lhsPositionY < rhsPositionY; }