"+(cycle.chatting?"*":" ")+replaceColors(cycle.getColoredName())+" | "+replaceColors(cycle.alive?"0x00ff00Yes":"0xff0000No")+" | "+cycle.score+" | "+cycle.ping+" | "+(cycle.team?cycle.team.name:"")+" | ";
}
playersSB.innerHTML = tmp;
}
-/*function updateScoreBoard()
-{
- var scoreboard = "";
- for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined")
- {
- var cycle = engine.players[x];
- scoreboard += (cycle.chatting?"*":" ")+removeColors(cycle.name)+" "+cycle.alive?"Yes":"No"+" "+cycle.score+" "+cycle.ping+" ";
- }
-}*/
+}(typeof(exports) === 'undefined' ? this.game = {} : exports));
diff --git a/scripts/init.js b/scripts/init.js
index 968e7d7..d08a13d 100644
--- a/scripts/init.js
+++ b/scripts/init.js
@@ -1,126 +1,136 @@
/*
* 3DCycles - A lightcycle game.
* Copyright (C) 2019 Glen Harpring
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+if(typeof(global) == undefined)
+ global = window;
+
//resize window listener function
var resizeWindow = function()
{
if(engine.renderer)
{
engine.renderer.setSize(window.innerWidth,window.innerHeight);
engine.renderer.render(engine.scene, engine.camera);
}
if(engine.camera)
{
engine.camera.aspect = window.innerWidth / window.innerHeight;
engine.camera.updateProjectionMatrix();
}
};
-function init()
+global.init = function()
{
- //set renderer after detecting available renderer
- if (Detector.webgl) { engine.renderer = new THREE.WebGLRenderer({ antialias: true });}
- else { engine.renderer = new THREE.SoftwareRenderer(); engine.usingWebgl = false; }
- engine.renderer.setSize(window.innerWidth, window.innerHeight);
- document.body.appendChild(engine.renderer.domElement);
+ //let's load settings first.
+ loadsettingcfgs();
+ window.onbeforeunload = saveusercfg;
+ if(!engine.dedicated)
+ {
+ //set renderer after detecting available renderer
+ if (Detector.webgl) { engine.renderer = new THREE.WebGLRenderer({ antialias: settings.ANTIALIAS });}
+ else { engine.renderer = new THREE.SoftwareRenderer(); engine.usingWebgl = false; }
+ engine.renderer.setSize(window.innerWidth, window.innerHeight);
+ document.body.appendChild(engine.renderer.domElement);
+ }
engine.scene = new THREE.Scene();
+ if(engine.dedicated) return;
loadTextures();
window.addEventListener('touchstart',touchControl);
window.addEventListener('resize',resizeWindow);
}
function gameLostTab()
{
if(engine.inputState == 'game') { pauseMenuToggle(); console.log("PAUSED because the tab lost focus"); }
}
function gameLostFocus()
{
- if(engine.inputState == 'game') { engine.players[engine.activePlayer].chatting = true; updateScoreBoard() }
+ if(engine.inputState == 'game') { engine.players[engine.activePlayer].chatting = true; game.updateScoreBoard() }
}
function gameGainedFocus()
{
- if(engine.inputState == 'game') { engine.players[engine.activePlayer].chatting = false; updateScoreBoard() }
+ if(engine.inputState == 'game') { engine.players[engine.activePlayer].chatting = false; game.updateScoreBoard() }
}
window.onblur = gameLostFocus;
window.onfocus = gameGainedFocus;
window.onload = function()
{
if(!engine.scene) init();
httpGetAsync("layout/menu.xml",function(output){
engine.menu = xmlify(output); menu('menu:main'); aamenurender();
if(typeof(_GET["ssl"]) != "undefined")
{
chsetting("CONNECT_SSL",_GET["ssl"]);
}
if(typeof(_GET["preset"]) != "undefined")
{
menu('menu:preset_loaded');menu('menu:preset_loaded');
menu('menu:loading');
preset(_GET["preset"]);
}
else if(typeof(_GET["connect"]) != "undefined")
{
var s = _GET["connect"].split(":");
settings.CONNECT_HOST = ""+s[0];
if(s.length > 1) settings.CONNECT_PORT = s[1];
connectToGame();
}
});
//keyboard input
window.addEventListener('keydown', keyboardKeyDown );
window.addEventListener('keyup', keyboardKeyUp );
(function() {//event listener cross browser support for auto-pause when focus lost
'use strict';
// Set the name of the "hidden" property and the change event for visibility
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") {
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") { // Firefox up to v17
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") { // Chrome up to v32, Android up to v4.4, Blackberry up to v10
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
var handleVisibilityChange = function() { if(document[hidden]) gameLostTab() };
// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
alert("AUTO-PAUSE UNAVAILABLE");
} else {
// Handle page visibility change
document.addEventListener(visibilityChange, handleVisibilityChange, false);
}
})();
}
diff --git a/scripts/input.js b/scripts/input.js
index 52e9efd..1a543b2 100644
--- a/scripts/input.js
+++ b/scripts/input.js
@@ -1,501 +1,501 @@
/*
* 3DCycles - A lightcycle game.
* Copyright (C) 2019 Glen Harpring
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
function stopPropagation(e)
{
e = e || event;/* get IE event ( not passed ) */
e.stopPropagation? e.stopPropagation() : e.cancelBubble = true;
e.returnValue = false;
}
//EVENT INPUTS
var keyboardKeyDown = function(e)
{
e = e || event;//safety (against what?)
//get state here, like: playing, menu, chatting, etc.
//refer to engine.inputState: menu | menu2 | game | chat | pause
//for each input state, either switch(keyCode) {}, or send keycode to appropriate function
var keyCode = typeof(keyCodeRemap[e.keyCode]) == "undefined"?e.keyCode:keyCodeRemap[e.keyCode];
var specificState = engine.inputState.split(':');
if(specificState[0] != "input" && settings.controls.console.indexOf(keyCode) > -1) //console key works everywhere except other inputs
{
var input = document.getElementById("input");
input.style.display = "block";
engine.inputStatePrev = engine.inputState;
engine.inputState = "input:console";
if(engine.players[engine.activePlayer]) engine.players[engine.activePlayer].chatting = true;
- updateScoreBoard();
+ game.updateScoreBoard();
input.children[0].innerText = "Con:";
input.children[1].focus();
stopPropagation(e);
}
else if(specificState[0] == 'menu'/* || engine.paused*/) //any menu, not game
{
var actmenu = document.getElementsByClassName("menu-active")[0];
if(!actmenu)
{
if(engine.menus.length == 1) menu("menu:"+engine.menus[engine.menus.length-1]);
else if(engine.menus.length > 1) menu("exitmenu");
else menu("menu:main");
return;
}
if(actmenu.attributes.id)
actid = actmenu.attributes.id.value;
else
actid = "";
var actsp = actid.split(":");
/*if(actsp[0] != "var" && (actsp[2] != "str" || actsp[2] == "color"))
stopPropagation(e);*/
//console.log(actid.split(":"));
switch(keyCode)
{
case 13: //enter
//menuSelect('enter',"key");
break;
case 27: //esc
stopPropagation(e);
menuSelect('esc',"key");
break;
case 37: //left
menuSelect('left',"key");
break;
case 38: //up
menuSelect('up',"key");
break;
case 39: //right
menuSelect('right',"key");
break;
case 40: //down
menuSelect('down',"key");
break;
}
}
else if(specificState[0] == 'input')
{
switch(keyCode)
{
case 9: //tab
var input = document.getElementById("input");
var textbox = input.children[1];
var output = textbox.value;
var split = output.split(" ");
if(specificState[1] == "console")
{
}
else switch(split[0])
{
case "/console":
split[split.length-1]
break;
default:
var p = getPlayer(split[split.length-1]);
if(p)
{
//textbox.value += p.getColoredName();
split[split.length-1] = p.getColoredName()+"0xffff7f";
if(split.length == 1) split[split.length-1] += ", ";
else split[split.length-1] += " ";
textbox.value = split.join(" ");
}
else
{
engine.console.print("Matches:\n");
for(var i=engine.players.length;i--;)
{
if(engine.players[i].name.toLowerCase().indexOf(name.toLowerCase()) > -1)
{
engine.console.print(engine.players[i].name+"\n");
}
}
}
break;
}
stopPropagation(e);
break;
case 27: case 13: //escape or return
var input = document.getElementById("input");
var textbox = input.children[1];
var output = textbox.value; textbox.value = "";
input.style.display = "none";
if(engine.players[engine.activePlayer]) engine.players[engine.activePlayer].chatting = false;
engine.inputState = engine.inputStatePrev;
- updateScoreBoard();
+ game.updateScoreBoard();
if(keyCode == 13) //return
{
switch(specificState[1])
{
case "chat":
handleChat(engine.players[engine.activePlayer],output);
break;
case "console":
engine.console.print("0x7f7fff> "+output+"\n");
loadcfg(output);
break;
}
//engine.inputState = engine.inputStatePrev;
}
break;
}
}
else if(engine.inputState == 'game') //game settings.controls
{
gameControl(keyCode);//send keycode to control function
//if(engine.inputState.split(':')[0] == "input" || keyCode == 9)
stopPropagation(e);
}
else //parse input state (typically settings to add/remove controls)
{
if(specificState[0] == 'controlAR')
{
stopPropagation(e);
if(!e.forceHACK && e.keyCode == 27)
{
engine.inputState = "menu:"+engine.menus[engine.menus.length-1]; menu("reload");
return;
}
var temp_items = Object.keys(settings.controls);
var temp_item = temp_items.indexOf(specificState[1]) || 0;
if(settings.controls[specificState[1]].indexOf(keyCode) > -1) //control is there already
{
settings.controls[specificState[1]].splice(settings.controls[specificState[1]].indexOf(keyCode), 1); //remove
}
else
{
for(var i=0;i -1)
{
settings.controls[control].splice(settings.controls[control].indexOf(keyCode),1); //remove control found
}
}
}
settings.controls[specificState[1]].push(keyCode); //add control to chosen option
settings.controls[specificState[1]].sort(function(a,b){return a-b});//sort listing in order
}
engine.inputState = "menu:"+engine.menus[engine.menus.length-1]; menu("reload");
//menu('menu-controls_'+temp_item);
}
}
}
var keyboardKeyUp = function(e)
{
if(engine.inputState == 'game')//game settings.controls
{
gameControlUp(typeof(keyCodeRemap[e.keyCode]) == "undefined"?e.keyCode:keyCodeRemap[e.keyCode]);
}
}
//GAME
function touchControl(e)
{
if(!document.oncontextmenu)
document.oncontextmenu = function(){return false}
if(engine.inputState == 'game')
{
//console.log(e);
var sepX = document.body.offsetWidth/3, sepY = document.body.offsetHeight/2;
if(engine.gtime > 0)
{
/*engine.console.print(e.touches.length+" touches");
for(var x=e.touches.length-1;x>=0;x--)*/
var x = 0; //other touch appears to get sent in another message anyway
{
//var dir = (e.touches[x].clientX < half)?-1:1;
if(e.touches[x].clientX > sepX*2)
{
var dir = 1;
}
else if(e.touches[x].clientX > sepX)
{
if(e.touches[x].clientY < sepY)
{
engine.players[engine.activePlayer].boosting = !engine.players[engine.activePlayer].boosting;
}
else
{
engine.players[engine.activePlayer].braking = !engine.players[engine.activePlayer].braking;
}
return;
}
else
{
var dir = -1;
}
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turn(dir);
else if(engine.players[engine.activePlayer].dedtime+1000 > performance.now())
changeViewTarget(dir);
}
}
}
}
//game settings.controls - keydown
function gameControl(keycode)
{
if(engine.controls.pressed.indexOf(keycode) == -1)
{
if(engine.gtime > 0)
{
if(settings.controls.left.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turn(-1);
else if(engine.players[engine.activePlayer].dedtime+1000 < performance.now())
changeViewTarget(-1);
engine.controls.pressed.push(keycode);
}
if(settings.controls.right.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turn(1);
else if(engine.players[engine.activePlayer].dedtime+1000 < performance.now())
changeViewTarget(1);
engine.controls.pressed.push(keycode);
}
if(settings.controls.north.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turnAbs(0,1);
}
if(settings.controls.south.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turnAbs(0,-1);
}
if(settings.controls.east.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turnAbs(1,0);
}
if(settings.controls.west.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].turnAbs(-1,0);
}
if(settings.controls.togglebrake.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].braking = !engine.players[engine.activePlayer].braking;
engine.controls.pressed.push(keycode);
}
if(settings.controls.brake.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
engine.players[engine.activePlayer].braking = true;
engine.controls.pressed.push(keycode);
}
if(settings.controls.boost.indexOf(keycode) > -1)
{
if(engine.players[engine.activePlayer].alive)
{
if(settings.CYCLE_BOOST == 0 && settings.CYCLE_BRAKE < 0)
engine.players[engine.activePlayer].braking = true;
else
engine.players[engine.activePlayer].boosting = true;
}
engine.controls.pressed.push(keycode);
}
if(settings.controls.jump.indexOf(keycode) > -1)
{
if(settings.CYCLE_MIDAIR_JUMP || engine.players[engine.activePlayer].position.z == 0)
engine.players[engine.activePlayer].model.rotation.y = -settings.CYCLE_JUMP;
engine.controls.pressed.push(keycode);
}
}
if(settings.controls.look_left.indexOf(keycode) > -1)
{
engine.camera.userViewDir = engine.players[engine.viewTarget].left;
engine.controls.pressed.push(keycode);
}
if(settings.controls.look_right.indexOf(keycode) > -1)
{
engine.camera.userViewDir = engine.players[engine.viewTarget].right;
engine.controls.pressed.push(keycode);
}
if(settings.controls.look_forward.indexOf(keycode) > -1)
{
engine.camera.userViewDir = cdir(engine.players[engine.viewTarget].rotation.z);
engine.controls.pressed.push(keycode);
}
if(settings.controls.look_back.indexOf(keycode) > -1)
{
engine.camera.userViewDir = cdir(engine.players[engine.viewTarget].rotation.z-Math.PI);
engine.controls.pressed.push(keycode);
}
}
if(settings.controls.chat.indexOf(keycode) > -1)
{
var input = document.getElementById("input");
input.style.display = "block";
engine.inputStatePrev = engine.inputState;
engine.inputState = "input:chat";
engine.players[engine.activePlayer].chatting = true;
- updateScoreBoard();
+ game.updateScoreBoard();
input.children[0].innerText = "Say:";
input.children[1].focus();
}
if ( settings.controls.camera.indexOf(keycode) > -1 ) {
//do camera change
if ( engine.controls.pressed.indexOf(keycode) == -1 ) { //if not pressed, CHANGE
if (engine.views.indexOf(engine.view) == (engine.views.length-1) ) { //if is last view in list, go back to first [0]
engine.view = engine.views[0];
}
else {//change UP in list
engine.view = engine.views[((engine.views.indexOf(engine.view)) + 1)];
}
engine.controls.pressed.push(keycode);//add only if not added already to pressed keys
}
if(engine.view == 'cockpit')
engine.players[engine.viewTarget].audio.gain.setTargetAtTime(0.2, ctx.currentTime, 0.02);
else
engine.players[engine.viewTarget].audio.gain.setTargetAtTime(6, ctx.currentTime, 1);
console.log('CHANGE_CAMERA to '+engine.view);
}
if(settings.controls.score.indexOf(keycode) > -1)
{
var scoreboard = document.getElementById("scoreboard");
scoreboard.style.display = scoreboard.style.display=="none"?"block":"none";
- updateScoreBoard();
+ game.updateScoreBoard();
}
if(settings.controls.esc.indexOf(keycode) > -1)
{
//do in game menu
if(!engine.paused) pauseMenuToggle();
}
if(settings.controls.scroll_up.indexOf(keycode) > -1)
{
engine.console.scroll(-10);
engine.console.time_manual = performance.now();
}
if(settings.controls.scroll_down.indexOf(keycode) > -1)
{
engine.console.scroll(10);
engine.console.time_manual = performance.now();
}
if(settings.controls.scroll_end.indexOf(keycode) > -1)
{
if(settings.TEXT_OUT_MODE == 1)
{
var lines = engine.console.scrollback
var lnnum = engine.console.scrollby;
var currln = lines[lnnum];
}
else
{
var lines = engine.console.innerText.split("\n");
var lnnum = (-(parseFloat(engine.console.style.top)/engine.console.scrollby));
var currln = lines[lnnum-1];
}
engine.console.time_manual = 0;
engine.console.scroll(lines.length-lnnum-1);
}
if(settings.controls.pause.indexOf(keycode) > -1)
{
console.log('PAUSE');//do pause
}
for(var x=settings.instantchats.length-1;x>=0;--x)
{
var chat = settings.instantchats[x];
for(var y=chat.input.length-1;y>=0;--y)
{
if(keycode == chat.input[y]) handleChat(engine.players[engine.activePlayer],chat.text);
}
}
}
//keyup
function gameControlUp(keycode)
{
if(engine.controls.pressed.indexOf(keycode) > -1)
{
var temp = engine.controls.pressed.indexOf(keycode);
if ( temp > -1 ) //if is pressed
engine.controls.pressed.splice(temp, 1);
}
if(settings.controls.brake.indexOf(keycode) > -1)
{
engine.players[engine.activePlayer].braking = false;
}
if(settings.controls.boost.indexOf(keycode) > -1 )
{
if(settings.CYCLE_BOOST == 0 && settings.CYCLE_BRAKE < 0)
engine.players[engine.activePlayer].braking = false;
engine.players[engine.activePlayer].boosting = false;
}
if(
settings.controls.look_left.indexOf(keycode) > -1 ||
settings.controls.look_right.indexOf(keycode) > -1 ||
settings.controls.look_forward.indexOf(keycode) > -1 ||
settings.controls.look_back.indexOf(keycode) > -1
)
{
engine.camera.userViewDir = false;
}
}
var keyCodeRemap = { 59:186, 61:187 }; //some browsers used alternate keycodes for ; and =
var keycodeList = {
8: 'Backspace',
13: 'Enter',
16: 'Shift', 20: 'Capslock',
17: 'Ctrl', 18: 'Alt',
19: 'Pause/Break', 27: 'Escape', 93: 'Menu',
9: 'Tab', 32: 'Spacebar',
33: 'Page Up',34: 'Page Down',
36: 'Home', 35: 'End',
37: 'Left Arrow', 39: 'Right Arrow',
38: 'Up Arrow', 40: 'Down Arrow',
45: 'Insert', 46: 'Delete',
48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5', 4: '6', 55: '7', 56: '8', 57: '9',
65: 'A', 66: 'B', 67: 'C', 68: 'D', 69: 'E', 70: 'F', 71: 'G', 72: 'H', 73: 'I', 74: 'J', 75: 'K', 76: 'L', 77: 'M', 78: 'N', 79: 'O', 80: 'P', 81: 'Q', 82: 'R', 83: 'S', 84: 'T', 85: 'U', 86: 'V', 87: 'W', 88: 'X', 89: 'Y', 90: 'Z',
91: 'Left Meta', 92: 'Right Meta',
111: 'NUM /', 106: 'NUM *', 109: 'NUM -', 107: 'NUM +', 110: 'NUM .',
96: 'NUM 0', 97: 'NUM 1', 98: 'NUM 2', 99: 'NUM 3', 100: 'NUM 4', 101: 'NUM 5', 102: 'NUM 6', 103: 'NUM 7', 104: 'NUM 8', 105: 'NUM 9',
112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6', 118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12',
144: 'Num Lock', 145: 'Scroll Lock',
186: ';',
187: '=',
188: ',',
189: '-',
190: '.',
191: '/',
192: '`',
219: '[', 221: ']',
220: '\\',
222: '\'',
};
diff --git a/scripts/menu.js b/scripts/menu.js
index dbb72c4..d103375 100644
--- a/scripts/menu.js
+++ b/scripts/menu.js
@@ -1,459 +1,459 @@
/*
* 3DCycles - A lightcycle game.
* Copyright (C) 2019 Glen Harpring
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//change setting via keyboard (menuselect left or right)
function changeMenuItem(name,add,wrap=false,from=false,ref=false)
{
var actmenu = document.getElementsByClassName("menu-active")[0];
var actsp = name.split(":");
//console.log(actsp);
if(actsp[0] == "list")
{
var elem = actmenu.children[0].children[1];
var keys = Object.keys(elem.options);
var elempos = -1;
for(i=0;i= keys.length) if(wrap) elempos = 0; else elempos = keys.length-1;
if(elempos < 0) if(wrap) elempos = key.length-1; else elempos = 0;
elem.innerHTML = replaceColors(elem.options[keys[elempos]]);
elem.call(keys[elempos]);
}
else if(actsp[2] == "num")
{
var elem = actmenu.children[0].children[1];
var value = parseFloat(elem.innerText);
if(from != "key:enter") value += add*actmenu.add;
if(value > actmenu.max) if(wrap) value = actmenu.min; else value = actmenu.max;
if(value < actmenu.min) if(wrap) value = actmenu.max; else value = actmenu.min;
elem.innerText = value;
chsetting(actsp[1],value);
}
}
//MENU SELECT
//keyboard
function menuSelect(direction)
{
//detect menu
//if (from != 'menu-about') {//if its a screen that has a menu with options
var themenu = document.getElementById('menuList').childNodes;
//detect menu position
var selectedItem = -1;
for(var x=0;x= themenu.length) selectedItem = 0; //wrap to first item
hoverSelect(themenu[selectedItem]);
break;
case "esc":
//Exit Menu should be the last item, so convenient hack
selectedItem = themenu.length-1;
//[[FALLTHROUGH]]
case "enter":
document.activeElement.blur();//remove focus from any clicked menu items
menu(themenu[selectedItem].id,"key:"+direction);
break;
//adjust setting - used to change a setting from current value, up or down some, whatever it is
case "left":
changeMenuItem(themenu[selectedItem].id,-1,false,"key:"+direction);
break;
case "right":
changeMenuItem(themenu[selectedItem].id,1,false,"key:"+direction);
break;
}
}
function menuFindPrevSelectable()
{
var themenu = document.getElementById('menuList').childNodes;
var selectedItem = -1;
for(var x=themenu.length-1;x>=0;x--)
{
if(selectedItem >= 0 && themenu[x].href)
{
return x;
}
if(hasClass(themenu[x],'menu-active')) selectedItem = x; //find which one is selected
}
return themenu.length-1;
}
function menuFindNextSelectable()
{
var themenu = document.getElementById('menuList').childNodes;
var selectedItem = -1;
for(var x=0;x= 0 && themenu[x].href)
{
return x;
}
if(hasClass(themenu[x],'menu-active')) selectedItem = x; //find which one is selected
}
return 0;
}
function hoverSelect(item)
{
var themenu = document.getElementById('menuList').childNodes;
for(var x=0;xI don't know either";
var doc = engine.menu.getElementsByTagName("Menus");
if(doc.length > 0)
{
var menus = doc[0].getElementsByTagName("Menu");
for(var x=0;x"+replaceColors(tStringify(cmenu.attributes.title.value))+"";
var items = cmenu.getElementsByTagName("Item");
var list = document.createElement("UL");
list.setAttribute("id","menuList");
for(var i=0;i -1) updateScoreBoard();
+ if(engine.playersByScore.indexOf(this) > -1) game.updateScoreBoard();
}
addScore(x)
{
this.setScore(this.score+((x*1)||0));
}
softReset() //! Resets the cycle state to default variables
{
this.speed = 0;
this.lastSpeed = this.speed;
this.rubber = 0;
this.brakes = 1;
this.braking = false;
this.boosting = false;
this.boost = 0;
this.dedtime = 0;
this.alive = false;
this.collidetime = Infinity;
this.sensor = {left:Infinity,right:Infinity,front:Infinity};
this.dir = {front:[0,0],left:[0,0],right:[0,0]};
this.minDistance = {front:settings.CYCLE_RUBBER_MINDISTANCE};
this.turnQueue = [];
this.lastTurnTime = 0;
this.gameTime = 0;
this.handleNetTurn = true;
}
hardReset() //! Same as soft reset but resets all varaibles
{
this.softReset();
this.setScore(0);
this.ping = 0;
}
getColoredName() //! Name with colors...
{
switch(typeof(this.tailColor))
{
case "string":
return this.tailColor.replace("#","0x")+this.name;
case "object":
return "0x"+this.tailColor.getHexString()+this.name;
case "number":
var color = this.tailColor.toString(16);
color = ("0".repeat(6-color.length))+color;
return "0x"+color+this.name;
default:
console.warn("Can't get color");
return "0xRESETT"+this.name;
}
}
getBoringName() //! Name without colors...
{
return removeColors(this.name);
}
newWallSegment() //should be called on turns
{
var adj = 0.7, wmap = this.walls.map, dirmult = this.dir.front;
wmap[wmap.length-1] = [this.position.x,this.position.y,this.position.z];
wmap[wmap.length] = [this.position.x,this.position.y,this.position.z];
this.resetCurrWallSegment(false,1);
var wall = newWall(this.tailColor,this.position.x,this.position.y,this.position.z);
var adjx = (dirmult[0]*adj), adjy = (dirmult[1]*adj);
wall.scale.x -= adjx/wall.size; wall.scale.y -= adjy/wall.size;
this.walls.add(wall);
}
/*recalcCurrWallLength(tocurrpos=false)
{
var adj = 0.7, dirmult = this.dir.front, wall = this.walls.children[this.walls.children.length-1];
var adjx = (dirmult[0]*adj), adjy = (dirmult[1]*adj);
wall.scale.x += adjx/wall.size; wall.scale.y += adjy/wall.size;
this.resetCurrWallSegment(tocurrpos,0,true);
wall.scale.x -= adjx/wall.size; wall.scale.y -= adjy/wall.size;
}*/
resetCurrWallSegment(tocurrpos=false,offset=0,breakWallLength=false) //! Redoes the current 3D wall segment to the actual wall segment.
{
if(this.walls.children.length == 0) return;
var wmap = this.walls.map;
var oldwall = this.walls.children[this.walls.children.length-1];
if(breakWallLength)
{
var sizex = oldwall.scale.x*oldwall.size,sizey = oldwall.scale.y*oldwall.size;
this.walls.netLength -= Math.sqrt((sizex*sizex)+(sizey*sizey));
}
if(typeof(wmap[wmap.length-3]) == "undefined")
{
//console.warn("Wall was undefined when trying to calculate wall size");
//console.log();
return;
}
if(tocurrpos)
{
wmap[wmap.length-2] = [this.position.x,this.position.y,this.position.z];
}
var a = 2+offset, b=1+offset;
oldwall.position.set(wmap[wmap.length-a][0],wmap[wmap.length-a][1],wmap[wmap.length-3][2]||0);
oldwall.scale.x = (wmap[wmap.length-b][0]-wmap[wmap.length-a][0])/oldwall.size||1;
oldwall.scale.y = (wmap[wmap.length-b][1]-wmap[wmap.length-a][1])/oldwall.size||1;
if(breakWallLength)
{
var sizex = oldwall.scale.x*oldwall.size,sizey = oldwall.scale.y*oldwall.size;
this.walls.netLength += Math.sqrt((sizex*sizex)+(sizey*sizey));
}
else
{
this.calcWallLength();
}
}
calcWallLength(cycle) //! sets the actual wall length
{
var wmap = this.walls.map;
this.walls.netLength = 0;
for(var x=wmap.length;x>=0;x--)
{
if(wmap[x+1] !== undefined)
{
var p1=wmap[x],p2=wmap[x+1];
this.walls.netLength += pointDistance(p1[0],p1[1],p2[0],p2[1]);
}
}
return this.walls.netLength;
}
resetWall(full=true) //! Completely redoes the 3D wall according to the actual wall
{
if(full === true)
{
for(var x=0,len=this.walls.children.length;x Math.PI)
{
return this.turn(1);
}
else if(ang != 0)
{
return this.turn(-1);
}
}
spawn(cfg,respawn=true,update=true)
{
//configure cycle
this.softReset();
this.position.set(cfg.x,cfg.y,cfg.z);
this.lastpos = this.position.clone();
this.rotation.set(0,0,cfg.dir);
this.lastdir = {front:0};
this.alive = true;
this.speed = settings.CYCLE_START_SPEED;
this.gameTime = this.spawntime = Math.max(0,engine.gtime);
this.haswall = !(respawn||settings.CYCLE_FIRST_SPAWN_PROTECTION);
//walls
if(this.haswall)
{
this.walls = createWall(this,cfg.x,cfg.y,cfg.z);
engine.scene.add(this.walls);
}
if(this.audio) this.audio.panner.connect(ctx.destination);
engine.scene.add(this);
- if(update) updateScoreBoard();
+ if(update) game.updateScoreBoard();
if(this == engine.players[engine.activePlayer]) engine.viewTarget = engine.activePlayer;
}
kill()
{
this.resetCurrWallSegment();
this.alive = false; this.dedtime = performance.now();
engine.scene.remove(this);
if(this == engine.players[engine.viewTarget] && !engine.dedicated)
- setTimeout(function(){if(!engine.players[engine.viewTarget].alive)changeViewTarget()},3000);
+ setTimeout(function(){if(!engine.players[engine.viewTarget].alive)game.changeViewTarget()},3000);
if(this.audio)
{
this.audio.panner.disconnect();
playSound(bufferLoader.bufferList[this.engineType+6],0.5,1,false,ctx.destination);
spawnExplosion(this.position,this.cycleColor,this.tailColor);
}
- updateScoreBoard();
+ game.updateScoreBoard();
if(this.hasFlag)
{
engine.console.print(this.getColoredName()+"0xRESETT dropped the flag they were holding.\n");
this.hasFlag.type = "flag";
this.hasFlag = null;
}
if(engine.dedicated)
{
var alive = 0, aliveAI = 0;
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
if(engine.players[x].alive)
{
alive++;
if(engine.players[x].AI) aliveAI++;
}
}
- if(alive==aliveAI) changeViewTarget(0); //this will handle the finish type stuff
+ if(alive==aliveAI) game.changeViewTarget(0); //this will handle the finish type stuff
}
}
killAt(position,y=false,z=false)
{
if(y !== false) var x = position;
else var x=position.x,y=position.y,z=position.z;
this.position.set(x,y,z===false?this.position.z:z);
this.kill();
}
killIn(timestep)
{
this.update(timestep);
this.kill();
}
doChat(msg)
{
if(engine.network)
{
engine.connection.send(JSON.stringify({type:"chat",data:msg}));
}
else
{
engine.console.print(this.getColoredName()+"0xffff7f: "+msg+"\n");
if(engine.dedicated) {}
}
}
update(timestep=false) //! Simulates game movement on cycles
{
if(timestep === false) { timestep = (engine.gtime-this.gameTime)/1000; if(timestep < 0) return; }
this.gameTime += timestep*1000;
//var timeElapsed = engine.gtime;
var timeElapsed = this.gameTime;
//movement
var acceleration = 0;
if(this.braking)
{
if(this.brakes > 0)
{
acceleration -= settings.CYCLE_BRAKE;
this.brakes -= timestep*settings.CYCLE_BRAKE_DEPLETE;
}
}
else if(this.brakes < 1)
{
this.brakes += timestep*settings.CYCLE_BRAKE_REFILL;
}
if(this.brakes > 1) this.brakes = 1;
else if(this.brakes < 0) this.brakes = 0;
if(this.boosting)
acceleration += settings.CYCLE_BOOST;
if(this.speed < settings.CYCLE_SPEED)
{
acceleration += (settings.CYCLE_SPEED-this.speed)*settings.CYCLE_SPEED_DECAY_BELOW;
}
else if(this.speed > settings.CYCLE_SPEED)
{
acceleration += (settings.CYCLE_SPEED-this.speed)*settings.CYCLE_SPEED_DECAY_ABOVE;
}
if(this.sensor.left < settings.CYCLE_WALL_NEAR || this.sensor.right < settings.CYCLE_WALL_NEAR)
{
var wallAccel = settings.CYCLE_ACCEL;
if(wallAccel != 0) //don't bother if there's no accel
{
var accelMult = [(settings.CYCLE_WALL_NEAR-this.sensor.left)/settings.CYCLE_WALL_NEAR,(settings.CYCLE_WALL_NEAR-this.sensor.right)/settings.CYCLE_WALL_NEAR];
var accelTargets = [this.sensor.lnearestobj,this.sensor.rnearestobj];
for(var z=2;z--;)
{
if(accelMult[z] > 0)
{
if(accelTargets[z] == "rim")
{
wallAccel *= settings.CYCLE_ACCEL_RIM;
}
else if(typeof(accelTargets[z]) == "object")
{
if(accelTargets[z] == this)
{
wallAccel *= settings.CYCLE_ACCEL_SELF;
}
else
{
wallAccel *= settings.CYCLE_ACCEL_ENEMY;
}
}
else
{
throw "Accel target is unknown.";
}
wallAccel *= accelMult[z];
}
}
//console.log(wallAccel);
acceleration += wallAccel;
}
}
this.speed += acceleration*timestep;
if(this.speed < settings.CYCLE_SPEED*settings.CYCLE_SPEED_MIN)
{
this.speed = settings.CYCLE_SPEED*settings.CYCLE_SPEED_MIN;
}
if(settings.CYCLE_SPEED_MAX != 0 && this.speed > settings.CYCLE_SPEED*settings.CYCLE_SPEED_MIN)
{
this.speed = settings.CYCLE_SPEED*settings.CYCLE_SPEED_MAX;
}
this.accel = acceleration;
if(this.speed < 0) this.speed = 0;
//wheel spin per player
if(!engine.dedicated)
{
this.model.children[1].rotation.y += (deg2rad(this.model.rotaon.front * this.speed) * timestep);//0.5x wheel size
this.model.children[2].rotation.y += (deg2rad(this.model.rotaon.back * this.speed) * timestep);
}
//collision test
var dir = cdir(this.rotation.z);
var posx = this.position.x, posy = this.position.y;
var escape = false;
if(posx+settings.ARENA_BOUNDARY > engine.logicalBox.max.x*engine.REAL_ARENA_SIZE_FACTOR)
{
escape = true;
this.position.x = (engine.logicalBox.max.x*engine.REAL_ARENA_SIZE_FACTOR)-settings.ARENA_BOUNDARY;
}
if(posy+settings.ARENA_BOUNDARY > engine.logicalBox.max.y*engine.REAL_ARENA_SIZE_FACTOR)
{
escape = true;
this.position.y = (engine.logicalBox.max.y*engine.REAL_ARENA_SIZE_FACTOR)-settings.ARENA_BOUNDARY;
}
if(posx-settings.ARENA_BOUNDARY < engine.logicalBox.min.x*engine.REAL_ARENA_SIZE_FACTOR)
{
escape = true;
this.position.x = (engine.logicalBox.min.x*engine.REAL_ARENA_SIZE_FACTOR)+settings.ARENA_BOUNDARY;
}
if(posy-settings.ARENA_BOUNDARY < engine.logicalBox.min.y*engine.REAL_ARENA_SIZE_FACTOR)
{
escape = true;
this.position.y = (engine.logicalBox.min.y*engine.REAL_ARENA_SIZE_FACTOR)+settings.ARENA_BOUNDARY;
}
/*var collided = false;
for(var y=0; y= this.sensor.front)
if(dist >= this.sensor.front-(this.minDistance.front))
//if(this.speed*timestep >= this.sensor.front)
{
dist = (this.sensor.front-(this.minDistance.front));
//if(x == engine.viewTarget) console.warn(dist+" "+this.sensor.front+"\n");
collided = true;
}
if(dist > this.sensor.front-(this.minDistance.front)) //shouldn't happen
{
dist = this.minDistance.front;
}
if(collided || (escape && settings.ARENA_BOUNDARY_KILLS))
{
if(this.rubber >= settings.CYCLE_RUBBER)
{
if(!engine.network)
{
- doDeath(this,escape);
+ game.killBlame(this,escape);
}
}
else if(
(settings.CYCLE_RUBBER_DEPLETE_RIM && this.sensor.nearestobj == "rim") ||
(settings.CYCLE_RUBBER_DEPLETE_SELF && this.sensor.nearestobj == this) ||
(settings.CYCLE_RUBBER_DEPLETE_ENEMY && this.sensor.nearestobj != this && typeof(this.sensor.nearestobj) == "object")
)
{
this.rubber += radj;
}
}
var move2d = Math.cos(this.model.rotation.y), movez = -this.model.rotation.y;
var dist2d = dist*move2d;
var newx = dist2d*dir[0], newy = dist2d*dir[1], newz = dist*movez;
this.position.x += newx;
this.position.y += newy;
this.position.z += newz;
if(this.newPos)
{
this.newPos.x += newx;
this.newPos.y += newy;
}
if(this.position.z-this.sensor.bottom < this.model.rotation.y)
{
this.model.rotation.y = this.position.z;
if(this.model.rotation.y < 0)
{
this.model.rotation.y = 0;
this.position.z = this.sensor.bottom;
}
}
if(this.position.z > this.sensor.bottom)
{
this.model.rotation.y += timestep*(1-this.model.rotation.y);
}
//if(typeof(this.walls.children) != "undefined")
if(this.haswall && this.walls.children.length > 0 && this.walls.map.length > 0)
{
var wallmod = this.walls.children[this.walls.children.length-1];
var wallmap = this.walls.map[this.walls.map.length-1];
wallmap[0]+=(newx); wallmap[1]+=(newy);
wallmod.scale.x += newx/wallmod.size;
wallmod.scale.y += newy/wallmod.size;
this.walls.netLength += dist;
this.sensor.front -= dist; //assume distance until we have new real results.
//this.sensor.front =
var lendiff = this.walls.netLength - settings.WALLS_LENGTH;
while(settings.WALLS_LENGTH > 0 && lendiff > 0)
{
var map = this.walls.map;
var xdir = (map[1][0]-map[0][0]), ydir = (map[1][1]-map[0][1]);
var len = Math.sqrt((xdir*xdir)+(ydir*ydir));
if(len > 1) { xdir /= len; ydir /= len; }
if(isNaN(xdir)) xdir = SMALL_NUM; if(isNaN(ydir)) ydir = SMALL_NUM;
//console.log(lendiff,xdir,ydir);
if(xdir == 0 && ydir == 0 && this.walls.map.length > 2)
{
//this.walls.children.shift();
this.walls.remove(this.walls.children[0]);
this.walls.map.shift();
}
else if(this.walls.children[0] && this.walls.map[0])
{
this.walls.children[0].scale.x -= xdir/wallmod.size;
this.walls.children[0].position.x += xdir;
this.walls.children[0].scale.y -= ydir/wallmod.size;
this.walls.children[0].position.y += ydir;
this.walls.map[0][0] += xdir;
this.walls.map[0][1] += ydir;
this.walls.netLength -= Math.sqrt((xdir*xdir)+(ydir*ydir));
} else { break; }
lendiff = this.walls.netLength - settings.WALLS_LENGTH;
}//*/
if(this.position.z > 0) this.newWallSegment();
}
else if(engine.gtime > this.spawntime+(settings.CYCLE_WALL_TIME*1000))
{
this.walls = createWall(this,this.position.x,this.position.y,this.position.z);
engine.scene.add(this.walls);
this.haswall = true;
}
this.collidetime = timeElapsed+(((this.sensor.front-this.minDistance.front)/this.speed)*1000);
this.lastSpeed = this.speed;
}
if(this.speed > engine.fastestSpeed)
{
engine.fastestPlayer = this; engine.fastestSpeed = this.speed;
}
}
constructor(cfg)
{
super();
//var dir = cdir(cfg.dir);
//this.cfg = cfg;//carry over the cfg???
//choose model
this.model = cycleModel(cfg.cycleColor);
this.add(this.model);
//this.shadow = cycleShadow();
//this.add(this.shadow);
this.chatarrow = newChatArrow();
this.chatarrow.position.z = 1.20;
this.chatarrow.position.x -= 0.5;
this.chatarrow.scale.set(0.25,0.25,0.25);
this.add(this.chatarrow);
this.cycleColor = cfg.cycleColor;
this.tailColor = cfg.tailColor;
/*this.walls = {};
//this.walls.children = [];
this.walls.netLength = 0;
this.walls.map = [];
this.walls.scale = this.walls.position = new THREE.Vector3();*/
this.walls = createWall(this,0,0,0); //walls are still called upon when spectating
this.chatting = cfg.chatting||false; this.spectating = cfg.spectating||false;
if(cfg.ai||settings.DEBUG_EVERYONE_IS_AI)
{
this.AI = new AI(this);
}
else
{
this.AI = false;
}
// this.playerID = cfg.playerID;
this.name = cfg.name;
this.team = cfg.team;
this.hardReset();
//audio creation
this.engineType = cfg.engineType;
if(ctx)
{
this.audio = ctx.createGain();
this.audio.gain.value = 0.01;
this.audio.panner = ctx.createPanner();
if(engine.retroSound)
this.audio.panner.panningModel = "HRTF";
else
this.audio.panner.panningModel = "equalpower";
this.audio.connect(this.audio.panner);
this.audio.panner.connect(ctx.destination);
//audio initialization
this.engineSound = playSound(bufferLoader.bufferList[this.engineType], 0.5, 0, true, this.audio);
this.audio.gain.setTargetAtTime(6, ctx.currentTime, 1.0);
}
}
};
if(typeof(module) != "undefined") module.exports = Player;
diff --git a/scripts/render.js b/scripts/render.js
index a0d6a05..ba32523 100644
--- a/scripts/render.js
+++ b/scripts/render.js
@@ -1,562 +1,562 @@
/*
* 3DCycles - A lightcycle game.
* Copyright (C) 2019 Glen Harpring
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
var draw2dmap = true;
function render()
{
if(!engine.roundCommencing && !engine.paused)
{
engine.renderRunning = true;
- if(settings.GAME_LOOP > 0) game(true); //update game right before render
+ if(settings.GAME_LOOP > 0) game.run(true); //update game right before render
if(settings.REDRAW_MODE == 0) requestAnimationFrame(render);
else setTimeout(render,1000/settings.TARGET_FPS);
draw(); //actual 3d draw
if(settings.HUD_MAP && draw2dmap && engine.hud.style.opacity > 0)
{
draw2dmap = false;
if(settings.REDRAW_MODE == 0)
setTimeout(draw2d_canvas,0);
else
requestAnimationFrame(draw2d_canvas);
}
}
else
{
engine.renderRunning = false;
if(engine.paused)
{
//var lines = engine.console.innerText.split("\n");
//if(lines[(parseFloat(0+engine.console.style.top)/engine.console.scrollby].length > 0)
}
}
if(settings.TEXT_OUT_MODE == 1)
{
var lines = engine.console.scrollback
var lnnum = engine.console.scrollby;
var currln = lines[lnnum];
}
else
{
var lines = engine.console.innerText.split("\n");
var lnnum = (-(parseFloat(engine.console.style.top)/engine.console.scrollby));
var currln = lines[lnnum-1];
}
if(Math.round(engine.console.time/engine.console.scrolltime) < Math.round(performance.now()/engine.console.scrolltime) || (performance.now() > engine.console.time_manual+engine.console.scrolltime_manual && lines.length-lnnum > 10))
{
if(!currln && lnnum != lines.length)
{
if(lnnum < 0) var scrby = 1;
if(lnnum > lines.length) var scrby = -1;
engine.console.scroll(scrby);
console.log("scroll",scrby);
}
else
{
engine.console.time = performance.now();
if(typeof(currln) != "undefined" && currln.length > 0)
engine.console.scroll();
console.log("scroll");
}
}
}
function draw()
{
//time handlers and delta
var timenow = performance.now();
var delta = (timenow - engine.lastRenderTime);
var frametime = delta/1000;//time step
engine.lastRenderTime = timenow;
var fpsDelta = (timenow - engine.fpsTime);
settings.TARGET_FPS = (1000/delta)*2;
if(settings.TARGET_FPS < 10) settings.TARGET_FPS = 10;
if(settings.MAX_TARGET_FPS < settings.TARGET_FPS) settings.TARGET_FPS = settings.MAX_TARGET_FPS;
//if(fpsDelta > 999) //update fps gui once every second
if(fpsDelta >= 500) // experimental quicker FPS updating...
{
//var fpsValue = fpsDelta/delta;
/*var fpsValue = 1000/delta;*/
var fpsValue = engine.framesCount*(1000/fpsDelta);
//settings.TARGET_FPS = fpsValue*2;
engine.framesCount = 0;
engine.fpsTime = timenow;
/*document.getElementById("fps").innerHTML = "FPS: " + fpsValue;*/
updateHUD("current_framerate",fpsValue);
}
//updateHUD("current_framerate_now",1000/delta);
updateHUD("current_frametime",delta);
var timeElapsed = (timenow - engine.timeStart)-engine.totalPauseTime-4000;
if(engine.zones) for(var x=engine.zones.children.length-1;x>=0;--x)
{
//zones spin
switch(settings.ZONE_RENDER_TYPE)
{
case "cylinder":
engine.zones.children[x].rotation.y += ((engine.zones.children[x].cfg.rotationSpeed * pi(2)) * frametime);
break;
default:
engine.zones.children[x].rotation.z += ((engine.zones.children[x].cfg.rotationSpeed * pi(2)) * frametime);
break;
}
}
for(var x=engine.players.length-1;x>=0;x--) if(engine.players[x] !== undefined)
{ //cycle un-tilting
var cycle=engine.players[x];
var xdir=Math.cos(cycle.rotation.z),ydir=Math.sin(cycle.rotation.z);
var xd = Math.abs(xdir), yd = Math.abs(ydir);
var sens = 0;
if(cycle.sensor.left < 1) sens -= 0.02/cycle.sensor.left;
if(cycle.sensor.right < 1) sens += 0.02/cycle.sensor.right;
if(sens > 1) sens = 1;
if(sens < -1) sens = -1;
cycle.rotation.x -= xd*(((cycle.rotation.x)*frametime*4)+(sens*frametime*xdir));
cycle.rotation.y -= yd*(((cycle.rotation.y)*frametime*4)+(sens*frametime*ydir));
if(cycle.chatting != cycle.chatarrow.visible) cycle.chatarrow.visible = cycle.chatting;
if(cycle.chatting)
{
cycle.chatarrow.rotation.z += frametime;
}
//sound
if(window.mixCycle) mixCycle(cycle);
}
if(settings.WALLS_STAY_UP_DELAY >= 0)
{
for(var x=engine.players.length;x>=0;x--) if(engine.players[x] !== undefined)
{
if(!engine.players[x].alive && timenow-engine.players[x].dedtime >= settings.WALLS_STAY_UP_DELAY*1000)
{
if(engine.players[x].walls.scale.z > 0)
{
engine.players[x].walls.scale.z -= frametime*2;
}
else
{
engine.scene.remove(engine.players[x].walls);
}
}
}
}
for(var x=engine.expl.length-1;x>=0;x--)
{
if(engine.expl[x].children[0].material.opacity <= 0)
{
engine.scene.remove(engine.expl[x]);
engine.expl.splice(x,1);
}
else for(var y=engine.expl[x].children.length-1;y>=0;y--)
{
engine.expl[x].children[y].scale.x = engine.expl[x].children[y].scale.y = engine.expl[x].children[y].scale.z += frametime*10;
//engine.expl[x].children[y].position.z += frametime;
if(engine.expl[x].children[y].scale.z > 10)
{
engine.expl[x].children[y].material.opacity -= frametime/25;
}
}
}
if(settings.FLOOR_MIRROR && typeof(engine.grid.reflection) != "undefined")
{
engine.grid.visible = false;
engine.grid.reflection.update(engine.renderer,engine.scene);
engine.grid.visible = true;
}
if(settings.RIM_WALL_COLOR_MODE == 3)
{
var color = engine.walls.children[0].material.color;
var p = settings.COLOR_MODE_3_COLORS.split(";");
var c = p[engine.currrim3clr].split(",");
//var c = {r:parse[0],g:parse[1],b:parse[2]};
var sum = color.r+color.g+color.b;
var keys = Object.keys(color);
for(var x=keys.length-1;x>=0;--x)
{
if(c[x] < color[keys[x]])
{
color[keys[x]] -= frametime*settings.COLOR_MODE_3_SPEED;
}
else if(c[x] > color[keys[x]])
{
color[keys[x]] += frametime*settings.COLOR_MODE_3_SPEED;
}
if(color[keys[x]] > 1)
color[keys[x]] = 1;
if(color[keys[x]] < 0)
color[keys[x]] = 0;
}
//console.log(color,c);
if(color.r == c[0] && color.g == c[1] && color.b == c[2])
{
engine.currrim3clr += 1;
if(engine.currrim3clr >= p.length)
engine.currrim3clr = 0;
}
for(var x=engine.walls.children.length-1;x>=0;--x)
{
engine.walls.children[x].material.color = color;
}
}
if(timenow > engine.cMFadeOutAfter)
{
var cm = document.getElementById("centerMessage")
cm.style.opacity -= frametime;
if(cm.style.opacity <= 0)
{
cm.style.opacity = 0;
cm.style.display = "none";
engine.cMFadeOutAfter = Infinity;
}
}
if(engine.hud.fadein && engine.hud.game.style.opacity < 1)
{
engine.hud.game.style.opacity = (engine.hud.game.style.opacity*1)+(frametime*0.25); //workaround for opacity being a string
if(engine.hud.game.style.opacity > 1) engine.hud.game.style.opacity = 1;
}
else if(!engine.hud.fadein && engine.hud.game.style.opacity > 0)
{
engine.hud.game.style.opacity -= frametime*0.25;
if(engine.hud.game.style.opacity < 0) engine.hud.game.style.opacity = 0;
}
//update HUD (needs to be done for cycle being viewed)
var cycle = engine.players[engine.viewTarget];
updateHUD("player_rubber",cycle.rubber,0,settings.CYCLE_RUBBER);
var maxspeed = maxSpeed();
updateHUD("player_speed",cycle.speed,0,maxspeed);
updateHUD("player_brake",cycle.brakes,0,1);
updateHUD("max_speed",maxspeed);
updateHUD("player_acceleration",cycle.accel);
updateHUD("dist_to_impact_front",cycle.sensor.front);
updateHUD("time_to_impact_front",cycle.sensor.front/cycle.speed);
updateHUD("dist_to_impact_left",cycle.sensor.left);
updateHUD("time_to_impact_left",cycle.sensor.left/cycle.speed);
updateHUD("dist_to_impact_right",cycle.sensor.right);
updateHUD("time_to_impact_right",cycle.sensor.right/cycle.speed);
updateHUD("current_name",cycle.name);
updateHUD("current_pos_x",cycle.position.x,engine.logicalBox.min.x*engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.max.x*engine.REAL_ARENA_SIZE_FACTOR);
updateHUD("current_pos_y",cycle.position.y,engine.logicalBox.min.y*engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.max.y*engine.REAL_ARENA_SIZE_FACTOR);
updateHUD("current_pos_x_adj",cycle.position.x/engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.min.x,engine.logicalBox.max.x);
updateHUD("current_pos_y_adj",cycle.position.y/engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.min.y,engine.logicalBox.max.y);
var dir = cdir(cycle.rotation.z);
updateHUD("current_angle_x",dir[0]);
updateHUD("current_angle_y",dir[1]);
updateHUD("current_time",Math.round(timeElapsed)/1000);
//settings test
var setnames = Object.keys(settings);
for(var i=setnames.length;i--;)
{
var setting = setnames[i];
updateHUD(setting.toLowerCase(),settings[setting]);
}
//actual drawing
/*if(engine.players[engine.viewTarget].alive)*/ cameraView(engine.players[engine.viewTarget],frametime*engine.timemult);
if(ctx) audioMixing();
//renderer switch for post processing
if (engine.usingPostProcessing) {
engine.composer.render();//new render? for post processing
}
else {
engine.renderer.render(engine.scene, engine.camera);
}
engine.framesCount++;
}
function updateHUD(celement,thevalue,min=false,max=false)
{
var elements = document.getElementsByName(celement);
for(var i=elements.length;i--;)
{
var value = thevalue;
var element = elements[i];
if(min && element.attributes.min) element.setAttribute("min",min);
if(max && element.attributes.max) element.setAttribute("max",max);
if(element.attributes.precision)
{
var prec = Math.pow(10,element.attributes.precision.value);
value = Math.round(value*prec)/prec;
if(isNaN(value)) value = 0;
}
if(element.attributes.toprecision)
{
var prec = 1*element.attributes.toprecision.value;
if(!element.attributes.dontlimit)
{
value = parseFloat(value).toPrecision(prec-1+((""+Math.round(thevalue)).length));
}
else
{
value = value.toPrecision(prec);
}
}
//if(element.attributes.precision) element.attributes.precision.value==0?value=Math.round(value):value.toPrecision(element.attributes.precision.value);
//if(value)
{
if(element.tagName == "PROGRESS")
{
element.setAttribute("value",value);
//console.log(value);
}
else if(element.className == "progress")
{
element.style.width = (Math.min(1,value/max)*100)+"%";
}
else if(!element.attributes.ignoretext)
{
element.innerHTML = ""+value;
}
if(element.attributes.bgcolorgrad)
{
var grad = element.attributes.bgcolorgrad.value;
var p = grad.split(";");
var c1 = p[0].split(",");
var c2 = p[1].split(",");
var color = {r:c1[0]*1,g:c1[1]*1,b:c1[2]*1},key=['r','g','b'];
var progval = (value/max)*15;
for(var x=0;x<3;x++)
{
if(c1[x] < c2[x])
{
color[key[x]] += progval;
}
else if(c1[x] > c2[x])
{
color[key[x]] -= progval;
}
}
element.style.backgroundColor = "rgb("+(color.r*255)+","+(color.g*255)+","+(color.b*255)+")";
}
}
}
}
function draw2d_canvas() //TODO: have an svg output option
{
var canvas = document.getElementById("canvas");
if(!canvas) return;
var ctx = canvas.getContext("2d");
ctx.clearRect(0,0,canvas.width,canvas.height);
var xsize = engine.logicalBox.max.x-engine.logicalBox.min.x, ysize = engine.logicalBox.max.y-engine.logicalBox.min.y;
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetWidth*(ysize/xsize);
ctx.scale(
canvas.width/(xsize*engine.REAL_ARENA_SIZE_FACTOR),
canvas.height/(ysize*engine.REAL_ARENA_SIZE_FACTOR)
);
var ax = engine.logicalBox.min.x * engine.REAL_ARENA_SIZE_FACTOR,
ay = engine.logicalBox.min.y * engine.REAL_ARENA_SIZE_FACTOR;
ctx.lineWidth = ((xsize*engine.REAL_ARENA_SIZE_FACTOR)/canvas.width);
//ctx.lineWidth = canvas.width-canvas.height-2;
//ctx.lineWidth = (canvas.offsetWidth-canvas.width)*engine.REAL_ARENA_SIZE_FACTOR;
ctx.strokeStyle = "white";
for(var i=engine.map.walls.length-1;i>=0;i--)
{
ctx.beginPath();
var spl = engine.map.walls[i][engine.map.walls[i].length-1];
ctx.moveTo(1*spl[0],1*spl[1]);
for(var z=engine.map.walls[i].length-1;z>=0;z--)
{
var spl = engine.map.walls[i][z];
ctx.lineTo(1*spl[0]-ax,1*spl[1]-ay);
//console.log(spl[0],spl[1]);
}
ctx.stroke();
}
for(var x=engine.players.length-1;x>=0;x--) if(engine.players[x] !== undefined)
{
var color = engine.players[x].walls.children[0].children[0].material.color;
ctx.strokeStyle = "rgb("+(color.r*255)+","+(color.g*255)+","+(color.b*255)+")";
ctx.beginPath();
if(engine.players[x].walls.map.length > 0)
{
var walls = engine.players[x].walls.map;
ctx.moveTo(walls[walls.length-1][0]-ax,walls[walls.length-1][1]-ay);
for(var i=walls.length-1;i>=0;i--)
{
ctx.lineTo(walls[i][0]-ax,walls[i][1]-ay);
}
}
ctx.stroke();
if(engine.players[x].alive)
{
var color = new THREE.Color(engine.players[x].cycleColor);
ctx.fillStyle = "rgb("+(color.r*255)+","+(color.g*255)+","+(color.b*255)+")";
ctx.beginPath();
ctx.arc(engine.players[x].position.x-ax,engine.players[x].position.y-ay, ctx.lineWidth, 0,Math.PI*2);
ctx.fill();
}
}
var lw = ctx.lineWidth;
ctx.lineWidth = lw*settings.ZONE_ALPHA*settings.ZONE_ALPHA_SERVER;
for(var x=engine.zones.children.length-1;x>=0;--x)
{
var zone = engine.zones.children[x];
var color = zone.material.color;
ctx.strokeStyle = "rgb("+(color.r*255)+","+(color.g*255)+","+(color.b*255)+")";
var geo = zone.geometry.clone(); geo.applyMatrix(zone.matrix); //apply rotation, scale, and position
ctx.beginPath();
var pX = zone.position.x-ax, pY = zone.position.y-ay;
for(var i=geo.faces.length-2;i>=0;i-=2)
{
ctx.moveTo(geo.vertices[geo.faces[i].b].x-ax,geo.vertices[geo.faces[i].b].y-ay);
ctx.lineTo(geo.vertices[geo.faces[i].a].x-ax,geo.vertices[geo.faces[i].a].y-ay);
}
ctx.stroke();
}
lw *= 0.7;
for(var x=engine.expl.length-1;x>=0;x--)
{
ctx.lineWidth = lw*engine.expl[x].children[0].material.opacity;
if(ctx.lineWidth > 0)
{
var scale = (engine.expl[x].children[0].scale.x+engine.expl[x].children[0].scale.y)/2;
var cx = engine.expl[x].children[0].position.x, cy = engine.expl[x].children[0].position.y;
for(var y=engine.expl[x].children.length;y--;)
{
var color = engine.expl[x].children[y].material.color;
ctx.strokeStyle = "rgb("+(color.r*255)+","+(color.g*255)+","+(color.b*255)+")";
ctx.beginPath();
ctx.moveTo(cx-ax,cy-ay);
ctx.lineTo(
(cx+engine.expl[x].children[y].geometry.vertices[1].x*scale)-ax,
(cy+engine.expl[x].children[y].geometry.vertices[1].y*scale)-ay
);
ctx.stroke();
}
}
}
draw2dmap = true;
}
//camera view function (handles all views for view target)
var cameraView = function(cycle, timestep) {
var relativeCameraOffset, cameraOffset;
var cameraEase = engine.cameraEase;
if(engine.camera.userViewDir !== false) // HACK: camera rotation
{
var realRot = cycle.rotation.z;
cycle.rotation.z = Math.atan2(engine.camera.userViewDir[1],engine.camera.userViewDir[0]);
cycle.updateWorldMatrix();
cycle.rotation.z = realRot;
}
switch(engine.view)
{
case 'smart':
if(engine.camera.userViewDir === false)
{
//relativeCameraOffset = new THREE.Vector3(-5,0,5+cycle.speed);
relativeCameraOffset = new THREE.Vector3(-5,0,(5+cycle.speed*0.006));
cameraOffset = relativeCameraOffset.applyMatrix4(cycle.matrixWorld);
engine.camera.position.x += (cameraOffset.x - engine.camera.position.x) * (engine.cameraEase/3) * timestep*60;
engine.camera.position.y += (cameraOffset.y - engine.camera.position.y) * (engine.cameraEase/3) * timestep*60;
engine.camera.position.z += (cameraOffset.z - engine.camera.position.z) * (engine.cameraEase/5) * timestep*60;
engine.camera.lookAt(cycle.position);
break;
}
else
{
relativeCameraOffset = new THREE.Vector3((-10-(cycle.speed*0.006)),0,(5+cycle.speed*0.006));
cameraEase = 0.3;
// [[FALLTHROUGH]]
}
case 'chase':
if(!relativeCameraOffset) relativeCameraOffset = new THREE.Vector3((-10-(cycle.speed*0.006)),0,(15+cycle.speed*0.006));
cameraOffset = relativeCameraOffset.applyMatrix4(cycle.matrixWorld);
engine.camera.position.x += (cameraOffset.x - engine.camera.position.x) * cameraEase * timestep*60;
engine.camera.position.y += (cameraOffset.y - engine.camera.position.y) * cameraEase * timestep*60;
engine.camera.position.z += (cameraOffset.z - engine.camera.position.z) * cameraEase * timestep*60;
engine.camera.lookAt(cycle.position);
break;
case 'custom':
engine.camera.position.set(0,0,0);
engine.camera.rotation.z = settings.CAMERA_CUSTOM_PITCH;
break;
case 'stationary':
break;
case 'track':
engine.camera.lookAt(cycle.position);
break;
case 'topdown':
engine.camera.position.set(cycle.position.x, (cycle.position.y-0.01), (10+cycle.speed*timestep));
engine.camera.lookAt(cycle.position);
break;
case 'birdseye':
relativeCameraOffset = new THREE.Vector3(-0.1, 0, 10+(cycle.speed*timestep));
cameraOffset = relativeCameraOffset.applyMatrix4(cycle.matrixWorld);
engine.camera.position.x += (cameraOffset.x - engine.camera.position.x) * engine.cameraEase * timestep*60;
engine.camera.position.y += (cameraOffset.y - engine.camera.position.y) * engine.cameraEase * timestep*60;
engine.camera.position.z += (cameraOffset.z - engine.camera.position.z) * engine.cameraEase * timestep*60;
// engine.camera.position.set(cycle.position.x, cycle.position.y, (10+cycle.speed));
// engine.camera.rotation.z = cycle.rotation.z;
engine.camera.lookAt(cycle.position);
break;
case 'cockpit':
/**/// cockpit
//if(cycle.speed > 2)
{
relativeCameraOffset = new THREE.Vector3(-2+(2.5*cycle.speed),0,0.5);
}
/*else
{
relativeCameraOffset = new THREE.Vector3(0.01,0,0.5);
}*/
cameraOffset = relativeCameraOffset.applyMatrix4(cycle.matrixWorld);
engine.camera.position.set(cycle.position.x,cycle.position.y,cycle.position.z+0.5);
//engine.camera.rotation.set(cycle.rotation.x,cycle.rotation.y,0);
// engine.camera.position.x += (cameraOffset.x - engine.camera.position.x) * 0.5;
// engine.camera.position.y += (cameraOffset.y - engine.camera.position.y) * 0.5;
// engine.camera.position.z = 2;
engine.camera.lookAt(cameraOffset);
//engine.camera.rotation.z = cycle.rotation.x+cycle.rotation.y;
// cycle.audio.gain.setTargetAtTime(0.2, ctx.currentTime, 0.02);
//cycle.textLabel.style.visibility = 'hidden';
//cycle.model.visible = false;
/*/
if (cycle.walls.children[cycle.walls.children.length-2]) {
cycle.walls.children[cycle.walls.children.length-1].visible = false;
cycle.walls.children[cycle.walls.children.length-2].visible = true;
}
/**/
break;
}
};
diff --git a/scripts/zone.js b/scripts/zone.js
index 05307e2..4c0d8cd 100644
--- a/scripts/zone.js
+++ b/scripts/zone.js
@@ -1,384 +1,389 @@
/*
* 3DCycles - A lightcycle game.
* Copyright (C) 2019 Glen Harpring
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-//if(typeof(THREE) == "undefined") var THREE = require('./lib/Three.js');
+if(this.require)
+{
+ if(typeof(THREE) == "undefined")
+ var THREE = require('./lib/Three.js');
+}
var flagColors = [ 0x55AAFF, 0xFFFF55, 0xFF5555, 0x55FF55, 0xFF55FF, 0x55FFFF, 0xFFFFFF, 0x888888];
class Zone
{
spawn()
{
engine.zones.add(this.mesh);
return this;
}
destroy()
{
engine.zones.remove(this.mesh);
return this;
}
constructor(prop)
{
this.timesEntered = 0; this.netObject = false;
this.type = prop.type||"null";
this.rotationSpeed = isNaN(prop.rot)?settings.ZONE_SPIN_SPEED:prop.rot;
this.value = prop.value||0;
this.expansion = prop.expansion||0;
this.radius = prop.radius||0;
this.xdir = prop.xdir||0; this.ydir = prop.ydir||0;
this.bounce = !!prop.bounce;
this.team = false;
var zoneHeight = prop.height||settings.ZONE_HEIGHT;
if (settings.ZONE_SEGMENTS < 1) { settings.ZONE_SEGMENTS = 11; }
var zoneSegments = (Math.floor(this.radius/10)*10)+1;
if (zoneSegments < 11) { zoneSegments = 11; }
var zoneColor = 0xFFFFFF;
if(prop.color || prop.color === 0)
{
zoneColor = prop.color;
}
else
{
switch(this.type)
{
case "death": zoneColor = 0xFF0000; break;
case "soccerball": zoneColor = 0xFF8888; break;
case "soccergoal": zoneColor = 0xBB6666; break;
case "rubber": zoneColor = 0xFFB033; break;
case "rubberadjust": zoneColor = 0xFF8800; break;
case "oneway": zoneColor = 0xFFFF00; break;
case "win": zoneColor = 0x00FF00; break;
case "target": zoneColor = 0x00DD00; break;
case "teleport": zoneColor = 0x00AA00; break;
case "speed": zoneColor = 0x00FF88; break;
case "acceleration": zoneColor = 0x00BB66; break;
case "blast": zoneColor = 0x0088FF; break;
case "fortress": case "flag":
var lastDist = Infinity;
var closestSpawn = 0;
if(engine.teams.length > 0)
{
for(var w=0;w 7) { zoneColor = 0x4488FF; }
- else { zoneColor = (this.type=="fortress"?teamColor:teamColor)(closestSpawn); }
+ else { zoneColor = (this.type=="fortress"?game.teamColor:game.teamColor)(closestSpawn); }
this.team = closestSpawn;
break;
case "object": zoneColor = 0xBB0066; break;
case "checkpoint": zoneColor = 0xFF0088; break;
case "koh": zoneColor = 0xDDDDDD; break;
case "wall": case "ball": zoneColor = 0xFFFFFF; break;
case "switch": zoneColor = 0x999999; break;
}
}
var color = typeof(zoneColor)=="object"?zoneColor:new THREE.Color(zoneColor), geo = new THREE.Geometry();
switch(prop.shape)
{
case "polygon":
var min = [Infinity,Infinity],
max = [-Infinity,-Infinity];
for(var i=0;i=0;z--)
{
if(point[z] < min[z]) min[z] = point[z];
if(point[z] > max[z]) max[z] = point[z];
console.log(point[z]);
}
}
for(var i=0,halfvert=(geo.vertices.length/2)-1;imin[1]?min[0]:min[1]);
this.shape = "polygon";
break;
default: //circle
var zoneSegCoords = [];//get the coordinates for each segment vertex
var zoneSegMidpoints = [];//get midpoints for each segment
var trueSegments = [];
for (var i = 0; i < settings.ZONE_SEGMENTS; i++)
{
var zpx = Math.cos(2 * Math.PI * i / settings.ZONE_SEGMENTS);
var zpy = Math.sin(2 * Math.PI * i / settings.ZONE_SEGMENTS);
zoneSegCoords.push({x:zpx, y:zpy});
if (i > 0 && i != settings.ZONE_SEGMENTS-1) {//all segments starting from the second
zoneSegMidpoints[i] = { x:((zoneSegCoords[i-1].x+zoneSegCoords[i].x)/2), y:((zoneSegCoords[i-1].y+zoneSegCoords[i].y)/2) };
}
else if (i == settings.ZONE_SEGMENTS-1) {//last segment + first
zoneSegMidpoints[i] = { x:((zoneSegCoords[i-1].x+zoneSegCoords[i].x)/2), y:((zoneSegCoords[i-1].y+zoneSegCoords[i].y)/2) };
zoneSegMidpoints[0] = { x:((zoneSegCoords[0].x+zoneSegCoords[i].x)/2), y:((zoneSegCoords[0].y+zoneSegCoords[i].y)/2) };
}
}
//with midpoints, determine segments
for (var s = 0; s < settings.ZONE_SEGMENTS; s++)
{
//var segmentFullLength = pointDistance( zoneSegCoords[s].x, zoneSegCoords[s].y, zoneSegCoords[s+1].x, zoneSegCoords[s+1].y );
//var adjustedSegLength = segmentFullLength * settings.ZONE_SEG_LENGTH;
if (s == 0) {
var np1x = (zoneSegMidpoints[0].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[zoneSegCoords.length-1].x - zoneSegMidpoints[0].x) ) );
var np1y = (zoneSegMidpoints[0].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[zoneSegCoords.length-1].y - zoneSegMidpoints[0].y) ) );
var np2x = (zoneSegMidpoints[0].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].x - zoneSegMidpoints[0].x) ) );
var np2y = (zoneSegMidpoints[0].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].y - zoneSegMidpoints[0].y) ) );
}
else {
var np1x = (zoneSegMidpoints[s].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s-1].x - zoneSegMidpoints[s].x) ) );
var np1y = (zoneSegMidpoints[s].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s-1].y - zoneSegMidpoints[s].y) ) );
var np2x = (zoneSegMidpoints[s].x + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].x - zoneSegMidpoints[s].x) ) );
var np2y = (zoneSegMidpoints[s].y + (settings.ZONE_SEG_LENGTH * ( zoneSegCoords[s].y - zoneSegMidpoints[s].y) ) );
}
trueSegments[s] = { x1:np1x, y1:np1y, x2:np2x, y2:np2y };
}
//have segment coordinates, now build it
for (var n = 0; n < trueSegments.length; n++) {
geo.vertices.push( new THREE.Vector3( (trueSegments[n].x1), (trueSegments[n].y1), 0) );
geo.vertices.push( new THREE.Vector3( (trueSegments[n].x2), (trueSegments[n].y2), 0) );
}
for (var n = 0; n < trueSegments.length; n++) {
geo.vertices.push( new THREE.Vector3( (trueSegments[n].x1), (trueSegments[n].y1), settings.ZONE_HEIGHT) );
geo.vertices.push( new THREE.Vector3( (trueSegments[n].x2), (trueSegments[n].y2), settings.ZONE_HEIGHT) );
}
for (var i = 0; i < (geo.vertices.length/2)-1; i+=2) {
geo.faces.push(
new THREE.Face3( (i), (i+1), (i+(geo.vertices.length/2)) ), //a,b,c
new THREE.Face3( (i+(geo.vertices.length/2)+1), (i+(geo.vertices.length/2)), (i+1) ) //d,c,b
);
}
this.shape = "circle";
break;
}
//var alpha = Math.max(color.r,color.g,color.b);
//color.r /= alpha; color.g /= alpha; color.b /= alpha;
if(!this.mat)
this.mat = new THREE.MeshBasicMaterial( { color: color, transparent: settings.ALPHA_BLEND, opacity: settings.ZONE_ALPHA/**alpha*/, side: THREE.DoubleSide } );
if(!this.mesh)
{
this.mesh = new THREE.Mesh(geo,this.mat);
this.mesh.cfg = this;
}
this.mesh.position.set(prop.x||0,prop.y||0,prop.z||0);
this.mesh.scale.set(this.radius||1,this.radius||1,1);
}
netSync()
{
if(window.svr)
{
var zone = {
id: engine.zones.children.indexOf(this.mesh),
x: this.mesh.position.x, y:this.mesh.position.y, z:this.mesh.position.z,
type:this.type, rotationSpeed:this.rot, value: this.value,
expansion:this.expansion, radius: this.radius,
xdir: this.xdir, ydir: this.ydir, bounce: this.bounce,
team: this.team, color: this.mesh.material.color.getHex(),
shape: this.shape,
};
if(this.type == "flagHeld") zone.heldBy = engine.players.indexOf(this.heldBy);
if(this.shape == "polygon")
{
zone.points = [];
for(var i=geo.faces.length-2;i>=0;i-=2)
{
var geo = this.mesh.geometry.clone(); geo.applyMatrix(this.mesh.matrix);
zone.points.push(geo.vertices[geo.faces[i].b].x,geo.vertices[geo.faces[i].b].y);
}
}
var data = JSON.stringify({type:"zone",data:[zone],gtime:engine.gtime});
window.svr.clients.forEach(function(ws){ws.send(data)});
}
return this;
}
distance(position)
{
switch(this.shape)
{
case "circle":
return pointDistance(this.mesh.position.x,this.mesh.position.y,position.x,position.y);
break;
case "polygon":
var min = Infinity, x, tmp, coords = this.mesh.geometry.vertices;
for(var i=(coords.length/2)-1;i>=0;x=(--i)-1)
{
if(coords[x] !== undefined)
{
tmp = distanceoflines(
coords[i].x,coords[i].y, coords[x].x,coords[x].y,
position.x,position.y, position.x,position.y
);
if(min > tmp) { min = tmp; }
}
}
return min;
break;
}
return Infinity;
}
onEnter(cycle,time)
{
switch(this.type)
{
case "wall":
cycle.position.x -= cycle.dir.front[0]*(engine.gtime-time);
cycle.position.y -= cycle.dir.front[1]*(engine.gtime-time);
break;
case "death":
cycle.kill();
engine.console.print(cycle.getColoredName()+"0xRESETT exploded on a deathzone.\n");
break;
case "win":
if(engine.winner == undefined && engine.declareRoundWinner == undefined)
{
//engine.console.print(cycle.getColoredName()+"0xRESETT ");
this.expansion = -1;
engine.declareRoundWinner = cycle.name;
}
break;
case "target":
loadcfg(settings.DEFAULT_TARGET_COMMAND.replace(/\\n/g,"\n"));
cycle.addScore(settings.TARGET_INITIAL_SCORE);
break;
}
}
onInside(cycle,time,timestep)
{
switch(this.type)
{
case "rubber":
cycle.rubber += timestep*this.value;
if(cycle.rubber >= settings.CYCLE_RUBBER)
{
cycle.kill();
engine.console.print(cycle.getColoredName()+"0xRESETT exploded on a rubberzone.\n");
}
break;
case "fortress":
if(engine.gtime > 0)
{
if(settings.BASE_RESPAWN)
{
engine.teams[this.team].spawn(true,true,false);
}
if(this.team == engine.teams.indexOf(cycle.team))
{
+ this.lastContact = engine.gtime;
}
else
{
this.rotationSpeed += timestep*settings.FORTRESS_CONQUEST_RATE;
if(this.rotationSpeed > settings.ZONE_SPIN_SPEED*16)
{
engine.console.print(cycle.getColoredName()+"0xRESETT conquered a fortress zone.\n");
this.type = "null"; this.expansion = -10;
engine.declareRoundWinner = cycle.name;
}
}
}
break;
case "ball": case "soccerball":
var mindirx=0,mindiry=0,mindist=Infinity,apc=0;
for(var i=359;i>0;i--)
{
var xdir = Math.cos(Math.PI*2*(i/360)), ydir=Math.sin(Math.PI*2*(i/360));
var xpos = xdir*this.radius+this.mesh.position.x, ypos=ydir*this.radius+this.mesh.position.y;
var dist = pointDistance(xpos,ypos,cycle.position.x,cycle.position.y);
if(dist < mindist)
{
/*if(mindist == Infinity)mindist = dist; else mindist += dist;
mindirx -= xdir; mindiry -= ydir;
apc++;*/
mindist=dist;mindirx=xdir;mindiry=ydir;apc=1;
}
}
//mindist /= apc; mindirx /= apc; mindiry /= apc;
if(mindist != Infinity)
{
this.xdir = -mindirx*cycle.speed; this.ydir = -mindiry*cycle.speed;
if(!this.bounce) this.bounce = true;
this.lastHitCycle = cycle;
this.netSync();
}
break;
case "speed":
cycle.speed = this.value||0;
break;
case "acceleration":
accel = (this.value||0); cycle.accel += accel;
cycle.speed += cycle.speed*accel;
break;
case "flag":
if(!engine.network && !cycle.hasFlag && engine.teams.indexOf(cycle.team) != this.team)
{
engine.console.print(cycle.getColoredName()+"0xRESETT picked up "+engine.teams[this.team].name+"0xRESETT's flag.\n");
cycle.hasFlag = this;
this.type = "flagHeld";
this.heldBy = cycle;
if(!this.px) this.px = this.mesh.position.x;
if(!this.py) this.py = this.mesh.position.y;
this.mesh.position.set(cycle.position.x,cycle.position.y,0);
this.netSync();
}
break;
}
}
onLeave(cycle,time)
{
}
onOutside(cycle,time)
{
-
+
}
}
if(typeof(module) != "undefined") module.exports = Zone;