diff --git a/index.html b/index.html
index 8cfca13..1bb8a88 100644
--- a/index.html
+++ b/index.html
@@ -1,131 +1,136 @@
3DCycles
+
+
+
+
+
Say:
3DCycles is loading...
FPS :
(,)
F:
F:s
L:
L:s
R:
R:s
Name: | Alive: | Score: | Ping: | Team: |
diff --git a/layout/menu.xml b/layout/menu.xml
index 2de20b6..da83f08 100644
--- a/layout/menu.xml
+++ b/layout/menu.xml
@@ -1,314 +1,315 @@
diff --git a/scripts/input.js b/scripts/input.js
index 5c3ace9..52e9efd 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();
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();
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.keyCode == 27)
+ 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();
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();
}
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 8773f8a..dbb72c4 100644
--- a/scripts/menu.js
+++ b/scripts/menu.js
@@ -1,457 +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