Files
Airport/assets/scripts/gameplay/scene.toy
2023-06-16 04:11:03 +10:00

146 lines
3.3 KiB
Plaintext

import standard;
import node;
import random;
//consts
var TILE_WIDTH: int const = 32;
var TILE_HEIGHT: int const = 32;
var MAP_WIDTH: int const = 16;
var MAP_HEIGHT: int const = 16;
var CAMERA_X: int const = 0;
var CAMERA_Y: int const = 32;
var tilemap: opaque = null;
var player: opaque = null;
var stepCounter: opaque = null;
var enemies: [opaque] = [];
var collisionMap: [bool] = null; //cache this, since it won't change during a level
var rng: opaque = null;
//lifecycle functions
fn onLoad(node: opaque) {
var empty = node.loadChild("scripts:/empty.toy");
tilemap = empty.loadChild("scripts:/gameplay/tilemap.toy");
stepCounter = empty.loadChild("scripts:/gameplay/step-counter.toy");
player = node.loadChild("scripts:/gameplay/lejana.toy");
}
fn onInit(node: opaque) {
node.generateLevel(clock().hash(), MAP_WIDTH, MAP_HEIGHT);
stepCounter.callNodeFn("setMaxSteps", 100);
}
fn onFree(node: opaque) {
rng.freeRandomGenerator();
}
//fn onStep(node: opaque) {
// //
//}
fn onDraw(node: opaque) {
node.sortChildrenNode(depthComparator);
stepCounter.callNodeFn("customOnDraw", 0, 0, TILE_WIDTH * MAP_WIDTH, 32);
}
//utils - polyfills
fn loadChild(parent: opaque, fname: string) {
var child: opaque = loadNode(fname);
parent.pushNode(child);
return child;
}
//gameplay functions
fn generateLevel(node: opaque, seed: int, width: int, height: int) {
//reset the array
enemies = [];
if (rng != null) rng.freeRandomGenerator();
rng = createRandomGenerator(seed);
//place player
player.callNodeFn("setGridPos", 1, 1);
//generate map
tilemap.callNodeFn("generateFromRng", rng, 16, 16);
collisionMap = tilemap.callNodeFn("getCollisionMap");
//generate drones
var droneCount: int const = rng.generateRandomNumber() % 2 + 20;
for (var i = 0; i < droneCount; i++) {
var d = node.loadChild("scripts:/gameplay/drone.toy");
d.initNode();
enemies.push(d);
var x = 0;
var y = 0;
//while generated spot is a collision, or too close to the player
while (x == 0 && y == 0 || node.getCollisionAt(x, y) == false || x < width / 6 * 2 && y < height / 6 * 2) {
x = rng.generateRandomNumber() % width;
y = rng.generateRandomNumber() % height;
}
d.callNodeFn("setGridPos", x, y);
d.callNodeFn("setRealPos", (width -1) * TILE_WIDTH, (height - 1) * TILE_HEIGHT);
}
}
fn getCollisionAt(node: opaque, x: int, y: int) {
if (collisionMap == null || x == null || y == null) {
return false;
}
//entities
var pos = player.callNodeFn("getGridPos");
if (x == pos[0] && y == pos[1]) {
return false;
}
for (var i = 0; i < enemies.length(); i++) {
var pos = enemies[i].callNodeFn("getGridPos");
if (x == pos[0] && y == pos[1]) {
return false;
}
}
//default
return collisionMap[y * MAP_WIDTH + x];
}
fn runAI(node: opaque) {
for (var i = 0; i < enemies.length(); i++) {
enemies[i].callNodeFn("runAI", rng);
}
stepCounter.callNodeFn("alterRemainingSteps", -1);
}
fn depthComparator(lhs: opaque, rhs: opaque) { //for sorting by depth
var lhsPos = lhs.callNodeFn("getRealPos");
var rhsPos = rhs.callNodeFn("getRealPos");
if (lhsPos == null || rhsPos == null) { //BUGFIX: children without that function
return true;
}
if (lhsPos[1] == rhsPos[1]) { //BUGFIX: prevent z-fighting
return lhsPos[0] <= rhsPos[0];
}
return lhsPos[1] < rhsPos[1];
}
fn getCameraPos(node: opaque) {
return [CAMERA_X, CAMERA_Y];
}