212 lines
5.1 KiB
Plaintext
212 lines
5.1 KiB
Plaintext
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;
|
|
|
|
//lifetime functions
|
|
fn onInit(node: opaque) {
|
|
//init the rng with a seed (random)
|
|
if (rng != null) {
|
|
rng.freeRandomGenerator();
|
|
}
|
|
rng = createRandomGenerator(clock().hash());
|
|
|
|
|
|
//generate the level, filling out the entity data
|
|
node.generateLevel(rng);
|
|
|
|
//generate the child node to render the map
|
|
var renderer: opaque = node.loadChild("scripts:/tilemap/renderer.toy");
|
|
renderer.callNodeFn("setTilemap", tilemap);
|
|
|
|
//load the music
|
|
loadMusic("music:/Music_Skylands_placeholder.ogg");
|
|
playMusic();
|
|
}
|
|
|
|
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) {
|
|
//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.loadChild("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.loadChild("scripts:/entities/drone.toy");
|
|
drone.callNodeFn("setGridPosition", room["x"] + x, room["y"] + y);
|
|
|
|
//increment here
|
|
i++;
|
|
}
|
|
}
|
|
|
|
|
|
//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);
|
|
}
|
|
}
|
|
|
|
|
|
//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;
|
|
}
|
|
|
|
|
|
//polyfills
|
|
fn loadChild(parent: opaque, fname: string) {
|
|
//TODO: add this to the API proper
|
|
var child: opaque = loadNode(fname);
|
|
parent.pushNode(child);
|
|
return child;
|
|
} |