Page MenuHomePhabricator

No OneTemporary

diff --git a/layout/menu.xml b/layout/menu.xml
index 9e5a57e..dfa631c 100644
--- a/layout/menu.xml
+++ b/layout/menu.xml
@@ -1,335 +1,335 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Menus>
<Menu id="firsttime" title="Welcome to @progtitle@!
&lt;div style='font-size:17pt'>Please choose some initial settings:&lt;/div>">
<Item type="list" call="init_key" text="Keyset">
<Option value="-1" text="Don't Touch!" />
<Option value="0" text="Home row" /> <!--(ASDF for left and JKL; for right)-->
<Option value="1" text="WASD/Arrows" />
</Item>
<Item type="list" call="init_color" text="Initial Color">
<Option value="0" text="0xff0000Red" />
<Option value="1" text="0xff8800Orange" />
<Option value="2" text="0xffff00Yellow" />
<Option value="3" text="0x00ff00Green" />
<Option value="4" text="0x00ffffCyan" />
<Option value="5" text="0x0000ffBlue" />
<Option value="6" text="0xff00ffViolet" />
</Item>
<Item type="str" var="player.name" text="Name"/>
<Item type="exitmenu" text="Let's go!"/>
</Menu>
<Menu id="main" title="@progtitle@ Alpha">
<Item type="submenu" onenter="game" text="Play"/>
<Item type="submenu" onenter="player" text="Customize Player"/>
<Item type="submenu" onenter="input" text="Configure Input"/>
<Item type="submenu" onenter="system" text="Configure 3DCycles"/>
<Item type="submenu" onenter="about" text="About"/>
<!-- <Item type="submenu" onenter="egg" text="&lt;- Go Back"/> -->
<!-- alt: <Item type="text" text="" /> <!- - no exit game function, escape will do nothing -->
<Item type="js" onenter="menu('quit')" text="Quit"/>
</Menu>
<!-- General game configuration -->
<Menu id="game" title="Play Game">
- <Item type="js" onenter="playGame()" style="display:inline-block;" text="Locally"/>
+ <Item type="js" onenter="game.play()" style="display:inline-block;" text="Locally"/>
<Item type="submenu" onenter="game_setup" style="font-size:16pt;" text="(config)"/>
<Item type="submenu" onenter="network" text="Network"/>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="network" title="Network Game">
<Item type="str" var="CONNECT_HOST" text="Host" />
<Item type="num" range="1024,49151" var="CONNECT_PORT" text="Port" />
<Item type="list" var="CONNECT_SSL" text="SSL">
<Option value="false" text="No" /> <Option value="true" text="Yes" />
</Item>
<Item type="js" onenter="connectToGame()" text="Connect"/>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="connect" title="Connecting...">
<Item type="text" text="" from="con:last" style="font-size:14pt;text-align:left;padding:10px;color:grey" />
<Item type="leave" text="&lt;- Cancel"/>
</Menu>
<Menu id="connectfail" title="Connection Failure">
<Item type="text" text="" from="con:last" style="font-size:11pt;text-align:left;padding:10px" />
<Item type="leave" text="&lt;- Okay"/>
</Menu>
<Menu id="connectterm" title="Connection Terminated">
<Item type="text" text="" from="con:last" style="font-size:11pt;text-align:left;padding:10px" />
<Item type="leave" text="&lt;- Okay"/>
</Menu>
<Menu id="game_setup" title="Local Game Config" if="not engine.network">
<Item type="submenu" onenter="presets" text="Load Preset..."/>
<Item type="num" range="0,Infinity" var="TEAMS_MIN" text="Min Teams (# of Humans+AIs)" />
<Item type="list" var="GAME_TYPE" text="When the round finishes">
<Option value="0" text="Keep the round going" />
<Option value="1" text="End the round" />
</Item>
<Item type="list" var="FINISH_TYPE" text="When only AIs remain">
<Option value="1" text="Have AIs win" />
<Option value="2" text="Fast finish" />
<Option value="3" text="Find winner (alpha)" />
</Item>
<Item type="num" range="-20,15" var="SIZE_FACTOR" text="Arena Size" />
<Item type="num" range="0,Infinity" var="CYCLE_SPEED" text="Cycle Speed" />
<Item type="num" range="0,Infinity" var="CYCLE_RUBBER" text="Cycle Rubber" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<!--<Menu id="presets" title="Load Preset">
<Item type="js" onenter="preset('classic');menu('exitmenu');menu('exitmenu')" text="Classic"/>
<Item type="js" onenter="preset('df');menu('menu:loading')" text="Dogfight"/>
<Item type="js" onenter="preset('hr');menu('menu:loading')" text="High Rubber"/>
<Item type="js" onenter="preset('ft');menu('menu:loading')" text="Fast Track"/>
<Item type="js" onenter="preset('fort');menu('menu:loading')" text="Fortress"/>
<Item type="js" onenter="preset('racing');menu('menu:loading')" text="Racing"/>
<Item type="js" onenter="preset('zonetest');menu('exitmenu');menu('exitmenu')" text="Zone test"/>
<Item type="exitmenu" text="Cancel"/>
</Menu>-->
<Menu id="presets" title="Load Preset">
<Item type="js" style="font-size:14pt" onenter="preset('classic');menu('exitmenu');menu('exitmenu')"
text="Classic" title="Default low rubber settings in Armagetron"/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('df')"
text="Loose Dogfight" title="Obey loose dogfight rules or go elsewhere!"/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('hr')"
text="0x0000ff-=}0xffffffID0x0000ff&lt; 0xffff00T0x00ff00I0xffff00L0x00ff00T 0x0000ffHigh Rubber0x00ff00" title="No camping!"/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('ft')"
text="0xc0c000&gt;&gt;&gt; 0xff0000F0xff1c1cA0xff3838S0xff5555T0xff7171T0xff8d8dR0xffaaaaA0xffc6c6C0xffe2e2K 0xc0c000&lt;&lt;&lt;" title="Gotta go fast! Very fast!"/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('fort')"
text="Fortress" title="Take the enemy's base, try not to let them take yours."/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('ctf')"
text="Capture the Flag" title="Take the enemy's flag, try not to let them take yours."/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('styball')"
text="Styball (Soccer / Hockey)" title="Push the ball into the enemy's base, but don't let them push it into yours!"/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('racing')"
text="0x66cc66Adventures of 0x00cc00TRON 0xffffff>> Advanced Racing &lt;&lt;" title="First to the finish line wins!"/>
<Item type="js" style="font-size:14pt" onenter="menu('menu:loading');preset('snake')"
text="0x66ccffSnake Survival" title="How long can you get your trail?"/>
<Item type="js" style="font-size:14pt" onenter="preset('zonetest');menu('exitmenu');menu('exitmenu')"
text="Zone test" title="Zones! Zones! Zones! Zones everywhere!"/>
<Item type="exitmenu" text="Cancel" title="Never mind, none of these look interesting..."/>
</Menu>
<Menu id="loading" title="Loading...">
<Item type="text" text="" from="con:last" style="font-size:14pt;text-align:left;padding:10px;color:grey" />
</Menu>
<!-- Player configuration -->
<Menu id="player" title="Player Setup">
<Item type="str" var="player.name" text="Name"/>
<Item type="submenu" onenter="macro" text="Instant Chats"/>
<Item type="color" var="player.cycleColor" text="Cycle Color" />
<Item type="color" var="player.tailColor" text="Tail Color" />
<!--<Item type="num" range="0,5" var="player.engineType" text="Engine Type" />-->
<Item type="list" var="player.spectating" text="Spectator Mode">
<Option value="false" text="Off" /> <Option value="true" text="On" />
</Item>
<Item type="js" onenter="exportUsrSets()" text="Export player settings" />
<Item type="js" onenter="importSets()" text="Import settings" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="macro" title="Instant Chats">
<!--<Foreach var="instantchats" as="n">
<Item type="str" var="instantchats.$(n).text" text="Chat"/>
<Item type="keys" var="instantchats.$(n).input" text="Input" />
<Item type="text" text="&amp;nbsp;" />
</Foreach>-->
<Item type="str" var="instantchats.0.text" text="Chat"/>
<Item type="keys" var="instantchats.0.input" text="Input" />
<Item type="text" text="&amp;nbsp;" />
<Item type="str" var="instantchats.1.text" text="Chat"/>
<Item type="keys" var="instantchats.1.input" text="Input" />
<Item type="text" text="&amp;nbsp;" />
<Item type="str" var="instantchats.2.text" text="Chat"/>
<Item type="keys" var="instantchats.2.input" text="Input" />
<Item type="text" text="&amp;nbsp;" />
<Item type="str" var="instantchats.3.text" text="Chat"/>
<Item type="keys" var="instantchats.3.input" text="Input" />
<Item type="text" text="&amp;nbsp;" />
<Item type="js" onenter="" text="Add instant chat (future)" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="input" title="Configure Input">
<Item type="submenu" onenter="input_conf" text="Player Control"/>
<Item type="submenu" onenter="global_input_conf" text="Global Input"/>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="input_conf" title="Player Input">
<Item type="keys" var="left" text="Turn left" />
<Item type="keys" var="right" text="Turn right" />
<!--<Item type="keys" var="north" text="Turn North" />
<Item type="keys" var="south" text="Turn South" />
<Item type="keys" var="east" text="Turn East" />
<Item type="keys" var="west" text="Turn West" />-->
<Item type="keys" var="boost" text="Boost" />
<Item type="keys" var="toggleboost" text="Toggle Boost" />
<Item type="keys" var="brake" text="Brake" />
<Item type="keys" var="togglebrake" text="Toggle Brake" />
<Item type="keys" var="jump" text="Jump" />
<Item type="keys" var="chat" text="Chat" />
<Item type="keys" var="camera" text="Switch View" />
<Item type="keys" var="look_left" text="Look Left" />
<Item type="keys" var="look_right" text="Look Right" />
<Item type="keys" var="look_forward" text="Look Forward" />
<Item type="keys" var="look_back" text="Look Back" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<!-- Configuration -->
<Menu id="system" title="System Setup">
<Item type="submenu" onenter="screen" text="Configure Display"/>
<Item type="submenu" onenter="display" text="Configure Visuals"/>
<Item type="submenu" onenter="sound" text="Configure the Sound"/>
<Item type="submenu" onenter="other" text="Misc Settings"/>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="screen" title="Screen Mode">
<Item type="list" call="settings.FULLSCREEN" text="Fullscreen (F11)" title="It's recommended that you use F11 instead of this fullscreen option. It is, however, left in for mobile touchscreen devices.">
<Option value="false" text="Off" /> <Option value="true" text="On" />
</Item>
<Item type="list" var="REDRAW_MODE" text="VSync" title="Synchronize framerate with vertical refresh rate\nThe vertical refresh rate is basically the frames per second your monitor displays. Turning this on would make it depend on browser redraw calls, effectively capping your FPS at the refresh rate. Turning it off would continously draw the frames but throws away additional frames that your monitor doesn't display. Depending on game loop configuration, this can provide minimal advantage.">
<Option value="1" text="Off" /> <Option value="0" text="On" />
</Item>
<Item type="num" range="1,Infinity" var="MAX_TARGET_FPS" text="Max Target FPS" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="display" title="Visual Settings">
<Item type="submenu" onenter="detail" text="Detail Settings"/>
<Item type="submenu" onenter="visual_prefs" text="Other Preferences"/>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="detail" title="Detail Settings">
<Item type="list" var="FLOOR_DETAIL" text="Floor Detail" title="">
<Option value="0" text="No Grid" />
<Option value="1" text="Line Grid" />
<Option value="2" text="Textured Floor (Standard quality)" />
<Option value="3" text="Textured Floor (Maximum quality)" />
</Item>
<Item type="list" call="aamenurender_nocallonreq" text="Menu Background Rendering" title="How the background is rendered. Default: Image">
<Option value="img" text="Image" />
<Option value="css" text="CSS" />
<Option value="css_rot" text="CSS+Rotation" />
</Item>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="visual_prefs" title="Preferences">
<Item type="list" var="HIGH_RIM" text="High Rims">
<Option value="false" text="Off" /> <Option value="true" text="On" />
</Item>
<Item type="list" var="EXPLOSION" text="Explosions">
<Option value="false" text="Off" /> <Option value="true" text="On" />
</Item>
<Item type="list" var="engine.view" from="engine.views" text="Current Camera" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="sound" title="Sound Configuration">
<Item type="list" var="player.engineType" text="Sound set">
<Option value="5" text="ArmagetronAd" />
<Option value="3" text="Tr2n Origins" />
<Option value="4" text="glTron" />
</Item>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="other" title="Misc Configuration">
<Item type="submenu" onenter="display_tweaks" text="Tweaks"/>
<Item type="submenu" onenter="global_input_conf" text="Global Keys"/>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="display_tweaks" title="Game Tweaks">
<Item type="list" var="GAME_LOOP" text="Run game loop">
<Option value="0" text="Outside render cycle" />
<Option value="2" text="Outside+during render cycle" title="possibily reduces fps?" />
<Option value="0.5" text="Outside render cycle + cycle movement in render" title="may reduce visible jumps, the default" />
<Option value="1" text="During render cycle" title="may reduce jumps but increase lag"/>
</Item>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="global_input_conf" title="Input Configuration">
<Item type="keys" var="scroll_up" text="Scroll Up" />
<Item type="keys" var="scroll_down" text="Scroll Down" />
<Item type="keys" var="scroll_end" text="Scroll to End" />
<Item type="keys" var="score" text="Toggle Scoreboard" />
<Item type="keys" var="esc" text="In-game Menu" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="about" title="About">
<Item type="text" style="font-size:15pt" text="0xff8800Title: 0xRESETT@progtitle@" />
<Item type="text" style="font-size:15pt" text="Draws heavy inspiration from the excellent lightcycle game Armagetron Advanced." />
<Item type="text" style="font-size:15pt" text="0xff8800Version: 0xRESETTv1.0-beta6" />
<Item type="text" style="font-size:15pt" text="This is a development version. It's a heavy work in progress. Anything could change at any time, and there may be a lot of bugs." />
<Item type="submenu" onenter="about_dev" text="Credits"/>
<Item type="submenu" onenter="license" text="Legal Stuff"/>
<!--<Item type="text" text="0xff7f00Official Website: 0xRESETTN/A" />-->
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="about_dev" title="Credits">
<Item type="text" style="font-size:15pt" text="0xff8800Project Admin: 0xRESETTNelg" />
<Item type="text" style="font-size:15pt" text="0xff8800Developers: 0xRESETTNelg, Durf" />
<Item type="text" style="font-size:15pt" text="0xff8800Collision Detection: 0xRESETTDurf, softSurfer" />
<Item type="text" style="font-size:15pt" text="0xff8800ArmagetronAd Font: 0xRESETTLucifer, Fabrice Holbe" />
<Item type="text" style="font-size:15pt" text="0xRESETTDefault Theme:" />
<Item type="text" style="font-size:15pt" text="0xff8800Wall Textures: 0xRESETTBrian Hilmers" />
<Item type="text" style="font-size:15pt" text="0xff8800Textures: 0xRESETTthe Armagetron Advanced development team" />
<Item type="text" style="font-size:15pt" text="0xff8800ArmagetronAd Cycles: 0xRESETTZ-Man(?)" />
<!--<Item type="text" style="font-size:15pt" text="0xff8800Testing: 0xRESETTdukevin, light, jericho, zoom" />-->
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="license" title="Legal Stuff">
<Item type="text" style="font-size:15pt" text="3DCycles - A lightcycle game. &lt;br>
Copyright (C) 2019 Glen Harpring &lt;br> &lt;br>
This program is free software; you can redistribute it and/or &lt;br>
modify it under the terms of the GNU General Public License &lt;br>
as published by the Free Software Foundation; either version 2 &lt;br>
of the License, or (at your option) any later version. &lt;br>
&lt;br>
This program is distributed in the hope that it will be useful, &lt;br>
but WITHOUT ANY WARRANTY; without even the implied warranty of &lt;br>
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the &lt;br>
GNU General Public License for more details. &lt;br>
&lt;br>
You should have received a copy of the GNU General Public License &lt;br>
along with this program; if not, write to the Free Software &lt;br>
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA." />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="pause" title="Paused" exitmenu="pauseMenuToggle()">
<Item type="submenu" onenter="game_setup" text="Local Game Setup"/>
<Item type="submenu" onenter="team" text="Change Teams"/>
<Item type="submenu" onenter="player" text="Customize Player"/>
<Item type="submenu" onenter="input" text="Configure Input"/>
<Item type="submenu" onenter="system" text="Configure 3DCycles"/>
<Item type="submenu" onenter="about" text="About"/>
<Item type="leave" text="Leave Grid"/>
<Item type="exitmenu" text="Return to Game"/>
</Menu>
<Menu id="team" title="Change Teams">
<!-- script to dynamically generate items-->
<Item type="list" var="player.spectating" text="Spectator Mode" onenter="KILL_ALL">
<Option value="false" text="Off" /> <Option value="true" text="On" />
</Item>
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="vote" title="Vote" exitmenu="menu('exitmenu');vote(voteopt)"> <!--Future implementation?-->
<Item type="list" call="function(in){voteopt = in; return '';}" text="Vote">
<Option value="no" text=" No &gt;" />
<Option value="" text="&lt; Ignore &gt;" />
<Option value="yes" text="&lt; Yes " />
</Item>
<Item type="exitmenu" text="Submit"/>
</Menu>
<Menu id="highscores" title="0x000000Highscores">
<Item type="text" text="0xff0000»0x808080Swag´0xRESETT: INF points" />
<Item type="text" text="0x0088ff|0xRESETTNelg0xRESETT: 10 points" />
<Item type="text" text="0x00ff00Z-Man0xRESETT: 1 points" />
<Item type="exitmenu" text="&lt;- Go Back"/>
</Menu>
<Menu id="preset_loaded" title="Preset Loaded">
- <Item type="js" onenter="playGame()" text="Play"/>
+ <Item type="js" onenter="game.play()" text="Play"/>
<Item type="submenu" onenter="input_conf" text="Set Controls"/>
<Item type="exitmenu" text="Back to main menu"/>
</Menu>
</Menus>
diff --git a/scripts/functions-body.js b/scripts/functions-body.js
index 21ef668..69d3c13 100644
--- a/scripts/functions-body.js
+++ b/scripts/functions-body.js
@@ -1,472 +1,450 @@
/*
* 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;
-
-function getPlayer(name)
+global.getPlayer = function(name)
{
name = removeColors(name).filter();
var matches = [];
for(var i=engine.players.length-1;i>=0;--i) if(engine.players[i])
{
if(engine.players[i].getBoringName().filter() == name)
{
return engine.players[i];
}
else if(engine.players[i].getBoringName().filter().indexOf(name) > -1)
{
matches.push(i);
}
}
if(matches.length > 1)
{
engine.console.print("Too many matches for "+name+". Try something more exact to narrow down the search.\n");
}
else if(matches.length < 1)
{
engine.console.print("No matches for "+name+". Try a different name.\n");
}
else
{
return engine.players[matches[0]];
}
}
function retToLastSafe(cycle,w1x,w1y,w2x,w2y)
{
var dist = distanceoflines(cycle.position.x,cycle.position.y,cycle.position.x,cycle.position.y,w1x,w1y,w2x,w2y);
console.warn(cycle.name+" phased through a wall "+dist+"m.\n");
//if(dist == 0) return;
dist -= settings.CYCLE_RUBBER_MINDISTANCE;
cycle.position.x -= cycle.lastdir.front[0]*dist; cycle.position.y -= cycle.lastdir.front[1]*dist;
if(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y))
{
//cycle.position.x += cycle.lastdir.front[0]*(dist*2); cycle.position.y += cycle.lastdir.front[1]*(dist*2);
//if(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y))
{
var dist = distanceoflines(cycle.lastpos.x,cycle.lastpos.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y);
dist -= settings.CYCLE_RUBBER_MINDISTANCE;
cycle.position.x = cycle.lastpos.x+
(cycle.lastdir.front[0]*dist)/*+
(cycle.lastsensor.left*cycle.lastdir.left[0])+
(cycle.lastsensor.right*cycle.lastdir.right[0])*/;
cycle.position.y = cycle.lastpos.y+
(cycle.lastdir.front[1]*dist)/*+
(cycle.lastsensor.left*cycle.lastdir.left[1])+
(cycle.lastsensor.right*cycle.lastdir.right[1])*/;
/*while(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y))
{
cycle.position.x -= (1/1000)*cycle.lastdir.front[0];
cycle.position.y -= (1/1000)*cycle.lastdir.front[1];
}
cycle.collidetime = 0; cycle.lastspeed = 0;*/
if(lineIntersect(cycle.position.x,cycle.position.y,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y))
{
if(engine.network)
{
//request new cycle trails
}
else
{
doDeath(cycle);
engine.console.print(cycle.name+" phased through a wall and has been terminated.\n");
}
}
else
{
cycle.rubber += cycle.speed;
cycle.sensor.front = settings.CYCLE_RUBBER_MINDISTANCE;
}
}
}
else
{
cycle.rubber += cycle.speed;
cycle.sensor.front = settings.CYCLE_RUBBER_MINDISTANCE;
}
if(engine.haswall) recalcCurrWall(cycle);
}
-function getCycleSensors(full=false)
+global.getCycleSensors = function(full=false)
{
var oneline = "";
var range = settings.CYCLE_SENSORS_RANGE;
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x] !== undefined)
{
//if(full)
{
engine.players[x].sensor.left = engine.players[x].sensor.right =
engine.players[x].sensor.leftTurn = engine.players[x].sensor.rightTurn =
engine.players[x].sensor.front =
engine.players[x].sensor.rear = Infinity;
engine.players[x].sensor.nearestobj =
engine.players[x].sensor.lnearestobj = false;
engine.players[x].sensor.rnearestobj = false;
}
engine.players[x].sensor.bottom = 0;
engine.players[x].sensor.frontWallHeight = Infinity;
engine.players[x].sensor.objleft =
engine.players[x].sensor.objright =
engine.players[x].sensor.objfront =
engine.players[x].sensor.objrear = false;
engine.players[x].sensor.nearcycle = false;
engine.players[x].dir.front = cdir(engine.players[x].rotation.z);
engine.players[x].dir.left = cdir(engine.players[x].rotation.z+(Math.PI/2));
engine.players[x].dir.right = cdir(engine.players[x].rotation.z-(Math.PI/2));
engine.players[x].dir.leftTurn = cdir(engine.players[x].rotation.z+(Math.PI/(settings.ARENA_AXES*0.5)));
engine.players[x].dir.rightTurn = cdir(engine.players[x].rotation.z-(Math.PI/(settings.ARENA_AXES*0.5)));
}
for(var x=engine.zones.children.length-1;x>=0;--x)
{
engine.zones.children[x].walldist = Infinity;
engine.zones.children[x].wall = [0,0,0,0];
}
if(!engine.dedicated) var campos = engine.camera.position, ppos = engine.players[engine.viewTarget].position;
for(var y=engine.map.walls.length-1;y>=0;--y)
{
//console.log("ohi");
var lookThroughWall = false;
for(var i=engine.map.walls[y].length-1;i>=0;--i)
{
var w1x = engine.map.walls[y][i][0], w1y = engine.map.walls[y][i][1], p=engine.map.walls[y][i+1];
if(p !== undefined)
{
var w2x = p[0], w2y = p[1]/*,w2z = p[2]*/;
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x] !== undefined && engine.players[x].alive)
{
var cycle = engine.players[x];
var posx = cycle.position.x, posy = cycle.position.y, posz = cycle.position.z;
if(lineIntersect(posx,posy,cycle.lastpos.x,cycle.lastpos.y,w1x,w1y,w2x,w2y))
{
retToLastSafe(cycle,w1x,w1y,w2x,w2y);
}
else
{
var dir = engine.players[x].dir.front,
ldir = engine.players[x].dir.left,
rdir = engine.players[x].dir.right
ltdir = engine.players[x].dir.leftTurn,
rtdir = engine.players[x].dir.rightTurn;
var rg = /*cycle.sensor.front==Infinity?*/(cycle.speed*range);//:cycle.sensor.front;
//var output = pointLineDistance(w1x,w1y,w2x,w2y,posx,posy);
//var testx = (w2x-w1x)*dir[0], testy = (w2y-w1y)*dir[1], tpx = posx*(-dir[0]), tpy = posy*(-dir[1]);
//if(cycle == engine.players[engine.viewTarget]) oneline += ""+(w2x-w1x)+"\t\t\t\t\t\t\t"+posx+"\t\t\t\t\t\t\t"+(w2x-w1x)+"\t\t\t\t\t\t\t"+posy+";\n";
//if(((w2x+w1x)/2) >= posy*dir[0] && ((w2y+w1y)/2) >= posx*dir[1])
//if(isinfront(w1x,w1y,w2x,w2y,posx,posy,dir))
coord = [w1x,w1y,w2x,w2y];
if(lineIntersect(posx,posy,posx+(dir[0]*rg),posy+(dir[1]*rg),w1x,w1y,w2x,w2y))
{
//var ff = distanceoflines(posx,posy,posx+(dir[0]/6),posy+(dir[1]/6),w1x,w1y,w2x,w2y);
var ff = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y);
/*forward = Math.min(forward,ff);
if(ff == forward) type = "rim";//*/
if(ff < cycle.sensor.front) { cycle.sensor.front=ff; cycle.sensor.nearestobj = "rim";}
}
else if(lineIntersect(posx,posy,posx+(ldir[0]*rg),posy+(ldir[1]*rg),w1x,w1y,w2x,w2y))
{
var ll = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y);
if(ll < cycle.sensor.left) { cycle.sensor.left=ll; cycle.sensor.lnearestobj = "rim";}
}
else if(lineIntersect(posx,posy,posx+(rdir[0]*rg),posy+(rdir[1]*rg),w1x,w1y,w2x,w2y))
{
var rr = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y);
if(rr < cycle.sensor.right) { cycle.sensor.right=rr; cycle.sensor.rnearestobj = "rim";}
}
if(lineIntersect(posx,posy,posx+(ltdir[0]*rg),posy+(ltdir[1]*rg),w1x,w1y,w2x,w2y))
{
var ll = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y);
if(ll < cycle.sensor.leftTurn) { cycle.sensor.leftTurn=ll; }
}
else if(lineIntersect(posx,posy,posx+(rtdir[0]*rg),posy+(rtdir[1]*rg),w1x,w1y,w2x,w2y))
{
var rr = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y);
if(rr < cycle.sensor.rightTurn) { cycle.sensor.rightTurn=rr;}
}
/*
if(((w2x+w1x)/2) >= posy*ldir[0] && ((w2y+w1y)/2) >= posx*ldir[1])
{
var ll = distanceoflines(posx,posy,posx+(ldir[0]),posy+(ldir[1]),w1x,w1y,w2x,w2y);
left = Math.min(left,ll);
}
if(((w2x+w1x)/2) >= posy*rdir[0] && ((w2y+w1y)/2) >= posx*rdir[1])
{
var rr = distanceoflines(posx,posy,posx+(rdir[0]),posy+(rdir[1]),w1x,w1y,w2x,w2y);
right = Math.min(right,rr);
}
*/
}
}
for(var x=engine.zones.children.length-1;x>=0;--x)
{
var zone = engine.zones.children[x];
var posx = zone.position.x, posy = zone.position.y;
var walldist = distanceoflines(posx,posy,posx,posy,w1x,w1y,w2x,w2y)-zone.cfg.radius;
if(walldist < zone.walldist)
{
zone.walldist = walldist;
zone.wall[0]=w1x;zone.wall[1]=w1y;zone.wall[2]=w2x;zone.wall[3]=w2y;
}
}
if(!engine.dedicated && !lookThroughWall) lookThroughWall = (engine.walls.children[y]&&engine.walls.children[y].geometry.vertices[engine.walls.children[y].geometry.vertices.length-1].z) > campos.z && lineIntersect(campos.x,campos.y,ppos.x,ppos.y,w1x,w1y,w2x,w2y);
}
}
if(!engine.dedicated && engine.walls.children[y]) engine.walls.children[y].visible = !lookThroughWall;
}
for(var a=engine.players.length-1;a>=0;--a) if(engine.players[a] !== undefined)
{
var walls = engine.players[a].walls.map;
var len = walls.length;
for(var i=len-1;i>=0;--i)
{
var p1 = walls[i];
//var w1x = p1[0],w1y = p1[1],w1z = p1[2];
if(walls[i+1] !== undefined)
{
var p2 = walls[i+1];
//var w2x = p2[0],w2y = p2[1],w2z = p2[2];
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x] !== undefined && engine.players[x].alive)
{
//var cycle = engine.players[x];
//var isplayer = (engine.players[a] == engine.players[x]);
if(engine.players[a] != engine.players[x] || i <= len-(settings.ARENA_AXES))
{
//var posx = engine.players[x].position.x, posy = engine.players[x].position.y, posz = engine.players[x].position.z;
if(p1[2]||0 <= engine.players[x].position.z && (p1[2]||0)+1 >= engine.players[x].position.z)
{
if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].lastpos.x,engine.players[x].lastpos.y,p1[0],p1[1],p2[0],p2[1]))
{
retToLastSafe(engine.players[x],p1[0],p1[1],p2[0],p2[1]);
}
else
{
var dir = engine.players[x].dir.front,
ldir = engine.players[x].dir.left,
rdir = engine.players[x].dir.right,
ltdir = engine.players[x].dir.leftTurn,
rtdir = engine.players[x].dir.rightTurn;
//var rg = engine.players[x].sensor.front==Infinity?(engine.players[x].speed*range):engine.players[x].sensor.front;
//if(engine.players[x].sensor.front==Infinity)
var rg=engine.players[x].speed*range;//else var rg=engine.players[x].sensor.front;
//if(!(engine.players[x].position.x == p2[0] && engine.players[x].position.y == p2[1]))
{
if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(dir[0]*rg),engine.players[x].position.y+(dir[1]*rg),p1[0],p1[1],p2[0],p2[1]))
{
var ff=distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]);
/*forward = Math.min(forward,ff);
if(ff == forward) type = engine.players[x];//*/
if(ff < engine.players[x].sensor.front)
{
engine.players[x].sensor.front=ff;
engine.players[x].sensor.nearestobj = engine.players[a];
if(engine.players[a] != engine.players[x])
{
engine.players[x].sensor.lastnonselfobj = engine.players[a];
}
}
}
else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(ldir[0]*rg),engine.players[x].position.y+(ldir[1]*rg),p1[0],p1[1],p2[0],p2[1]))
{
var ll = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]);
if(ll < engine.players[x].sensor.left)
{
engine.players[x].sensor.left=ll;
engine.players[x].sensor.lnearestobj = engine.players[a];
engine.players[x].sensor.objleft = engine.players[a];
}
}
else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(rdir[0]*rg),engine.players[x].position.y+(rdir[1]*rg),p1[0],p1[1],p2[0],p2[1]))
{
var rr = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]);
if(rr < engine.players[x].sensor.right)
{
engine.players[x].sensor.right=rr;
engine.players[x].sensor.rnearestobj =
engine.players[x].sensor.objright = engine.players[a];
}
}
else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(-dir[0]*rg),engine.players[x].position.y+(-dir[1]*rg),p1[0],p1[1],p2[0],p2[1]))
{
var bb=distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]);
if(bb < engine.players[x].sensor.rear)
{
engine.players[x].sensor.rear=bb;
engine.players[x].sensor.objrear = engine.players[a];
}
}
if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(ltdir[0]*rg),engine.players[x].position.y+(ltdir[1]*rg),p1[0],p1[1],p2[0],p2[1]))
{
var ll = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]);
if(ll < engine.players[x].sensor.leftTurn) { engine.players[x].sensor.leftTurn=ll;}
}
else if(lineIntersect(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x+(rtdir[0]*rg),engine.players[x].position.y+(rtdir[1]*rg),p1[0],p1[1],p2[0],p2[1]))
{
var rr = distanceoflines(engine.players[x].position.x,engine.players[x].position.y,engine.players[x].position.x,engine.players[x].position.y,p1[0],p1[1],p2[0],p2[1]);
if(rr < engine.players[x].sensor.rightTurn) { engine.players[x].sensor.rightTurn=rr;}
}
}
}
}
}
}
}
}
}//*/
/*for(var x=engine.map.zones.length-1;x>=0;--x)
{
var zone = engine.map.zones[x];
for(var y=engine.players.length-1;y>=0;--y) if(engine.players[y] !== undefined)
{
var ff = Math.sqrt(((zone[1]-p2x)**2)+((zone[2]-p2y)**2))-zone[3];
if(ff < cycle.sensor.front) { cycle.sensor.front=ff; cycle.sensor.nearestobj = "zone"; }
}
}*/
//console.log(forward);
if(oneline != "") console.log(oneline);
for(var x=engine.players.length-1;x>=0;--x) if((cycle=engine.players[x]) !== undefined && cycle.lastpos)
{
cycle.lastpos.x = cycle.position.x;
cycle.lastpos.y = cycle.position.y;
cycle.lastpos.z = cycle.position.z;
engine.players[x].lastdir = {
front:engine.players[x].dir.front,
left:engine.players[x].dir.left,
right:engine.players[x].dir.right
};
engine.players[x].lastsensor = {
front:engine.players[x].sensor.front,
left:engine.players[x].sensor.left,
right:engine.players[x].sensor.right
};
cycle.intersectTest = [];
}
}
-function maxSpeed()
+global.maxSpeed = function()
{
if(settings.CYCLE_SPEED_DECAY_ABOVE > 0 )
var max_cs = settings.CYCLE_SPEED / settings.CYCLE_SPEED_DECAY_ABOVE;
else
var max_cs = settings.CYCLE_SPEED * 100;
var max_fastest = engine.fastestSpeed; //
return Math.max(max_cs,max_fastest);
}
-function handleChat(cycle,output)
+global.handleChat = function(cycle,output)
{
var split = output.split(" ");
- /*if(split[0][0] == "/")
- {
- switch(split[0])
- {
- case "/console": case "/admin":
- if(!engine.dedicated || split[0] != "/console")
- {
- split.shift();
- loadcfg(split.join(" "));
- break;
- }
- default:
- if(engine.network)
- {
-
- }
- else
- {
- engine.console.print('Unknown chat command "'+split[0]+'".\n');
- }
- break;
- }
- }*/
if(split[0] == "/console" && !engine.dedicated)
{
split.shift();
loadcfg(split.join(" "));
}
else if(split[0][0] == "/" && !engine.network)
{
switch(split[0])
{
case "/admin":
split.shift();
var ln = split.join(" ");
engine.console.print('Remote admin command from '+cycle.getBoringName()+'0x7f7fff: '+ln+'\n');
var text = []; engine.concatch = {to:text,type:"list"};
loadcfg(ln);
engine.concatch = undefined;
for(var i=0;i<text.length;++i)
{
engine.console.print('0xff7f7fRA:0xRESETT '+text[i]+'\n',cycle);
}
break;
case "/players":
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
engine.console.print(x+": "+engine.players[x].getColoredName()+"\n",cycle);
}
break;
case "/me":
cycle.doChat(output);
break;
default:
break;
}
}
else
{
cycle.doChat(output);
}
}
if(typeof(document) == "undefined")
{
- function centerMessage(msg,time=5000)
+ global.centerMessage = function(msg,time=5000)
{
console.log(msg);
if(window.svr)
{
if(time == Infinity) time = Number.MAX_VALUE;
var data = JSON.stringify({type:"cen",data:{msg:msg,time:time}});
window.svr.clients.forEach(function(ws){ws.send(data);});
}
}
}
else
{
- function centerMessage(msg,time=5000)
+ global.centerMessage = function(msg,time=5000)
{
var cm = document.getElementById("centerMessage");
cm.innerHTML = replaceColors(htmlEntities(msg));
cm.style.opacity = 1;
cm.style.display = "block";
engine.cMFadeOutAfter = performance.now()+time;
}
}
-function toLadderLog(event,params)
+global.toLadderLog = function(event,params)
{
if(settings["LADDERLOG_WRITE_"+event])
{
}
}
diff --git a/scripts/functions-head.js b/scripts/functions-head.js
index 28a58b1..71c2b30 100644
--- a/scripts/functions-head.js
+++ b/scripts/functions-head.js
@@ -1,593 +1,596 @@
//FUNC
-function gafd(a,b) //! returns angle from xdir, ydir
+if(typeof(global) === "undefined")
+ global = window;
+
+global.gafd = function(a,b) //! returns angle from xdir, ydir
{
var c = 180 * Math.atan2(b,a) / Math.PI;
0 > c && (c += 360);
360 < c && (c -= 360);
return c
}
-function cdir(theta) //! Gets [xdir, ydir] from angle
+global.cdir = function(theta) //! Gets [xdir, ydir] from angle
{
var x = Math.cos(theta);
var y = Math.sin(theta);
return [x,y];
}
-function fileOpen(callback,type="plain/text")
+global.fileOpen = function(callback,type="plain/text")
{
if(window.FileReader)
{
var f = document.createElement("input");
f.type = "file";
f.onchange = function(e)
{
if(e.target.files.length > 0)
{
var r = new FileReader();
r.onload = function(e)
{
callback(e.target.result);
}
for(var i=0;i<e.target.files.length;i++)
{
switch(type)
{
case "plain/text":
r.readAsText(e.target.files[i]);
break;
default:
r.readAsDataURL(e.target.files[i]);
break;
}
}
}
}
f.click();
}
else
{
alert("FileReader doesn't exist in this browser. Contact nelg.");
return false;
}
}
-function fileSave(filename,data,type="plain/text") //Based on https://stackoverflow.com/a/30832210
+global.fileSave = function(filename,data,type="plain/text") //Based on https://stackoverflow.com/a/30832210
{
//TODO: get type from filename / data ?
var file = new Blob([data],{type:type});
if(window.navigator.msSaveOrOpenBlob) // IE :(
window.navigator.msSaveOrOpenBlob(file,filename);
else
{
var a = document.createElement("a"), url = URL.createObjectURL(file);
a.href = url; a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function()
{
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
},0);
}
}
-function httpGet(url) //! gets HTTP requests synchroniously. DEPRECATED and wont work in nodejs
+global.httpGet = function(url) //! gets HTTP requests synchroniously. DEPRECATED and wont work in nodejs
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET",url,false);
xmlHttp.send(null);
return xmlHttp.responseText;
}
-function httpGetAsync(url,callback,errcb=false) //! gets HTTP requests asynchronously
+global.httpGetAsync = function(url,callback,errcb=false) //! gets HTTP requests asynchronously
{
if(window.XMLHttpRequest)
{
var req = new XMLHttpRequest();
req.onreadystatechange = function()
{
if(req.readyState == 4)
if(req.status == 200)
callback(req.responseText);
else if(errcb)
{
req.onerror = null; errcb();
}
}
if(errcb)
{
req.onerror = errcb;
}
req.open("GET",url,true);
req.send(null);
}
else if(window.https && url.indexOf("https://") == 0)
{
var req = https.get(url,function(res)
{
res.data = "";
res.on('data',function(data)
{
res.data += data;
});
res.on('end',function()
{
if(res.statusCode == 200)
callback(res.data)
else if(errcb)
errcb();
});
});
if(errcb) req.on('error',errcb);
}
else if(window.http) //no https support
{
url=url.replace("https://","http://");
var req = http.get(url.replace("https://","http://"),function(res)
{
res.data = "";
res.on('data',function(data)
{
res.data += data;
});
res.on('end',function()
{
if(res.statusCode == 200)
callback(res.data)
else if(errcb)
errcb();
});
});
if(errcb) req.on('error',errcb);
}
else
{
throw "No methods to GET file";
}
}
-function xmlify(string) //! Gets XML object from string.
+global.xmlify = function(string) //! Gets XML object from string.
{
var val;
if (window.DOMParser) { val = (new DOMParser).parseFromString(string, "text/xml"); }
else { val = new ActiveXObject("Microsoft.XMLDOM"); val.async = !1; val.loadXML(string); }
return val;
}
-function getVarFromString(string) //! Find variable parameters from string, used in parsing menus
+global.getVarFromString = function(string) //! Find variable parameters from string, used in parsing menus
{
var splice = string.split(".");
var variable = settings, var2 = commands;
for(var y=0;y<splice.length-1;y++)
{
try{variable = variable[splice[y]]}catch(e){variable = undefined}
try{var2 = var2[splice[y]]}catch(e){var2 = undefined}
}
return [variable,splice[splice.length-1],var2];
}
-function htmlEntities(str) //! Get HTML entities for some characters.
+global.htmlEntities = function(str) //! Get HTML entities for some characters.
{
return (""+str).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/\>/g,"&gt;").replace(/"/g,"&quot;");
}
-function colorIsDark(r,g,b)
+global.colorIsDark = function(r,g,b)
{
return (
( r < 255*settings.FONT_MIN_R &&
g < 255*settings.FONT_MIN_G &&
b < 255*settings.FONT_MIN_B
)|| r+g+b < 255*settings.FONT_MIN_TOTAL
);
}
-function getDarkBGFromHex(hex)
+global.getDarkBGFromHex = function(hex)
{
var c = new THREE.Color(hex);
if(colorIsDark(c.r,c.g,c.b))
return "white";
else
return "none";
}
-function replaceColors(str)
+global.replaceColors = function(str)
{
if(typeof(str) == "undefined") return typeof(str);
var dark = "class=darktext";
//Capitals are allowed because the processes here can handle them
str = str.replace(settings.VERIFY_COLOR_STRICT?/0x([0-9A-Fa-f]{6}|RESETT)(.*?)(?=0x(?:[0-9A-Fa-f]{6}|RESETT)|$)/gm : /0x(.{6})(.*?)(?=0x(?:.{6})|$)/gm,
function(x)
{
if(x.substr(2,6) == "RESETT")
{
return x.substr(8);
}
else
{
//var darkI1="class=lighttext";
var darkI1="";
var r=parseInt(x[2]+x[3],16),g=parseInt(x[4]+x[5],16),b=parseInt(x[6]+x[7],16);
//NOTE: unless using regex, javascript only replaces the first occurance
if(isNaN(r)){if(isNaN(parseInt(x[2],16)))x=x.replace(x[2],"0");if(isNaN(parseInt(x[3],16)))x=x.replace(x[3],"0");r=parseInt(x[2]+x[3],16)}
if(isNaN(g)){if(isNaN(parseInt(x[4],16)))x=x.replace(x[4],"0");if(isNaN(parseInt(x[5],16)))x=x.replace(x[5],"0");g=parseInt(x[4]+x[5],16)}
if(isNaN(b)){if(isNaN(parseInt(x[6],16)))x=x.replace(x[6],"0");if(isNaN(parseInt(x[7],16)))x=x.replace(x[7],"0");b=parseInt(x[6]+x[7],16)}
if(colorIsDark(r,g,b))
{
if(settings.TEXT_DARK_HIGHLIGHT)
{
darkI1 = dark;
}
if(settings.TEXT_BRIGHTEN)
{
if(r < settings.FONT_MIN_R) r += settings.FONT_MIN_R;
if(g < settings.FONT_MIN_G) g += settings.FONT_MIN_G;
if(b < settings.FONT_MIN_B) b += settings.FONT_MIN_B;
if(colorIsDark(r,g,b))
{
r += settings.FONT_MIN_TOTAL/3;
g += settings.FONT_MIN_TOTAL/3;
b += settings.FONT_MIN_TOTAL/3;
}
}
}
return "<span "+darkI1+" style='color:rgb("+r+","+g+","+b+");'>"+x.substr(8)+"</span>";
}
});
return str;
}
-function removeColors(str)
+global.removeColors = function(str)
{
return str.replace(settings.VERIFY_COLOR_STRICT?/0x([0-9A-Fa-f]{6}|RESETT)(.*?)(?=0x(?:[0-9A-Fa-f]{6}|RESETT)|$)/gm : /0x(.{6})(.*?)(?=0x(?:.{6})|$)/gm,function(x){return x.substr(8)});
}
String.prototype.filter = function() //! Filter illegal player characters. Heavily based on ArmagetronAd's filtering.
{
var char, out="", str = this.toString();
for(var i=0;i<str.length;i++)
{
char = str.charCodeAt(i);
if(char <= 126 && char > 32) //Leave ASCII characters but convert them to lower case
{
if(char == 48)
out += "o"; //map 0 to o because z-man
else
out += str[i].toLowerCase();
}
//! map umlauts and similar to their base characters
else if(char >= 0xc0 && char <= 0xc5) out += 'a';
else if(char >= 0xd1 && char <= 0xd6) out += 'o';
else if(char >= 0xd9 && char <= 0xdD) out += 'u';
else if(char == 0xdf) out += 's';
else if(char >= 0xe0 && char <= 0xe5) out += 'a';
else if(char >= 0xe8 && char <= 0xeb) out += 'e';
else if(char >= 0xec && char <= 0xef) out += 'i';
else if(char >= 0xf0 && char <= 0xf6) out += 'o';
else if(char >= 0xf9 && char <= 0xfc) out += 'u';
else if(char >= 0xc0 && char <= 0xc5) out += 'a';
else switch(char)
{
//some of those are a bit questionable, but still better than lots of underscores
case 161: out += '!'; break;
case 162: out += 'c'; break;
case 163: out += 'l'; break;
case 165: out += 'y'; break;
case 166: out += '|'; break;
case 167: out += 's'; break;
case 168: out += '"'; break;
case 169: out += 'c'; break;
case 170: out += 'a'; break;
case 171: out += '"'; break;
case 172: out += '!'; break;
case 174: out += 'r'; break;
case 176: out += 'o'; break;
case 177: out += '+'; break;
case 178: out += '2'; break;
case 179: out += '3'; break;
case 182: out += 'p'; break;
case 183: out += '.'; break;
case 185: out += '1'; break;
case 187: out += '"'; break;
case 198: out += 'a'; break;
case 199: out += 'c'; break;
case 208: out += 'd'; break;
case 209: out += 'n'; break;
case 215: out += 'x'; break;
case 216: out += 'o'; break;
case 221: out += 'y'; break;
case 222: out += 'p'; break;
case 231: out += 'c'; break;
case 241: out += 'n'; break;
case 247: out += '/'; break;
case 248: out += 'o'; break;
case 253: out += 'y'; break;
case 254: out += 'p'; break;
case 255: out += 'y'; break;
default: out += "_"; break; //unknown character, mapped to underscore
}
}
return out;
}
-function tStringify(str) //!
+global.tStringify = function(str) //!
{
str = str.replace(/\$\w*/g,function(i){console.log(i.replace("\$",""));});
str = str.replace(new RegExp("@progtitle@",'g'),"3DCycles Web");
str = str.replace(new RegExp("@progtitleshort@",'g'),"3DCycles");
str = str.replace(new RegExp("@progname@",'g'),"webtron");
return str;
}
-function pi(a=1) {return Math.PI*a} //! Finds multiples of PI.
+global.pi = function(a=1) {return Math.PI*a} //! Finds multiples of PI.
-function setNewFont(input) //! Gets font from user input. Not used anywhere anymore.
+global.setNewFont = function(input) //! Gets font from user input. Not used anywhere anymore.
{
input = input.toLowerCase();
var output = "";
switch(input) {
case 'armagetronad':case 'armagetron':case 'arma':case 'tron':
output = "Armagetronad";
break;
case 'flynn':case 'flyn':case 'flyyn':case 'flin':case 'user':case 'legacy':
output = "Flynn";
break;
case 'serif':case 'srif':case 'serf':case 'srf':case 'font':
output = "serif";
break;
case 'sans-serif':case 'sansserif':case 'sans':case 'sanserif':case 'san':
output = "sans-serif";
break;
case 'nicefont':case 'nice':case 'nfont':
output = "nicefont";
break;
case 'monospace':case 'mono':case 'fixedwidth':case 'fixed':
output = "monospace";
break;
default:
output = "Armagetronad";
}
return output;
}
-function pointDistance(x1,y1,x2,y2)
+global.pointDistance = function(x1,y1,x2,y2)
{
var xs = x2 - x1, ys = y2 - y1;
return Math.sqrt( xs*xs + ys*ys );
}
-function getLogicalBox(string) //! Parses map file and returns [x, y, minx, miny, maxx, maxy] or false on failure.
+global.getLogicalBox = function(string) //! Parses map file and returns [x, y, minx, miny, maxx, maxy] or false on failure.
{
var re = /(x|y)\=.-?(\d*.)?\d+/gi;
var matches = string.match(re);
var temp = 0;
var box = [0,0,Infinity,Infinity,-Infinity,-Infinity];// x, y, minx, miny, maxx, maxy
if (matches) {
for (var i = 0; i < matches.length; i++) {
matches[i] = matches[i].replace(/\"|\'/g, '');
//console.log(matches[i]);
if (matches[i].indexOf("x") > -1) { // x=250.25
matches[i] = matches[i].replace('x=', '');
temp = parseFloat(matches[i]);
if (temp > box[4]) { box[4] = temp; }
if (temp < box[2]) { box[2] = temp; }
}
if (matches[i].indexOf("y") > -1) { // y=-25
matches[i] = matches[i].replace('y=', '');
temp = parseFloat(matches[i]);
if (temp > box[5]) { box[5] = temp; }
if (temp < box[3]) { box[3] = temp; }
}
}
//get center
box[0] = ( box[2] + box[4] ) / 2;
box[1] = ( box[3] + box[5] ) / 2;
//console.log(box);
return box;
}
else {
return false;
}
}
-function hasClass(element, cls) {//checks if element has classname, returns true | false
+global.hasClass = function(element, cls) {//checks if element has classname, returns true | false
return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}
-function relPath(path,rel="/")
+global.relPath = function(path,rel="/")
{
//if(rel.indexOf("/") != 0) rel = "/"+rel;
if(rel.indexOf("/",rel.length-1) == -1) rel += "/";
if(path.indexOf("://") >= 0 || path.indexOf("/") == 0) return path;
else return rel+path;
}
-function inround() //! Tries to determine if we're in a round or not.
+global.inround = function() //! Tries to determine if we're in a round or not.
{
return !engine.roundCommencing && engine.gtime >= -4000;
}
-function deg2rad(angle)
+global.deg2rad = function(angle)
{
if(!isFinite(angle)) return angle;
angle %= 360;
if(angle < 0) angle += 360;
var radians = angle * Math.PI / 180;
return radians;
}
-function rad2deg(radians)
+global.rad2deg = function(radians)
{
if(!isFinite(radians)) return radians;
var angle = radians * 180 / Math.PI;
angle %= 360;
if(angle < 0) angle += 360;
return angle;
}
-function normalizeRad(radians)
+global.normalizeRad = function(radians)
{
var pi2 = Math.PI*2;
radians = radians%pi2;
while(radians < 0) radians += pi2;
return radians;
}
// BEGIN based on code from http://geomalgorithms.com/a07-_distance.html
// Copyright 2001 softSurfer, 2012 Dan Sunday
// This code may be freely used, distributed and modified for any purpose
// providing that this copyright notice is included with it.
// SoftSurfer makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.
var dot = function(ux,uy,vx,vy) { return ((ux*vx)+(uy*vy)); };
var SMALL_NUM = 0.00000001; // anything that avoids division overflow
-function distanceoflines(x1,y1, x2,y2, x3,y3, x4,y4)
+global.distanceoflines = function(x1,y1, x2,y2, x3,y3, x4,y4)
{
var ux=x2-x1,uy=y2-y1;
var vx=x4-x3,vy=y4-y3
var wx=x1-x3,wy=y1-y3;
//var a = dot(ux,uy,ux,uy), b = dot(ux,uy,vx,vy), c = dot(vx,vy,vx,vy), d = dot(ux,uy,wx,wy), e = dot(vx,vy,wx,wy);
var a = (ux*ux)+(uy*uy), b = (ux*vx)+(uy*vy), c = (vx*vx)+(vy*vy), d = (ux*wx)+(uy*wy), e = (vx*wx)+(vy*wy); //probably faster
var D = a*c - b*b;
var sc,sN,sD = D;
var tc,tN,tD = D;
if(D < SMALL_NUM) //lines almost parallel
{
sN = 0; //force point p0 on segment s1
sD = 1; //prevent possible division by zero
tN = e; tD = c;
}
else //get closest points on the infinite lines
{
sN = (b*e - c*d); tN = (a*e - b*d);
if(sN < 0) //sc < 0 => the s=0 edge is visible
{
sN = 0; tN = e; tD = c;
}
else if(sN > sD) //sc > 1 => the s=1 edge is visible
{
sN = sD; tN = e + b; tD = c;
}
}
if(tN < 0) // tc < 0 => the t=0 edge is visible
{
tN = 0;
//recompute sc this edge
if(d>0)
{
sN = 0;
}
else if(d<a)
{
sN = sD;
}
else
{
sN = -d; sD = a;
}
}
else if(tN > tD) //tc > 1 => the t=1 edge is visible
{
tN = tD;
//recompute sc for this edge
if((b-d) < 0)
{
sN = 0;
}
else if((b-d) > a)
{
sN = sD;
}
else
{
sN = (b-d); sD = a;
}
}
//finally, do the division to get sc and tc;
var sc = (Math.abs(sN) < SMALL_NUM ? 0.0 : sN / sD);
var tc = (Math.abs(tN) < SMALL_NUM ? 0.0 : tN / tD);
var dPx = wx + (ux * sc) - (vx * tc);
var dPy = wy + (uy * sc) - (vy * tc);
//console.log(dPx,dPy);
//return Math.sqrt(dot(dPx,dPy,dPx,dPy));
return Math.hypot(dPx,dPy);
}
// END
-function is_in_circle(p1x, p1y, r1, p2x, p2y, r2=0)
+global.is_in_circle = function(p1x, p1y, r1, p2x, p2y, r2=0)
{
return(r1+r2 > Math.sqrt(Math.pow((p1x-p2x),2)+Math.pow((p1y-p2y),2)))
}
-function lineIntersect(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y)
+global.lineIntersect = function(p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y)
{
var s1_x = p1_x - p0_x, s1_y = p1_y - p0_y, s2_x = p3_x - p2_x, s2_y = p3_y - p2_y;
var s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y),
t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
return (s >= 0 && s <= 1 && t >= 0 && t <= 1);
}
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
//"encrytion" variables, not sure what they were for:
String.prototype.toEncodedString = function () {
var ostr = this.toString().replace(/\s+/g, '');
if (ostr.length < 8) {
alert("Password must be at least 8 characters long with no spaces.");
return null;
};
var x, nstr = '',
len = ostr.length;
for (x = 0; x < len; ++x) {
nstr += (255 - ostr.charCodeAt(x)).toString(36).toUpperCase().toPaddedString(2, '0');
};
return nstr;
};
String.prototype.fromEncodedString = function () {
var ostr = this.toString();
var x, nstr = '',
len = ostr.length;
for (x = 0; x < len; x += 2) {
nstr += String.fromCharCode(255 - parseInt(ostr.substr(x, 2), 36));
};
return nstr;
};
Number.prototype.toPaddedString = function (len, pad) {
len = (len) ? Number(len) : 2;
if (isNaN(len)) {
alert("Padded String 'length' argument is not numeric.");
return null;
};
var dflt = (isNaN(this.toString())) ? " " : "0";
pad = (pad) ? pad.toString().substr(0, 1) : dflt;
var str = this.toString();
if (dflt == "0") {
while (str.length < len) str = pad + str;
}
else {
while (str.length < len) str += pad;
};
return str;
};
String.prototype.toPaddedString = Number.prototype.toPaddedString;
/**/
var encrypt1 = new Date().getTime();
encrypt1 = ""+encrypt1;//##############...
//var encrypt2 = encrypt1.toEncodedString();
//var str3 = str2.fromEncodedString();
/**/
-function getSuperString() {
+global.getSuperString = function() {
var superstring = encrypt1.toEncodedString();
superstring = "lightcycle"+superstring;
return superstring;
}
var ss = getSuperString();
diff --git a/scripts/game.js b/scripts/game.js
index eb82820..ce63f61 100644
--- a/scripts/game.js
+++ b/scripts/game.js
@@ -1,1194 +1,1173 @@
/*
* 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 doNewRound()
+(function(game){
+
+/*if(this.require)
+{
+ if(typeof(THREE) === "undefined")
+ var THREE = require('./lib/Three.js');
+ if(typeof(Zone) === "undefined")
+ var Zone = require("./zone.js");
+}*/
+
+game.doNewRound = function()
{
if(engine.uRound !== false) { clearTimeout(engine.uRound); engine.uRound = false; }
- endRound();
- setTimeout(newRound,engine.dedicated?300:0); //give clients an opportunity to sync their data
+ game.endRound();
+ setTimeout(game.newRound,engine.dedicated?300:0); //give clients an opportunity to sync their data
}
-function endRound()
+game.endRound = function()
{
if(window.svr)
{
window.svr.clients.forEach(function(ws){ws.send('{"type":"endRound"}')});
window.svr.clients.forEach(function(ws){ws.send('{"type":"syncdata","gtime":-4000}')});
}
if(ctx)
{
audioStop();
if(settings.SOUNDS_EXTRO) playSound(bufferLoader.bufferList[bufferLoader.other+2],0.5,1,false,ctx.destination);
}
engine.roundCommencing = true;
//engine.hud.hide();
if(engine.hud) engine.hud.game.style.opacity = 0;
engine.console.print("Clearing grid...\n",false);
if(engine.renderer) engine.renderer.clear();
if(!engine.network)
{
- if(settings.ROUND_CENTER_MESSAGE != "")
+ //if(settings.ROUND_CENTER_MESSAGE != "")
{
centerMessage(settings.ROUND_CENTER_MESSAGE);
}
}
engine.gtime = -4000;
for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined")
{
engine.players[x].alive = false;
}
while(engine.scene.children.length > 0)
{
engine.scene.remove(engine.scene.children[0]);
}
//if(!engine.network) engine.players.splice(0);
}
-function endGame()
+game.end = function()
{
- endRound();
+ game.endRound();
engine.players.splice(0);
engine.round = 0;
}
-function playGame()
+game.play = function()
{
engine.playGame = true;
if(!engine.scene)
{
init();
}
else
{
engine.paused = false;
if(engine.hud) engine.hud.show();
}
- hideMenu(); newRound();
+ hideMenu(); game.newRound();
engine.inputState = 'game'; //change input state to accept game controls
if(engine.network)
{
document.getElementById("progtitle").innerHTML = tStringify("@progtitleshort@ &bull; Playing online");
}
else
{
document.getElementById("progtitle").innerHTML = tStringify("@progtitleshort@ &bull; Playing locally");
}
}
function revertMap()
{
if(engine.dedicated)
{
engine.console.print("Unable to load map file. Reverting...\n",true);
chsetting("MAP_FILE",engine.loadedMap);
loadRound();
}
else
{
var mapfile = settings.RESOURCE_REPOSITORY_CACHE+(settings.MAP_FILE.replace(/\(.+\)/,""));
engine.console.print("Downloading map from "+mapfile+"...\n",false);
- httpGetAsync(mapfile,loadRound,function()
+ httpGetAsync(mapfile,game.loadRound,function()
{
engine.console.print("Unable to load map file. Ignoring for now...\n",false);
- loadRound();
+ game.loadRound();
});
}
}
-function newRound()
+game.newRound = function()
{
engine.roundCommencing = true;
/////////////LIGHTS
var light1 = new THREE.AmbientLight( 0x666666 ); // soft white light
engine.scene.add( light1 );
var light = new THREE.DirectionalLight( 0xffffff, 1 );
light.castShadow = true;
light.position.set( 4, 1, 0 );
engine.scene.add( light );
var light2 = new THREE.DirectionalLight( 0xffffff, 1 );
light2.castShadow = true;
light2.position.set( -4, -1, 0 );
engine.scene.add( light2 );
//////////end of lights
var aspectRatio = (window.innerWidth / window.innerHeight);
engine.camera = new THREE.PerspectiveCamera( settings.CAMERA_FOV, aspectRatio, settings.CAMERA_NEAR_RENDER, settings.CAMERA_FAR_RENDER );
engine.camera.userViewDir = false;
engine.camera.up = new THREE.Vector3(0,0,1); //Z is up, X and Y is l+r and b+f
//engine.camera.position.set(247, 247, 3);
engine.viewTarget = engine.activePlayer;
//engine.cameraOrbit = new THREE.OrbitControls(engine.camera);
//engine.cameraOrbit.maxDistance = 400;
//BELOW THIS LINE DEPENDS ON GAME TYPE
//MAP
var maps = settings.MAP_ROTATION.split(";");
if(settings.ROTATION_TYPE > 0)
{
switch(settings.ROTATION_TYPE)
{
case 1:
engine.currrot += 1;
break;
case 2: // when matches are implemented
if(engine.rounds == 0) engine.currrot += 1;
break;
}
if(engine.currrot > maps.length) engine.currrot = 0;
settings.MAP_FILE = maps[engine.currrot];
}
if(settings.MAP_FILE != "" && settings.MAP_FILE != engine.loadedMap)
{
var mapfile = settings.RESOURCE_REPOSITORY_SERVER+(settings.MAP_FILE.replace(/\(.+\)/,""));
engine.console.print("Downloading map from "+mapfile+"...\n",false);
- httpGetAsync(mapfile,loadRound,revertMap);
- //loadRound(httpGet(mapfile));
+ httpGetAsync(mapfile,game.loadRound,revertMap);
}
else
{
- loadRound();
+ game.loadRound();
}
}
-function teamColor(id)
+game.teamColor = function(id)
{
id += 1;
if(settings["TEAM_NAME_"+id])
{
return new THREE.Color(settings["TEAM_RED_"+id]/15,settings["TEAM_GREEN_"+id]/15,settings["TEAM_BLUE_"+id]/15);
}
return new THREE.Color();
}
function createAIsettings()
{
var AI_NUM = 1;
for(var z=engine.players.length-1;z>=0;--z) if(engine.players[z] && engine.players[z].AI) {AI_NUM++;}
var cycleColor = [0x000000,0xff0000,0x00ff00,0x0000ff][Math.round(Math.random()*3)];
var tailColor = [0x0000ff,0xff0000,0xffff00,0x00ff00][Math.round(Math.random()*3)];
var colorcode;
if(settings.ALLOW_TEAM_NAME_COLOR)
{
colorcode = cycleColor.toString(16);
colorcode = ("0".repeat(6-colorcode.length))+colorcode;
}
else
{
cycleColor = tailColor = teamColor(1);
colorcode = cycleColor.getHexString();
}
var cycleinfo = { ai:true,
cycleColor:cycleColor, tailColor:tailColor,
/*engineType: 5,*/ engineType:(settings.players[0])?settings.players[0].engineType:5, spectating:false,
name: settings.AI_DUAL_COLOR_NAME?'AI0x'+colorcode+'#'+AI_NUM:'AI#'+AI_NUM
};
return cycleinfo;
}
function calculateSpawn(x)
{
var spawnslength = engine.map.spawns.length;
if(!engine.map.spawns[x])
{
var mult = Math.floor((x/spawnslength));
var currspawn = x-(spawnslength*mult);
var alt = (mult/2 != Math.floor(mult/2));
console.log(mult);
if(alt) mult = -Math.ceil(mult/2)
else mult = mult/2
console.log(mult,currspawn);
var spawns = JSON.parse(JSON.stringify(engine.map.spawns[Math.min(currspawn,(spawnslength-1))]||[]));
spawns[0] -= mult*settings.SPAWN_WINGMEN_SIDE;
spawns[1] -= Math.abs(mult)*settings.SPAWN_WINGMEN_BACK;
}
else
{
var spawns = engine.map.spawns[x];
}
return spawns;
}
function processPlayer(x,cfg)
{
var spawns = calculateSpawn(x);
if(engine.players[x])
{
var cycle = engine.players[x];
cycle.engineType = (typeof(cfg)=="undefined")?5:cfg.engineType;
//if(x == engine.activePlayer && !engine.dedicated)
{
var cycleColor = cfg.cycleColor,tailColor = cfg.tailColor;
if(!settings.ALLOW_TEAM_NAME_COLOR) { cycleColor = tailColor = teamColor(engine.teams.indexOf(engine.players[x].team)); }
if(cycle.name != cfg.name)
{
var out = cycle.getColoredName()+"0x7fff7f renamed to ";
cycle.cycleColor = cycleColor;
cycle.tailColor = tailColor;
cycle.name = cfg.name;
engine.console.print(out+cycle.getColoredName()+"\n");
}
else
{
cycle.cycleColor = cycleColor;
cycle.tailColor = tailColor;
}
if(cycle.spectating != cfg.spectating)
{
cycle.spectating = cfg.spectating;
if(cycle.spectating)
{
engine.console.print(cycle.getColoredName()+"0xff7f7f left to spectator mode.\n");
}
else
{
engine.console.print(cycle.getColoredName()+"0x7fff7f entered from spectator mode.\n");
}
}
}
}
else
{
cfg.x = spawns[0]; cfg.y = spawns[1]; cfg.z = spawns[2];
engine.players[x] = (new Player(cfg));
var cycle = engine.players[x];
if(cycle.spectating)
{
engine.console.print(cycle.getColoredName()+"0xff7f7f entered as spectator.\n");
}
else
{
engine.console.print(cycle.getColoredName()+"0x7fff7f entered the game.\n");
}
}
if(cycle.spectating)
{
cycle.team = null;
}
else if(!cycle.team)
{
if(engine.teams.length < settings.TEAMS_MAX)
{
engine.teams.push(cycle.team = new Team({name:cfg.name,x:spawns[0], y:spawns[1], z:spawns[2], dir:deg2rad(spawns[3])}));
}
else
{
var minPCount = 0, minPlayers = Infinity, minTeam;
for(var x=engine.teams.length-1;x>=0;--x) if(engine.teams[x])
{
if(engine.teams[x].members.length == minPlayers)
{
minPCount++;
if(minTeam.push)
{
minTeam.push(x);
}
else
{
minTeam = [minTeam,x];
}
}
else if(engine.teams[x].members.length < minPlayers)
{
minPlayers = engine.teams[x].members.length;
minTeam = x; minPCount = 1;
}
}
if(minPCount != 1)
{
minTeam = Math.floor(Math.random()*minTeam.length);
}
cycle.team = engine.teams[minTeam];
}
cycle.team.members.push(cycle);
}
}
-function ensurePlayersSane(removeAIs=true)
+game.processPlayers = function(removeAIs=true)
{
var numAIs = 0, numPlay = 0, numSpec = 0, numWantPlay = 0;
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
if(engine.players[x].AI) numAIs++;
if(engine.players[x].spectating) numSpec++; else numPlay++;
//if(engine.players[x].spectating && !settings.players[x].spectating) numWantPlay++;
}
var numHuman = numPlay-numAIs;
if(removeAIs)
{
for(var x=settings.TEAMS_MAX;x<engine.teams.length;++x) if(engine.teams[x])
{
for(var i=engine.teams[x].members.length-1;i>=0;--i)
{
engine.console.print(engine.teams[x].members[i].getColoredName()+"0xff7f7f left to spectator mode.\n");
engine.teams[x].members[i].spectating = true;
}
}
engine.teams.splice(settings.TEAMS_MAX);
}
for(var x=settings.players.length-1;x>=0;--x) if(settings.players[x])
{
if(engine.players[x] && engine.players[x].AI)
{
engine.players[engine.players.length-1] = engine.players[x];
engine.players[x] = undefined;
}
if(!engine.players[x])
{
numPlay++; numHuman++;
}
processPlayer(x,settings.players[x]);
}
if(removeAIs)
{
console.log(numHuman);
var shouldAIs = Math.max(0,(settings.MIN_PLAYERS-numHuman));
if(!settings.AI_TEAM)
{
shouldAIs += (numHuman <= settings.SP_HUMANS_COUNT)?settings.SP_NUM_AIS:settings.NUM_AIS;
}
if(shouldAIs > numAIs)
{
var AIsToAdd = (shouldAIs-numAIs);
console.log(numAIs+" AIs in the game, adding "+AIsToAdd+".");
for(var x=AIsToAdd;x>0;--x)
{
var cycleinfo = createAIsettings();
processPlayer(engine.players.length,cycleinfo);
}
numAIs += AIsToAdd;
}
else if(numAIs != 0)
{
var AIsToDealWith = (numAIs-shouldAIs);
console.log(numAIs+" AIs in the game, removing "+AIsToDealWith+".");
if(AIsToDealWith != 0)
{
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
if(engine.players[x].AI)
{
engine.console.print(engine.players[x].getColoredName()+"0xff7f7f left the game.\n");
engine.players.splice(x,1);
AIsToDealWith--;
if(window.svr)
{
var data = JSON.stringify({type:"leave",data:x});
window.svr.clients.forEach(function(ws){ws.send(data)});
}
}
if(AIsToDealWith == 0) break;
}
}
}
//clean up teams / remove ghost teams
for(var x=engine.teams.length-1;x>=0;--x) if(engine.teams[x])
{
for(var i=engine.teams[x].members.length-1;i>=0;--i)
{
if(engine.players.indexOf(engine.teams[x].members[i]) == -1)
{
engine.teams[x].members.splice(i,1);
}
}
if(engine.teams[x].members.length == 0)
{
engine.teams.splice(x,1);
}
else
{
engine.teams[x].spawn(false,false); //and finally spawn everyone
}
}
if(!engine.dedicated && !engine.players[engine.activePlayer].alive) changeViewTarget(1);
}
if(window.svr)
{
var teams = [];
for(var x=engine.teams.length-1;x>=0;--x) if(engine.teams[x])
{
teams.push({id:x,name:engine.teams[x].name,x:engine.teams[x].x,y:engine.teams[x].y,z:engine.teams[x].z});
}
teams=JSON.stringify({type:"team",data:teams});
window.svr.clients.forEach(function(ws){ws.send(teams);ws.senddata(0)});
}
}//*/
-function loadRound(dlmap)
+game.loadRound = function(dlmap)
{
if(typeof(dlmap) != "undefined")
{
engine.mapString = dlmap;
engine.loadedMap = settings.MAP_FILE;
}
engine.mapXML = xmlify(engine.mapString);
engine.console.print("Preparing grid...\n",false);
if(window.svr) window.svr.clients.forEach(function(ws){ws.send('{"type":"newRound"}')});
//virtual map data (used for positions, lines and stuff to calculate)
engine.map = {zones:[],spawns:[],walls:[]};
engine.expl = []; engine.deaths = 0;
engine.winzone = false;
//GRID
buildGrid();//buildObjects.js
engine.scene.add(engine.grid);
//WALLS
buildWalls();//buildObjects
engine.scene.add(engine.walls);
//ZONES
buildZones();
engine.scene.add(engine.zones);
if(settings.SOUNDS_INTRO)
playSound(bufferLoader.bufferList[bufferLoader.other+1],0.5,1,false,ctx.destination);
if(settings.ROUND_CONSOLE_MESSAGE != "")
{
engine.console.print(settings.ROUND_CONSOLE_MESSAGE+"\n");
}
loadcfg(settings.ROUND_COMMAND.replace(/\\n/g,"\n"));
//GAME
engine.gtime = -4000;
//PLAYERS
//CYCLE
if(!engine.network)
{
- ensurePlayersSane();ensurePlayersSane();
+ game.processPlayers();game.processPlayers();
if(engine.round == 0)
{
engine.console.print("Resetting scores...\n");
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
engine.players[x].score = 0;
}
}
engine.round++;
engine.console.print("Go (round "+engine.round+" of "+settings.LIMIT_ROUNDS+")!\n");
}
if(!engine.camera)
{
var aspectRatio = (window.innerWidth / window.innerHeight);
engine.camera = new THREE.PerspectiveCamera( settings.CAMERA_FOV, aspectRatio, settings.CAMERA_NEAR_RENDER, settings.CAMERA_FAR_RENDER );
engine.camera.up = new THREE.Vector3(0,0,1); //Z is up, X and Y is l+r and b+f
}
engine.camera.position.set(engine.logicalBox.center.x*engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.center.y*engine.REAL_ARENA_SIZE_FACTOR,3);
try{engine.camera.lookAt( new THREE.Vector3(engine.players[engine.viewTarget].position.x,engine.players[engine.viewTarget].position.y,engine.player[engine.viewTarget].position.z) );}
catch(e){engine.camera.lookAt( new THREE.Vector3(engine.logicalBox.center.x*engine.REAL_ARENA_SIZE_FACTOR,engine.logicalBox.center.y*engine.REAL_ARENA_SIZE_FACTOR,0) );}
- updateScoreBoard();
+ game.updateScoreBoard();
engine.lastGameTime = engine.lastRenderTime = engine.fpsTime = engine.timeStart = performance.now();
engine.totalPauseTime = 0;
engine.fastestPlayer = engine.fastestSpeed = 0;
engine.timemult = 1;
engine.asendtm = 0;
engine.winner = undefined;
engine.roundCommencing = false;
- getGoing();
+ game.start();
}//end of init main
-function game(oneoff=false)
+game.run = function(oneoff=false)
{
if(!engine.roundCommencing && !engine.paused)
{
- if(engine.network)
- {
- var cycle = engine.players[engine.activePlayer],data={},len=0;
- if(cycle.braking != cycle.brakingPrev) {data.braking=cycle.braking; cycle.brakingPrev=cycle.braking; ++len;}
- if(cycle.boosting != cycle.boostingPrev) {data.boosting=cycle.boosting; cycle.boostingPrev=cycle.boosting; ++len;}
-
- if(len > 0)
- {
- engine.connection.send(JSON.stringify({type:"playdata",data:data}));
- }
- }
- if(!oneoff && settings.GAME_LOOP != 1) {setTimeout(game,1000/settings.DEDICATED_FPS); engine.gameRunning = true;}
+ if(engine.network) engine.network.syncPlayData();
+ if(!oneoff && settings.GAME_LOOP != 1) {setTimeout(game.run,1000/settings.DEDICATED_FPS); engine.gameRunning = true;}
//time handlers and delta
var timenow = performance.now()/settings.TIME_FACTOR;
var rDelta = (timenow-engine.lastGameTime);
if(rDelta > settings.TIMESTEP_MAX*1000 && engine.gtime > 0)
{
var more = true;
rDelta = settings.TIMESTEP_MAX*1000;
//engine.timeStart += rDelta;
} else var more = false;
var delta = rDelta*engine.timemult;
var timestep = delta/1000;
engine.totalPauseTime += (timenow-engine.lastGameTime)-delta;
engine.lastGameTime += rDelta;
engine.avgTimeStep += rDelta/1000; engine.avgTimeStep /= 2;
if(!engine.network && !engine.dedicated) engine.players[0].ping = parseInt(engine.avgTimeStep*1000)
//if(!engine.network && timestep > engine.avgTimeStep*10 && rDelta == delta) {engine.totalPauseTime += timestep; console.log("Compensated skip of "+delta+"ms."); timestep = engine.avgTimeStep;}
engine.timemult += (engine.asendtm*timestep);
if(engine.timemult > 100) engine.timemult = 100;
//var timeElapsed = timenow-engine.timeStart-engine.totalPauseTime-4000;
//skipping ahead at the beginning of the round is silly
//engine.gtime = timeElapsed;
var timeElapsed = (engine.gtime += delta);
if(!engine.thread_collisiondetect && (settings.GAME_LOOP != 0.5 || !oneoff)) getCycleSensors();
var pldata = {};
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
var cycle = engine.players[x];
if(cycle.alive)
{
if(cycle.newPos) doNetSlide(cycle,timestep);
if(timeElapsed > 0)
{
if(x == engine.activePlayer)
{
if(settings.HACK_TURN_LEFT_WHEN_POSSIBLE > 0)
{
if(cycle.sensor.left > settings.HACK_TURN_SENSOR_DIST)
{
cycle.turn(-1);
settings.HACK_TURN_LEFT_WHEN_POSSIBLE--;
}
}
if(settings.HACK_TURN_RIGHT_WHEN_POSSIBLE > 0)
{
if(cycle.sensor.right > settings.HACK_TURN_SENSOR_DIST)
{
cycle.turn(1);
settings.HACK_TURN_RIGHT_WHEN_POSSIBLE--;
}
}
}
//bot turning
if(cycle.AI)
{
cycle.AI.think(timestep);
}
else if(x==engine.activePlayer && (cycle.chatting || settings.CHATBOT_ALWAYS_ACTIVE))
{
if(timenow > cycle.lastTurnTime+(settings.CYCLE_DELAY*1000) && cycle.sensor.front < Math.min(5,cycle.sensor.left,cycle.sensor.right))
{
if(cycle.sensor.right < cycle.sensor.left) cycle.turn(-1);
else if(cycle.sensor.right > cycle.sensor.left) cycle.turn(1);
else cycle.turn([-1,1][Math.round(Math.random()*1)]);
}
}
//do turning
//if(cycle.turnQueue.length > 0)
{
//if(cycle.turnQueue.length > 0 && x == 0)console.log(JSON.parse(JSON.stringify(cycle.turnQueue)));
if(cycle.turnQueue.length > settings.CYCLE_TURN_MEMORY) cycle.turnQueue.splice(0,cycle.turnQueue.length-settings.CYCLE_TURN_MEMORY);
var shouldTime = cycle.lastTurnTime+(settings.CYCLE_DELAY*1000);
if(cycle.turnQueue.length > 0 && timeElapsed >= shouldTime/*-delta*/)
{
//allow the cycle to turn when it should (???)
//var diff = (shouldTime-timeElapsed)/1000;
//cycle.update(diff);
if(settings.CYCLE_MIDAIR_TURN || cycle.position.z-cycle.sensor.bottom == cycle.model.rotation.y)
{
var dir = cycle.turnQueue[0],dirmult;
var olddir = cdir(cycle.rotation.z);
if(engine.network && settings.DEBUG_NETWORK_TURN_WAIT)
{
var rot = normalizeRad(cycle.rotation.z - (pi(2)/settings.ARENA_AXES)*dir);
engine.connection.send(JSON.stringify({
type:"turn",data:rad2deg(rot),gtime:cycle.gameTime
}));
cycle.lastTurnTime = Infinity;
cycle.turnQueue.splice(0,1); continue;
}
cycle.dir.front = (dirmult = cdir(cycle.rotation.z -= (pi(2)/settings.ARENA_AXES)*dir));
//cycle.rotation.z = cycle.rotation.z%(Math.PI*2);
//if(cycle.rotation.z < 0) cycle.rotation.z += Math.PI*2;
cycle.rotation.z = normalizeRad(cycle.rotation.z);
cycle.speed *= settings.CYCLE_TURN_SPEED_FACTOR;
cycle.rotation.x = Math.cos(cycle.rotation.z)*0.4*dir; //tilts the cycle
cycle.rotation.y = Math.sin(cycle.rotation.z)*0.4*dir;
//if(settings.GRAB_SENSORS_ON_TURN)
{
getCycleSensors(true);
}
cycle.collidetime = timeElapsed+(((cycle.sensor.front)/cycle.speed)*1000);
var mult = (1-settings.CYCLE_RUBBER_MINADJUST);
cycle.minDistance.front = Math.max(0,Math.min(cycle.sensor.front*mult,settings.CYCLE_RUBBER_MINDISTANCE));
cycle.lastpos = cycle.position.clone(); //redundant, should be handled by getCycleSensors
if(cycle.haswall) cycle.newWallSegment();
if(engine.network)
{
engine.connection.send(JSON.stringify({
type:"turn",data:rad2deg(cycle.rotation.z),gtime:cycle.gameTime,
position:[cycle.position.x,cycle.position.y,cycle.position.z],
speed:cycle.speed, rubber:cycle.rubber, brakes:cycle.brakes
}));
}
if(window.svr) //force a player sync
{
var data = JSON.stringify({type:"griddata",data:[{
position:[cycle.position.x,cycle.position.y,cycle.position.z],
direction:rad2deg(cycle.rotation.z),
speed:cycle.speed, rubber:cycle.rubber,
alive:cycle.alive,
netid:x, wall:cycle.walls.map,
}],gtime:engine.gtime});
if(cycle.speed > 1) cycle.update(0.01/cycle.speed);
var data2 = JSON.stringify({type:"griddata",data:[{
position:[cycle.position.x,cycle.position.y,cycle.position.z],
direction:rad2deg(cycle.rotation.z),
speed:cycle.speed, rubber:cycle.rubber,
alive:cycle.alive,
netid:x}],gtime:engine.gtime});
window.svr.clients.forEach(function(ws){ws.send(data);ws.send(data2)});
}
}
cycle.turnQueue.splice(0,1);
cycle.lastTurnTime = timeElapsed;
}
}
cycle.update();
}
if(cycle.rubber > settings.CYCLE_RUBBER+0.0001)
cycle.rubber = settings.CYCLE_RUBBER+0.0001;
else if(cycle.rubber > 0)
cycle.rubber -= (timestep/settings.CYCLE_RUBBER_TIME)*cycle.rubber;
else
cycle.rubber = 0;
//if(timeElapsed/1000 > -3 && cycle.alive)
}
else if(cycle.walls.map.length != 0 && timenow-cycle.dedtime >= settings.WALLS_STAY_UP_DELAY*1000)
{
cycle.walls.map = [];
console.log("DELETE WALLS id "+x);
}
else if(settings.RESPAWN_TIME >= 0 && !cycle.alive && timenow-cycle.dedtime > settings.RESPAWN_TIME*1000)
{
cycle.spawn({x:cycle.position.x||0,y:cycle.position.y||0,z:cycle.position.z||0,dir:cycle.rotation.z||0});
}
}
if(timeElapsed > -3000 && timeElapsed < 1000)
{
//timer
var time=-timeElapsed/1000,gTime = Math.ceil(time);
if(gTime < 0) gTime = 0;
if(typeof(engine.timer)=="undefined" || engine.timer != gTime)
{
engine.timer = gTime;
if(engine.hud) engine.hud.fadein = true;
if(engine.dedicated) console.log(gTime);
else centerMessage(gTime,(gTime-time));
//engine.console.print(gTime+"\n");
}
}
else if(!engine.network && typeof(engine.winner) == "undefined")
{
- checkForWinner();
+ game.checkForWinner();
}
if(!engine.network)
{
if(!engine.winzone && settings.WIN_ZONE_MIN_ROUND_TIME+engine.deaths*(settings.WIN_ZONE_MIN_LAST_DEATH) < timeElapsed/1000)
{
var zone = {expansion:settings.WIN_ZONE_EXPANSION};
if(settings.WIN_ZONE_DEATHS)
{
engine.console.print("Death zone activated. Avoid it!\n");
zone.type = "death";
}
else
{
engine.console.print("Win zone activated. Enter it to win the round.\n");
zone.type = "win";
}
zone.radius = Math.min(SMALL_NUM,settings.WIN_ZONE_INITIAL_SIZE)*engine.REAL_ARENA_SIZE_FACTOR;
zone.x = engine.REAL_ARENA_SIZE_FACTOR*(engine.logicalBox.center.x+(settings.WIN_ZONE_RANDOMNESS*(Math.random()-0.5)*2)*engine.logicalBox.center.x);
zone.y = engine.REAL_ARENA_SIZE_FACTOR*(engine.logicalBox.center.y+(settings.WIN_ZONE_RANDOMNESS*(Math.random()-0.5)*2)*engine.logicalBox.center.y);
new Zone(zone).spawn();
console.log("ZONE SPAWNED: "+zone.type);
engine.winzone = true;
}
}
for(var x=engine.zones.children.length-1;x>=0;--x)
{
var zone = engine.zones.children[x].cfg;
//zones expand
if(zone.radius > 0)
{
engine.zones.children[x].scale.x = engine.zones.children[x].scale.y = (zone.radius += zone.expansion*timestep*engine.REAL_ARENA_SIZE_FACTOR);
}
else if(zone.radius < 0) engine.zones.children[x].scale.x = engine.zones.children[x].scale.y = zone.radius = 0;
if(zone.type == "ball" || zone.type == "soccerball")
{
for(var z=engine.zones.children.length-1;z>=0;--z)
{
var z2n = engine.zones.children[z].cfg;
if(
(
(zone.type == "ball" && z2n.type == "fortress") ||
(zone.type == "soccerball" && z2n.type == "soccergoal")
) &&
is_in_circle(z2n.mesh.position.x,z2n.mesh.position.y,z2n.radius,zone.mesh.position.x,zone.mesh.position.y,zone.radius))
{
if(!engine.network && engine.winner == undefined)
{
if(zone.lastHitCycle)
{
if(engine.teams.indexOf(zone.lastHitCycle.team) == z2n.team)
{
engine.console.print(zone.lastHitCycle.getColoredName()+"0xRESETT scored in their own goal and lost a point. Boo!\n");
zone.lastHitCycle.addScore(-1);
}
else
{
engine.console.print(zone.lastHitCycle.getColoredName()+"0xRESETT scored a goal for 1 point.\n");
zone.lastHitCycle.addScore(1);
}
}
- engine.winner = false; startNewRound();
+ engine.winner = false; game.reqNewRound();
}
else
{
zone.xdir *= 1-timestep; zone.ydir *= 1-timestep;
if(!engine.dedicated) centerMessage("Goal!");
}
}
}
if(settings.BALL_SPEED_DECAY)
{
var dir = cdir(Math.atan2(zone.ydir,zone.xdir));
var speed = Math.sqrt((zone.xdir*zone.xdir)+(zone.ydir*zone.ydir));
var decay = settings.BALL_SPEED_DECAY*delta;
if(decay > speed) decay = speed;
speed -= decay;
zone.xdir = dir[0]*speed; zone.ydir = dir[1]*speed;
}
}
else if(zone.type == "flagHeld")
{
zone.mesh.position.x = zone.heldBy.position.x;
zone.mesh.position.y = zone.heldBy.position.y;
var h=[];
for(var z=engine.zones.children.length-1;z>=0;--z)
{
if(zone.type == "flagHeld") { h.push(zone.team); }
}
for(var z=engine.zones.children.length-1;z>=0;--z)
{
var z2n = engine.zones.children[z].cfg;
if(
(zone.type == "flagHeld" && z2n.type == "fortress") &&
is_in_circle(z2n.mesh.position.x,z2n.mesh.position.y,z2n.radius,zone.heldBy.position.x,zone.heldBy.position.y,zone.radius))
{
if(engine.teams.indexOf(zone.heldBy.team) == z2n.team)
{
if(h.length > 1 && h.indexOf(z2n.team) > -1)
{
if(!zone.homeMSG)
{
engine.console.print(zone.heldBy.getColoredName()+"0xRESETT took the enemy flag home, but their team flag must be returned to their base. Get them!\n");
zone.homeMSG = true;
}
}
else
{
engine.console.print(zone.heldBy.getColoredName()+"0xRESETT took the flag to their base for 1 point!\n");
zone.heldBy.addScore(1);
zone.heldBy.hasFlag = null;
zone.type = "flag";
zone.mesh.position.x = zone.px;
zone.mesh.position.y = zone.py;
zone.homeMSG = false;
zone.netSync();
}
}
}
}
}
//zone effect
var inzone = false;
for(var y=engine.players.length-1;y>=0;--y) if(engine.players[y] && engine.players[y].alive)
{
var cycle = engine.players[y];
//dont handle zones we don't need to
if(!zone.netObject/* || zone.type.indexOf("ball") >= 0*/)
{
//var lastdist = zone.distance(cycle.lastpos);
//var dist = zone.distance(cycle.position);
var lastdist = pointDistance(zone.mesh.position.x,zone.mesh.position.y,cycle.lastpos.x,cycle.lastpos.y)-zone.radius;
var dist = pointDistance(zone.mesh.position.x,zone.mesh.position.y,cycle.position.x,cycle.position.y)-zone.radius;
var inZone = (dist <= 0), wasInZone = (lastdist <= 0);
if(inZone)
{
var timediff = cycle.speed*dist;
var hitTime = timeElapsed-timediff;
if(!wasInZone) zone.onEnter(cycle,hitTime,timestep);
if(cycle.alive) zone.onInside(cycle,engine.gtime,timestep);
}
else if(wasInZone) //left zone
{
zone.onLeave(cycle,engine.gtime,timestep); //TODO: figure out "precise" left time
}
else
{
zone.onOutside(cycle,engine.gtime,timestep);
}
}
if(zone.type == "fortress") //fortress recover rate
{
zone.rotationSpeed += (settings.ZONE_SPIN_SPEED-zone.rotationSpeed)*timestep*settings.FORTRESS_CONQUEST_DECAY_RATE;
}
}
if(typeof(zone.xdir)+typeof(zone.ydir) !== "undefinedundefined")
{
if(zone.bounce && zone.mesh.walldist <= timestep)
{
var dir = cdir(Math.atan2(zone.ydir,zone.xdir));
//zone.mesh.position.x -= dir[0]*zone.mesh.walldist; zone.mesh.position.y -= dir[1]*zone.mesh.walldist;
var mindist=Infinity,apc=false;
//var px = zone.mesh.position.x+(zone.mesh.walldist*zone.xdir), py = zone.mesh.position.y+(zone.mesh.walldist*zone.ydir);
var px = zone.mesh.position.x+zone.radius*dir[0], py = zone.mesh.position.y+zone.radius*dir[1];
//lineIntersect(posx,posy,posx+(dir[0]*rg),posy+(dir[1]*rg),w1x,w1y,w2x,w2y)
for(var i=4;i>0;--i)
{
var xdir = Math.sin(Math.PI*2*(i/4)), ydir=Math.cos(Math.PI*2*(i/4));
if(lineIntersect(zone.mesh.position.x,zone.mesh.position.y,zone.mesh.position.x+xdir*(zone.radius+zone.mesh.walldist),zone.mesh.position.y+ydir*(zone.radius+zone.mesh.walldist),zone.mesh.wall[0],zone.mesh.wall[1],zone.mesh.wall[2],zone.mesh.wall[3]))
{
//console.log(i);
switch(i)
{
case 1: zone.xdir = -Math.abs(zone.xdir); break;
case 2: zone.ydir = Math.abs(zone.ydir); break;
case 3: zone.xdir = Math.abs(zone.xdir); break;
case 4: zone.ydir = -Math.abs(zone.ydir); break;
}
apc = true;
}
}
//console.log(apc);
//*/zone.xdir *= -1; zone.ydir *= -1;
//if(!apc) {console.log("?"); zone.xdir *= -1; zone.ydir *= -1;}
var dir = cdir(Math.atan2(zone.ydir,zone.xdir));
//zone.mesh.position.x -= dir[0]*zone.mesh.walldist; zone.mesh.position.y -= dir[1]*zone.mesh.walldist;
zone.mesh.position.x += dir[0]; zone.mesh.position.y += dir[1];
zone.mesh.position.x += zone.xdir*(timestep); zone.mesh.position.y += zone.ydir*(timestep);
if(settings.BALL_SPEED_HIT_DECAY)
{
var speed = Math.sqrt((zone.xdir*zone.xdir)+(zone.ydir*zone.ydir));
var decay = settings.BALL_SPEED_HIT_DECAY*delta;
if(decay > speed) decay = speed;
speed -= decay;
zone.xdir = dir[0]*speed; zone.ydir = dir[1]*speed;
}
zone.netSync();
}
else
{
zone.mesh.position.x += zone.xdir*timestep; zone.mesh.position.y += zone.ydir*timestep;
}
}
}
var dc = Object.keys(engine.delayedcommands);
for(var x=dc.length-1;x>=0;x--)
{
var cmd = engine.delayedcommands[dc[x]];
loadcfg(cmd[0]);
if(dc[x] >= engine.gtime)
{
if(cmd[1] > 0)
{
engine.delayedcommands[dc[x]+cmd[1]] = cmd;
}
delete engine.delayedcommands[dc[x]];
}
}
//if(more) game();
}
else
{
engine.gameRunning = false;
}
}
-function doDeath(cycle,escape=false)
+game.killBlame = function(cycle,escape=false)
{
if(escape || (cycle.sensor.nearestobj == "rim" && !cycle.sensor.lastnonselfobj))
{
if(escape || (
cycle.position.x-cycle.minDistance.front > engine.logicalBox.max.x ||
cycle.position.y-cycle.minDistance.front > engine.logicalBox.max.y ||
cycle.position.x+cycle.minDistance.front < engine.logicalBox.min.x ||
cycle.position.y+cycle.minDistance.front < engine.logicalBox.min.y
))
{
engine.console.print(cycle.getColoredName()+"0xRESETT tried to escape the game grid.\n");
}
else
{
engine.console.print(cycle.getColoredName()+"0xRESETT committed suicide.\n");
}
}
else
{
var objtoaccuse = typeof(cycle.sensor.lastnonselfobj)=="undefined"?cycle.sensor.nearestobj:cycle.sensor.lastnonselfobj;
if(objtoaccuse == cycle)
{
engine.console.print(cycle.getColoredName()+"0xRESETT committed suicide.\n");
}
else if(typeof(objtoaccuse) == "object")
{
engine.console.print(objtoaccuse.getColoredName()+"0xRESETT core dumped "+cycle.getColoredName()+"0xRESETT for 1 point.\n");
objtoaccuse.addScore(1);
}
else
{
engine.console.print(cycle.getColoredName()+"0xRESETT died.\n");
}
}
cycle.kill();
}
-function simulatePlayer(cycle,timestep)
+game.start = function()
{
- console.warn("Deprecated call to simulatePlayer");
- cycle.update(timestep);
-}
-
-function getGoing()
-{
- if(!engine.gameRunning) game();
+ if(!engine.gameRunning) game.run();
if(!engine.renderRunning) render();
}
-function pauseRender()
+game.pause = function()
{
engine.paused = true;//cuts off the loop
engine.startOfPause = performance.now();
audioStop();
}
-function unpauseRender()
+game.unpause = function()
{
for(var ctrl in engine.controls)
{
engine.controls[ctrl] = [];
}
//renderLoop = true;//replaces cutoff
if(engine.paused)
{
engine.paused = false;
audioStart();
engine.lastGameTime = engine.lastRenderTime = engine.fpsTime = performance.now();//resets delta so we don't pretend the game should have been playing the entire time we were paused
var endOfPause = performance.now();
engine.totalPauseTime += (endOfPause - engine.startOfPause);
- getGoing();//starts the loop again
+ game.start();//starts the loop again
}
}
-function changeViewTarget(a=1,forcechange=false)
+game.changeViewTarget = function(a=1,forcechange=false)
{
if(engine.dedicated) return;
if(a != 0)
{
if(!forcechange && engine.players[engine.activePlayer].alive) return;
var first = true; //force the loop to get started
var itcount = 0;
/*if(alive > 0) */while(first || !engine.players[engine.viewTarget] || !engine.players[engine.viewTarget].alive)
{
first = false;
engine.viewTarget+=a;
if(engine.viewTarget >= engine.players.length) engine.viewTarget = 0;
if(engine.viewTarget < 0) engine.viewTarget = engine.players.length+engine.viewTarget;
itcount++;
if(itcount > engine.players.length) break;
//console.log(engine.viewTarget);
}
}
if(engine.view == 'cockpit')
{
for(var x=0;x>engine.players.length;x++)
{
if(x == engine.viewTarget)
engine.players[x].audio.gain.setTargetAtTime(0.2, ctx.currentTime, 0.02);
else
engine.players[x].audio.gain.setTargetAtTime(6, ctx.currentTime, 1);
}
}
if(!engine.network && !engine.players[engine.activePlayer].spectating && typeof(engine.winner) == "undefined")
{
switch(settings.FINISH_TYPE)
{
case 2:
engine.asendtm = 0.2;
centerMessage("Time Warp!",Infinity);
if(engine.hud) engine.hud.fadein = false;
break;
case 3:
centerMessage("Please wait...",Infinity);
setTimeout(function()
{
engine.timemult = 100;
while(typeof(engine.winner) == "undefined") { game(true) }
engine.timemult = 1;
},100);
break;
}
}
engine.console.print("Watching "+engine.players[engine.viewTarget].name+"...\n");
}
-function checkForWinner()
+game.checkForWinner = function()
{
var alivecount = aliveaicount = 0;
var numPlay = 0;
var alive = [], theplayer = false;
var declareRoundWinner = typeof(engine.declareRoundWinner) != "undefined";
for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined")
{
if(!engine.players[x].spectating) numPlay++;
if(engine.players[x].alive)
{
alivecount++;
if(engine.players[x].AI)
aliveaicount++;
alive.push(engine.players[x]);
}
if(declareRoundWinner && engine.players[x].name == engine.declareRoundWinner)
{
engine.winner = engine.players[x];
engine.declareRoundWinner = undefined;
}
}
if(
(declareRoundWinner) ||
(settings.GAME_TYPE == 1 && numPlay > 1 && (alivecount <= 1 || (settings.FINISH_TYPE == 1 && aliveaicount == alivecount))) ||
(/*settings.GAME_TYPE == 0 && */(alivecount <= 0))
)
{
if(!declareRoundWinner)
{
engine.winner = (typeof(alive[0]) == "undefined")?{name:undefined}:alive[0];
}
if(settings.RIM_WALL_COLOR_MODE == 2)
{
if(engine.winner && settings.RIM_WALL_COLOR_MODE == 2)
{
var color = new THREE.Color(engine.winner.cycleColor);
settings.RIM_WALL_RED = color.r;
settings.RIM_WALL_GREEN = color.g;
settings.RIM_WALL_BLUE = color.b;
}
}
if(engine.asendtm > 0) {engine.asendtm = 0; engine.timemult = 1; centerMessage("Time Warp!",0);}
setTimeout(function(){centerMessage("Winner: "+engine.winner.name)},1000);
- if(!window.svr || window.svr.clients.size != 0) startNewRound();
- }//*/
- /*if(aliveaicount == alivecount)
- {
- engine.console.print("Vroom!");
- engine.timemult = 2;
- engine.asendtm = 1.1;
- }//*/
+ if(!window.svr || window.svr.clients.size != 0) game.reqNewRound();
+ }
}
-function startNewRound()
+game.reqNewRound = function()
{
if(typeof(engine.winner) == "undefined") engine.winner = null;
var endin = 4000;
if(engine.round >= settings.LIMIT_ROUNDS)
{
var highscore = -Infinity, highplayer;
for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined")
{
var cycle = engine.players[x];
if(cycle.score > highscore)
{
highplayer = cycle;
highscore = cycle.score;
}
else if(cycle.score == highscore)
{
highplayer = null;
}
}
if(highplayer != null)
{
setTimeout(function(){centerMessage("Match Winner: "+highplayer.name);engine.console.print("Match Winner: "+highplayer.name+" with "+highscore+" points.\n")},4000);
}
engine.round = 0;
endin += 4000;
}
- if(!settings.ROUND_WAIT) engine.uRound = setTimeout(doNewRound,endin);
+ if(!settings.ROUND_WAIT) engine.uRound = setTimeout(game.doNewRound,endin);
}
-function updateScoreBoard()
+game.updateScoreBoard = function()
{
if(window.svr)
{
var tmp = [];
for(var x=engine.players.length-1;x>=0;--x) if(engine.players[x])
{
tmp.push({netid:x,score:engine.players[x].score,ping:engine.players[x].ping,chatting:engine.players[x].chatting});
}
var data = JSON.stringify({type:"scoredata",data:tmp});
window.svr.clients.forEach(function(ws){ws.send(data);});
}
if(engine.network)
{
engine.connection.send(JSON.stringify({type:"playdata",data:{chatting:engine.players[engine.activePlayer].chatting}}));
}
if(engine.dedicated || scoreboard.style.display == "none") return;
var scoreBoard = document.getElementById("scoreboard").children[0];
var playersSB = scoreBoard.children[1];
var tmp = "";
for(var x=0;x<engine.playersByScore.length;++x) if(typeof(engine.playersByScore[x]) != "undefined")
{
var cycle = engine.playersByScore[x];
tmp += "<tr class=\"player\"><td>"+(cycle.chatting?"*":"&nbsp;")+replaceColors(cycle.getColoredName())+"</td><td>"+replaceColors(cycle.alive?"0x00ff00Yes":"0xff0000No")+"</td><td>"+cycle.score+"</td><td>"+cycle.ping+"</td><td>"+(cycle.team?cycle.team.name:"")+"</td><tr>";
}
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<temp_items.length;i++)
{
control = temp_items[i];
//check existing controls and clear other instances of the new control
if(control != specificState[1])
{
if(settings.controls[control].indexOf(keyCode) > -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;i++)
{
if(elem.options[keys[i]] == elem.innerText)
{
elempos = i; break;
}
}
elempos += add;
if(elempos >= 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;x++)
{
if(hasClass(themenu[x],'menu-active')) selectedItem = x; //find which one is selected
}
switch(direction)
{
//change menu position
case "up":
selectedItem--;
if(selectedItem < 0) selectedItem = themenu.length-1; //wrap to last item
hoverSelect(themenu[selectedItem]);
break;
case "down":
selectedItem++;
if(selectedItem >= 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<themenu.length;x++)
{
if(selectedItem >= 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;x<themenu.length;x++)
{
if(hasClass(themenu[x],'menu-active')) themenu[x].className = '';
}
if(item.attributes.id) var stuff = item.attributes.id.value.split(":"); else var stuff = [];
if(stuff[0] != "text")
item.className = 'menu-active';
if(stuff[0] == "var")
{
var txtarea = item.childNodes[0].childNodes[1];
txtarea.focus();
//txtarea.innerText = txtarea.innerText;
}
else
{
item.childNodes[0].focus(); //to detract focus off input boxes
}
}
////////////////////////////////////////
//MENU - changes menus, performs basic actions when menu switching (pause), optional active menu element
function menu(act,from=false)
{
var selectedItem = 0, ract=act;
if(act == "exitmenu")
{
var exitmenu = "menu:"+engine.menus[engine.menus.length-1];
act = "menu:"+engine.menus[engine.menus.length-2];
engine.menus.splice(engine.menus.length-2,2);
}
else if(act == "reload")
{
act = engine.inputState;
engine.menus.splice(engine.menus.length-1,1);
var themenu = document.getElementById('menuList').childNodes;
//detect menu position
var selectedItem = -1;
for(var x=0;x<themenu.length;x++)
{
if(hasClass(themenu[x],'menu-active')) selectedItem = x; //find which one is selected
}
}
var s = act.split(":");
var action = s.shift(); //set action to first argument while removing it
var arg = s.join(":"); //and rejoin them
var split = act.split(":"); //other method
switch(action)
{
case "menu":
engine.concatch = engine.msgcatch = undefined;
document.getElementById("inputbuttons").style.display = "none";
document.getElementById('menu').innerHTML = "<h1>I don't know either</h1>";
var doc = engine.menu.getElementsByTagName("Menus");
if(doc.length > 0)
{
var menus = doc[0].getElementsByTagName("Menu");
for(var x=0;x<menus.length;x++)
{
var cmenu = menus[x];
if(cmenu.attributes.id.value == split[1])
{
if(cmenu.attributes.title)
document.getElementById('menu').innerHTML = "<h1>"+replaceColors(tStringify(cmenu.attributes.title.value))+"</h1>";
var items = cmenu.getElementsByTagName("Item");
var list = document.createElement("UL");
list.setAttribute("id","menuList");
for(var i=0;i<items.length;i++)
{
var item = items[i];
var parent = document.createElement("LI");
var element = document.createElement("A");
//var text = document.createTextNode(item.attributes.text.value);
var text = document.createElement("SPAN");
text.innerHTML = replaceColors(tStringify(item.attributes.text.value));
if(item.attributes.style)
{
parent.setAttribute("style",item.attributes.style.value);
}
if(item.attributes.var || item.attributes.call)
{
//text.appendData(": ");
text.append(": ");
if(item.attributes.type && item.attributes.type.value == "list")
{
parent.setAttribute("id",item.attributes.type.value);
var input = document.createElement("SPAN");
input.options = [];
if(item.attributes.call)
{
input.call = eval(item.attributes.call.value);
}
else
{
input.call = mkSettingCallback(item.attributes.var.value,true);
}
if(item.attributes.from)
{
var si = getVarFromString(item.attributes.from.value);
var subitems = si[0][si[1]];
for(var z=0;z<subitems.length;z++)
{
var option = subitems[z];
input.options[option] = option;
}
}
else
{
var subitems = item.getElementsByTagName("Option");
for(var z=0;z<subitems.length;z++)
{
var option = subitems[z];
input.options[option.attributes.value.value] = tStringify(option.attributes.text.value);
}
}
input.innerHTML = replaceColors(input.options[input.call()])
}
else if(item.attributes.type.value == "keys")
{
var input = document.createElement("SPAN");
var one = settings.controls[item.attributes.var.value];
if(!one)
{
var vri = getVarFromString(item.attributes.var.value);
one = vri[0][vri[1]];
}
var out = "";
console.log(one.length);
for(var z=0;z<one.length;z++)
{
if(z != 0) out += ", ";
out += keycodeList[one[z]];
}
if(out == "") out = "Unbound";
input.appendChild(document.createTextNode(out));
parent.setAttribute("id","controlAR:"+item.attributes.var.value);
}
else
{
parent.setAttribute("id","var:"+item.attributes.var.value+":"+item.attributes.type.value);
var input = document.createElement("SPAN");
input.setAttribute("contenteditable",true);
var vri = getVarFromString(item.attributes.var.value);
input.appendChild(document.createTextNode(vri[0][vri[1]]));
//input.setAttribute("oninput","settings."+item.attributes.var.value+" = this.innerText");
switch(item.attributes.type.value)
{
case "num":
if(item.attributes.range)
{
var spl = item.attributes.range.value.split(",");
var min = parseFloat(spl[0]), max = parseFloat(spl[1]);
}
else
{
var min = -Infinity, max = Infinity;
}
if(item.attributes.add) add = item.attributes.add.value;
else add = 1;
parent.min = min; parent.max = max; parent.add = add;
break;
case "color":
//input.style.color=input.innerText;
input.oninput = function()
{
this.style.color=this.innerText;
//this.style.background=getDarkBGFromHex(this.style.innerText);
}
input.setAttribute("onblur","this.innerText = chsetting(\""+item.attributes.var.value+"\",'#'+(new THREE.Color(this.innerText.toLowerCase()).getHexString()),true);this.oninput()");
input.className += " darktext";
input.oninput();
break;
default:
input.setAttribute("oninput","chsetting(\""+item.attributes.var.value+"\",this.innerText,true)");
break;
}
}
element.setAttribute("href","javascript:void(0);");
}
else
{
var input = false;
if(item.attributes.from)
{
var fromsplit = item.attributes.from.value.split(":");
var obj = {to:text,type:fromsplit[1]?fromsplit[1]:"all"};
switch(fromsplit[0])
{
case "con": engine.concatch = obj; break;
case "msg": engine.msgcatch = obj; break;
}
}
if(item.attributes.type.value != "text")
{
switch(item.attributes.type.value)
{
case "submenu":
parent.setAttribute("id","menu:"+item.attributes.onenter.value);
break;
case "js":
parent.setAttribute("id","js:"+item.attributes.onenter.value);
break;
case "exitmenu":
if(cmenu.attributes.exitmenu)
{
parent.setAttribute("id","js:"+cmenu.attributes.exitmenu.value);
}
else
{
//parent.setAttribute("id",engine.inputState);
parent.setAttribute("id","exitmenu");
}
break;
default:
parent.setAttribute("id",item.attributes.type.value);
break;
}
element.setAttribute("href","javascript:void(0);");
}
}
element.setAttribute("onmouseover","hoverSelect(this.parentNode)");
element.setAttribute("onclick","menu(this.parentNode.id)");
element.appendChild(text);
if(input !== false) element.appendChild(input);
parent.appendChild(element);
list.appendChild(parent);
}
engine.inputState = "menu:"+cmenu.attributes.id.value;
document.getElementById('menu').appendChild(list);
if(ract == "exitmenu") //select the menu we just left
{
var themenu = document.getElementById('menuList').childNodes;
for(var x=0;x<themenu.length;x++)
{
if(exitmenu == themenu[x].id) selectedItem = x;
}
}
hoverSelect(document.getElementById("menuList").children[selectedItem])
engine.menus.push(cmenu.attributes.id.value);
return true;
}
}
}
console.log("Menu called not found.");
break;
case "controlAR":
engine.inputState = act;
document.getElementById('menuList').getElementsByClassName("menu-active")[0].childNodes[0].childNodes[1].innerHTML = "Press a key...";
document.getElementById("inputbuttons").style.display = "block";
break;
case "var": case "list":
changeMenuItem(action,1,true,from,"menu")
break;
case "js":
return eval(arg);
break;
case "leave"://return to main menu from pause state
- endGame(); disconnectFromGame();
+ game.end(); disconnectFromGame();
engine.menus = []; menu("menu:main");
document.getElementById('menu').className = "noselect mainbg_"+settings.MENU_RENDER;
aamenurender(); showMenu();
document.title = tStringify("@progtitleshort@");
break;
case 'quit'://quit game action from any menu
window.open('','_self',''); window.close(); location.replace('about:blank');
break;
case 'unpause'://return to game from pause menu
document.getElementById('menu').style.display = 'none';
if(engine.paused) { unpauseRender(); }
engine.inputState = 'game';
break;
default:
console.log("What's this? "+action);
return false;
}
}
function pauseMenuToggle()
{
if(engine.inputState == "game")
{
if(engine.network)
{
engine.players[engine.activePlayer].chatting=true;
}
else
{
- pauseRender();
+ game.pause();
}
menuSetup(true);
menu('menu:pause'); showMenu();
}
else
{
if(engine.network)
{
engine.players[engine.activePlayer].chatting=false;
}
- unpauseRender();
+ game.unpause();
hideMenu(); engine.inputState = 'game';
}
}
function menuSetup(game=false)
{
if(game) //ingame menu
{
document.getElementById('menu').className = "noselect pausebg";
document.getElementById('menu').style.backgroundColor = "";
}
else
{
aamenurender(); //let render selection handle it
}
}
function hideMenu()
{
document.getElementById('menu').style.display = 'none'; //hide menu
}
function showMenu()
{
document.getElementById('menu').style.display = 'block'; //show menu
}
diff --git a/scripts/player.js b/scripts/player.js
index a02fe71..db32cfa 100644
--- a/scripts/player.js
+++ b/scripts/player.js
@@ -1,639 +1,639 @@
/*
* 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');
class Player extends THREE.Object3D
{
setScore(x)
{
this.score = (x*1)||0;
engine.playersByScore.sort(function(a,b){return b.score-a.score});
- if(engine.playersByScore.indexOf(this) > -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<len;x++)
{
this.walls.remove(this.walls.children[x]);
}
}
var wmap = this.walls.map, wallmod;
for(var x=1,len=wmap.length;x<len;x++)
{
if(full === true || !this.walls.children[x-1])
{
this.walls.add(wallmod = newWall(this.tailColor,wmap[x-1][0],wmap[x-1][1],wmap[x-1][2]));
}
else
{
wallmod = this.walls.children[x-1];
wallmod.position.set(wmap[x-1][0],wmap[x-1][1],wmap[x-1][2]||0);
}
wallmod.scale.x = (wmap[x][0]-wmap[x-1][0])/wallmod.size;
wallmod.scale.y = (wmap[x][1]-wmap[x-1][1])/wallmod.size;
}
if(full !== true)
{
for(;x<this.walls.length;x++)
{
this.walls.remove(this.walls.children[x]);
}
}
this.calcWallLength();
}
turn(dir)
{
if(dir != -1 && dir != 1) return false;
this.turnQueue.push(dir);
}
turnAbs(dirX,dirY)
{
var ang = Math.atan2(this.position.y+dirY,this.position.x+dirX);
centerMessage(ang,500);
if(ang > 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<engine.map.walls.length;y++)
{
for(var i=0;i<engine.map.walls[y].length;i++)
{
var p = engine.map.walls[y][i].split(",");
var w1x = p[0],w1y = p[1];
if(engine.map.walls[y][i+1] !== undefined)
{
var p = engine.map.walls[y][i+1].split(",");
var w2x = p[0],w2y = p[1];
if(lineIntersect(posx,posy,posx+(dir[0]/4),posy+(dir[1]/4),w1x,w1y,w2x,w2y))
{
//console.log("Hitting wall");
collided = true;
}
}
}
}*/
var collided = (this.sensor.front <= this.minDistance.front); //potential replacement for above code
//var collided = false;
/*if(collided || (escape && settings.ARENA_BOUNDARY_KILLS))
{
this.collidetime = Infinity; //we've collided, no need to check
}
else*/
{
//var newx = dir[0]*this.speed*timestep, newy = dir[1]*this.speed*timestep;
var dist = this.speed*timestep, radj = dist;
if(dist < 0) dist = 0;
if(this.collidetime <= timeElapsed)
{
//this.rubber += timestep*(this.lastSpeed);
collided = true;
var adjdist = (((timeElapsed-this.collidetime)/1000)*this.lastSpeed);
radj = timestep;
//radj = adjdist;
radj *= this.lastSpeed;
dist -= adjdist;
//console.warn(x+" should have collided: "+(this.collidetime-timeElapsed)+"ms\n");
}
//if((dir[0]==0?0:(newx/dir[0]))+(dir[1]==0?0:(newx/dir[1])) >= 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<engine.teams.length;w++)
{
var disValue = pointDistance(engine.teams[w].x,engine.teams[w].y, prop.x, prop.y);
if (disValue < lastDist) { lastDist = disValue; closestSpawn = w; }
}
}
else
{
for(var w=0;w<engine.map.spawns.length;w++)
{
var checkx = engine.map.spawns[w][0];
var checky = engine.map.spawns[w][1];
var disValue = pointDistance( checkx, checky, prop.x, prop.y );
if (disValue < lastDist) { lastDist = disValue; closestSpawn = w; }
}
}
if (closestSpawn > 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<prop.points.length;i++)
{
var point = prop.points[i];
//point[0] += (1*prop.x)||0; point[1] += (1*prop.y)||0;
geo.vertices[i] = new THREE.Vector3(point[0],point[1],0);
geo.vertices[prop.points.length+i] = new THREE.Vector3(point[0],point[1],zoneHeight);
for(var z=1;z>=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;i<halfvert;i++)
{
var p1x = geo.vertices[i].x, p1y = geo.vertices[i].y;
var p2x = geo.vertices[i+1].x, p2y = geo.vertices[i+1].y;
var dist = Math.sqrt( (p2x-=p1x)*p2x + (p2y-=p1y)*p2y );
var normal = new THREE.Vector3( (p2y - p1y), -(p2x - p1x), 0 );
geo.faces.push(
new THREE.Face3( (i), (i+1), (i+(geo.vertices.length/2)), normal ), //a,b,c
new THREE.Face3( (i+(geo.vertices.length/2)+1), (i+(geo.vertices.length/2)), (i+1), normal ) //d,c,b
);
}
//prop.x = (max[0]-min[0])/2; prop.y = (max[1]-min[1])/2;
//this.radius = (max[0]<max[1]?max[0]:max[1])-(min[0]>min[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;

File Metadata

Mime Type
text/x-diff
Expires
Mon, Jun 23, 9:33 PM (3 d, 23 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
11295

Event Timeline