mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
360 lines
12 KiB
JavaScript
360 lines
12 KiB
JavaScript
//
|
|
// towerDefense.js
|
|
//
|
|
// Created by Clement on 12/1/16.
|
|
// Copyright 2016 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
print("============= Script Starting =============");
|
|
|
|
function findSurfaceBelowPosition(pos) {
|
|
var result = Entities.findRayIntersection({
|
|
origin: pos,
|
|
direction: { x: 0, y: -1, z: 0 }
|
|
});
|
|
if (result.intersects) {
|
|
return result.intersection;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
var GAME_STATES = {
|
|
IDLE: 0,
|
|
BUILD: 1,
|
|
FIGHT: 2,
|
|
GAMEOVER: 3,
|
|
};
|
|
|
|
var BASE_POSITION = findSurfaceBelowPosition(MyAvatar.position);
|
|
var BUILD_TIME_SECONDS = 60;
|
|
var BUTTON_POSITION = { x: 0, y: 0, z: 0 };
|
|
var BASES_SIZE = 15;
|
|
var TARGET_SIZE = 2;
|
|
var BASES_HEIGHT = 6;
|
|
var BASES_TRANSPARENCY = 0.2;
|
|
var BASES = [
|
|
{
|
|
position: { x: -15, y: 0, z: 0 },
|
|
color: { red: 255, green: 0, blue: 0 },
|
|
spawnerPosition: { x: -15 + BASES_SIZE/2, y: 0, z: -BASES_SIZE/2 },
|
|
},
|
|
{
|
|
position: { x: 15, y: 0, z: 0 },
|
|
color: { red: 0, green: 255, blue: 0 },
|
|
spawnerPosition: { x: 15 - BASES_SIZE/2, y: 0, z: BASES_SIZE/2 },
|
|
},
|
|
{
|
|
position: { x: 0, y: 0, z: -15 },
|
|
color: { red: 0, green: 0, blue: 255 },
|
|
spawnerPosition: { x: BASES_SIZE/2, y: 0, z: -15 + BASES_SIZE/2 },
|
|
},
|
|
{
|
|
position: { x: 0, y: 0, z: 15 },
|
|
color: { red: 255, green: 0, blue: 255 },
|
|
spawnerPosition: { x: -BASES_SIZE/2, y: 0, z: 15 - BASES_SIZE/2 },
|
|
},
|
|
];
|
|
|
|
|
|
var CHANNEL_NAME = "tower-defense-" //+ Math.floor(Math.random() * 9999);
|
|
print(CHANNEL_NAME);
|
|
|
|
var QUERY_RADIUS = 200;
|
|
|
|
var buttonID;
|
|
var bases = [];
|
|
var entityIDs = [];
|
|
var spawnerIDs = [];
|
|
|
|
var teamEntities = {
|
|
0: {},
|
|
1: {},
|
|
2: {},
|
|
3: {},
|
|
};
|
|
|
|
var currentState = GAME_STATES.IDLE;
|
|
|
|
Messages.subscribe(CHANNEL_NAME);
|
|
|
|
if (this.EntityViewer) {
|
|
EntityViewer.setPosition(Vec3.sum(BASE_POSITION, BUTTON_POSITION));
|
|
EntityViewer.setCenterRadius(QUERY_RADIUS);
|
|
}
|
|
|
|
var BEGIN_BUILDING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/letTheGamesBegin.wav"));
|
|
var BEGIN_FIGHTING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/fight.wav"));
|
|
var GAME_OVER_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/gameOver.wav"));
|
|
var TEN_SECONDS_REMAINING_SOUND = SoundCache.getSound(Script.resolvePath("assets/sounds/tenSecondsRemaining.wav"));
|
|
|
|
setup();
|
|
|
|
|
|
function setup() {
|
|
var buttonProperties = {
|
|
type: 'Box',
|
|
name: 'TD.StartButton',
|
|
position: Vec3.sum(BASE_POSITION, BUTTON_POSITION),
|
|
dimensions: { x: 1, y: 1, z: 1 },
|
|
color: { red: 0, green: 255, blue: 0 },
|
|
script: Script.resolvePath("towerButton.js"),
|
|
userData: JSON.stringify({
|
|
grabbableKey: {
|
|
wantsTrigger: true
|
|
},
|
|
gameChannel: CHANNEL_NAME
|
|
}),
|
|
}
|
|
buttonID = Entities.addEntity(buttonProperties);
|
|
|
|
for (var i in BASES) {
|
|
var position = Vec3.sum(BASE_POSITION, BASES[i].position);
|
|
var arenaProperties = {
|
|
name: 'TD.Arena',
|
|
type: 'Box',
|
|
position: position,
|
|
registrationPoint: { x: 0.5, y: 0, z: 0.5 },
|
|
dimensions: { x: BASES_SIZE, y: BASES_HEIGHT, z: BASES_SIZE },
|
|
color: { red: 255, green: 255, blue: 255 },
|
|
script: Script.resolvePath("teamAreaEntity.js"),
|
|
visible: false,
|
|
collisionless: true,
|
|
userData: JSON.stringify({
|
|
gameChannel: CHANNEL_NAME,
|
|
})
|
|
};
|
|
// Base block
|
|
var arenaID = Entities.addEntity(arenaProperties)
|
|
bases.push(arenaID);
|
|
teamEntities[i].arenaID = arenaID;
|
|
|
|
|
|
const ROOF_HEIGHT = 0.2;
|
|
position.y += BASES_HEIGHT - ROOF_HEIGHT;
|
|
var roofProperties = {
|
|
name: 'TD.Roof',
|
|
type: 'Box',
|
|
position: position,
|
|
registrationPoint: { x: 0.5, y: 0, z: 0.5 },
|
|
dimensions: { x: BASES_SIZE, y: ROOF_HEIGHT, z: BASES_SIZE },
|
|
color: BASES[i].color,
|
|
script: Script.resolvePath('roofEntity.js'),
|
|
userData: JSON.stringify({
|
|
gameChannel: CHANNEL_NAME,
|
|
})
|
|
}
|
|
// Player area
|
|
var roofID = Entities.addEntity(roofProperties)
|
|
bases.push(roofID);
|
|
teamEntities[i].roofID = roofID;
|
|
}
|
|
}
|
|
|
|
function cleanup() {
|
|
for (var i = 0; i < 4; ++i) {
|
|
var t = teamEntities[i];
|
|
Entities.deleteEntity(t.targetID);
|
|
Entities.deleteEntity(t.spawnerID);
|
|
if (t.bowIDs !== undefined) {
|
|
for (var j = 0; j < t.bowIDs.length; ++j) {
|
|
Entities.deleteEntity(t.bowIDs[j]);
|
|
}
|
|
}
|
|
Entities.deleteEntity(t.roofID);
|
|
Entities.deleteEntity(t.arenaID);
|
|
}
|
|
while (bases.length > 0) {
|
|
Entities.deleteEntity(bases.pop());
|
|
}
|
|
Entities.deleteEntity(buttonID);
|
|
print("Size of entityIDs:", entityIDs.length);
|
|
for (var i = 0; i < entityIDs.length; ++i) {
|
|
print("Deleting: ", entityIDs[i]);
|
|
Entities.deleteEntity(entityIDs[i]);
|
|
}
|
|
entityIDs = [];
|
|
for (var i = 0; i < spawnerIDs.length; ++i) {
|
|
Entities.deleteEntity(spawnerIDs[i]);
|
|
}
|
|
spawnerIDs = [];
|
|
|
|
print("============= Script Stopping =============");
|
|
Script.stop();
|
|
}
|
|
|
|
function parseJSON(json) {
|
|
try {
|
|
return JSON.parse(json);
|
|
} catch (e) {
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
Messages.messageReceived.connect(function(channel, messageJSON, senderID) {
|
|
print("Recieved: " + messageJSON + " from " + senderID);
|
|
if (channel === CHANNEL_NAME) {
|
|
var message = parseJSON(messageJSON);
|
|
if (message === undefined) {
|
|
print("towerDefense.js | Received non-json message");
|
|
return;
|
|
}
|
|
switch (message.type) {
|
|
case 'start-game':
|
|
if (currentState != GAME_STATES.IDLE) {
|
|
print("Got start message, but not in idle state. Current state: " + currentState);
|
|
return;
|
|
}
|
|
|
|
Entities.deleteEntity(buttonID);
|
|
|
|
for (var i in BASES) {
|
|
var position = Vec3.sum(BASE_POSITION, BASES[i].position);
|
|
|
|
// Create target entity
|
|
var targetID = Entities.addEntity({
|
|
name: 'TD.TargetEntity',
|
|
type: 'Sphere',
|
|
position: position,
|
|
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
|
color: BASES[i].color,
|
|
script: Script.resolvePath("targetEntity.js"),
|
|
userData: JSON.stringify({
|
|
gameChannel: CHANNEL_NAME,
|
|
teamNumber: i
|
|
}),
|
|
});
|
|
entityIDs.push(targetID);
|
|
teamEntities[i].targetID = targetID;
|
|
|
|
// Create box spawner
|
|
var spawnerID = Entities.addEntity({
|
|
name: 'TD.BoxSpawner',
|
|
type: 'Box',
|
|
position: Vec3.sum(BASE_POSITION, BASES[i].spawnerPosition),
|
|
dimensions: { x: TARGET_SIZE, y: TARGET_SIZE, z: TARGET_SIZE },
|
|
color: BASES[i].color,
|
|
script: Script.resolvePath("launchEntity.js"),
|
|
userData: JSON.stringify({
|
|
grabbableKey: {
|
|
wantsTrigger: true
|
|
},
|
|
gameChannel: CHANNEL_NAME,
|
|
})
|
|
});
|
|
teamEntities[i].spawnerID = targetID;
|
|
spawnerIDs.push(spawnerID);
|
|
Audio.playSound(BEGIN_BUILDING_SOUND, {
|
|
volume: 1.0,
|
|
position: BASE_POSITION
|
|
});
|
|
}
|
|
|
|
currentState = GAME_STATES.BUILD;
|
|
|
|
Script.setTimeout(function() {
|
|
Audio.playSound(TEN_SECONDS_REMAINING_SOUND, {
|
|
volume: 1.0,
|
|
position: BASE_POSITION
|
|
});
|
|
}, (BUILD_TIME_SECONDS - 10) * 1000);
|
|
Script.setTimeout(function() {
|
|
print("============ Done building, FIGHT =============");
|
|
|
|
Audio.playSound(BEGIN_FIGHTING_SOUND, {
|
|
volume: 1.0,
|
|
position: BASE_POSITION
|
|
});
|
|
|
|
Messages.sendMessage(CHANNEL_NAME, "FIGHT");
|
|
|
|
|
|
// Cleanup spawner cubes
|
|
currentState = GAME_STATES.FIGHT;
|
|
for (var i = 0; i < spawnerIDs.length; ++i) {
|
|
Entities.deleteEntity(spawnerIDs[i]);
|
|
}
|
|
|
|
// Spawn bows
|
|
for (var i = 0; i < BASES.length; ++i) {
|
|
var position = Vec3.sum(BASE_POSITION, BASES[i].position);
|
|
position.y += BASES_HEIGHT + 1;
|
|
teamEntities[i].bowIDs = [];
|
|
|
|
for (var j = 0; j < 4; ++j) {
|
|
teamEntities[i].bowIDs.push(Entities.addEntity({
|
|
position: position,
|
|
"collisionsWillMove": 1,
|
|
"compoundShapeURL": Script.resolvePath("bow/bow_collision_hull.obj"),
|
|
"created": "2016-09-01T23:57:55Z",
|
|
"dimensions": {
|
|
"x": 0.039999999105930328,
|
|
"y": 1.2999999523162842,
|
|
"z": 0.20000000298023224
|
|
},
|
|
"dynamic": 1,
|
|
"gravity": {
|
|
"x": 0,
|
|
"y": -1,
|
|
"z": 0
|
|
},
|
|
"modelURL": Script.resolvePath("bow/bow-deadly.fbx"),
|
|
"name": "TD.Hifi-Bow",
|
|
"rotation": {
|
|
"w": 0.9718012809753418,
|
|
"x": 0.15440607070922852,
|
|
"y": -0.10469216108322144,
|
|
"z": -0.14418250322341919
|
|
},
|
|
"script": Script.resolvePath("bow/bow.js"),
|
|
"shapeType": "compound",
|
|
"type": "Model",
|
|
"userData": "{\"grabbableKey\":{\"grabbable\":true},\"wearable\":{\"joints\":{\"RightHand\":[{\"x\":0.0813,\"y\":0.0452,\"z\":0.0095},{\"x\":-0.3946,\"y\":-0.6604,\"z\":0.4748,\"w\":-0.4275}],\"LeftHand\":[{\"x\":-0.0881,\"y\":0.0259,\"z\":0.0159},{\"x\":0.4427,\"y\":-0.6519,\"z\":0.4592,\"w\":0.4099}]}}}"
|
|
}));
|
|
}
|
|
}
|
|
|
|
}, BUILD_TIME_SECONDS * 1000);
|
|
break;
|
|
case 'target-hit':
|
|
print("Got target-hit for: ", message.teamNumber);
|
|
if (currentState !== GAME_STATES.FIGHT) {
|
|
return;
|
|
}
|
|
print("game is over");
|
|
Audio.playSound(GAME_OVER_SOUND, {
|
|
volume: 1.0,
|
|
position: BASE_POSITION
|
|
});
|
|
currentState = GAME_STATES.GAME_OVER;
|
|
|
|
// Delete the entities for the team that lost
|
|
var t = teamEntities[message.teamNumber];
|
|
Entities.deleteEntity(t.targetID);
|
|
Entities.deleteEntity(t.spawnerID);
|
|
Entities.deleteEntity(t.roofID);
|
|
Entities.deleteEntity(t.arenaID);
|
|
|
|
// TODO If more than 1 team is still alive, don't cleanup
|
|
// Do a full cleanup after 10 seconds
|
|
Script.setTimeout(function() {
|
|
cleanup();
|
|
currentState = GAME_STATES.IDLE;
|
|
}, 10 * 1000);
|
|
break;
|
|
default:
|
|
print("towerDefense.js | Ignoring unknown message type: ", message.type);
|
|
break;
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
// Script.update.connect(function() {
|
|
// EntityViewer.queryOctree();
|
|
// });
|
|
|
|
Script.scriptEnding.connect(cleanup);
|
|
|