Page MenuHomePhabricator

No OneTemporary

diff --git a/layout/menu.xml b/layout/menu.xml
index da83f08..f419097 100644
--- a/layout/menu.xml
+++ b/layout/menu.xml
@@ -1,315 +1,317 @@
<?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="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="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" call="aamenurender" 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="submenu" onenter="input_conf" text="Set Controls"/>
<Item type="exitmenu" text="Back to main menu"/>
</Menu>
</Menus>
diff --git a/scripts/config.js b/scripts/config.js
index 7e111b5..4eeb182 100644
--- a/scripts/config.js
+++ b/scripts/config.js
@@ -1,1498 +1,1502 @@
/*
* 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.
*/
/*class Setting
{
constructor(conf)
{
switch(typeof(conf))
{
case "object": this = conf; break;
}
}
push()
{
settings_work[this.name] = this;
settings[this.name] = this.val;
}
}
//new Setting({name:"VERIFY_COLOR_STRICT",val:false}).push();
var settings_work = {};*/
settings = {
VERIFY_COLOR_STRICT: false,
TEXT_BRIGHTEN: false,
TEXT_DARK_HIGHLIGHT: true,
FONT_MIN_R: 0.5, FONT_MIN_G: 0.5, FONT_MIN_B: 0.5,
FONT_MIN_TOTAL: 0.7,
CHAT_LAYER: 0.5,
TEXT_OUT: function(params=undefined){if(params !== undefined) engine.console.style.display=params?"block":"none"; return engine.console.style.display!="none";},
TEXT_OUT_MODE: 1,
FULLSCREEN: function(params=undefined){
if(params !== undefined)
{
var bd = document.body;
if(params)
{
if(bd.requestFullscreen) bd.requestFullscreen();
else if(bd.webkitRequestFullscreen) bd.webkitRequestFullscreen();
else if(bd.mozRequestFullScreen) bd.mozRequestFullScreen();
else if(bd.msRequestFullscreen) bd.msRequestFullscreen();
else alert("Can't go into fullscreen. Please alert nelg with information on what browser you're using.")
}
else
{
if(bd.exitFullscreen) bd.exitFullscreen();
else if(document.webkitExitFullscreen) document.webkitExitFullscreen();
else if(document.mozCancelFullScreen) document.mozCancelFullScreen();
//else if(document.msCancelFullscreen) bd.msCancelFullscreen();
else alert("Can't exit fullscreen. Please alert nelg with information on what browser you're using")
}
}
return Boolean(window.fullScreen || document.mozFullScreen || document.msFullScreen || document.webkitIsFullScreen || window.outerHeight - window.innerHeight <= 1);
},
//CAMERA
CAMERA_FOV: 60,
CAMERA_NEAR_RENDER: 0.001,
CAMERA_FAR_RENDER: 2000,
//GAME
GRID_SIZE: 1,
/*FLOOR_RED: 0.75,
FLOOR_GREEN: 0.75,
FLOOR_BLUE: 0.98,*/
FLOOR_RED: 0.03,
FLOOR_GREEN: 0.266,
FLOOR_BLUE: 0.8,
FLOOR_TEXTURE: "textures/floor.png",
/*GRID_SIZE: 2,
FLOOR_RED: 1,
FLOOR_GREEN: 1,
FLOOR_BLUE: 1,
FLOOR_TEXTURE: "textures/moviepack_t_r_u_e/floor.png",*/
/*GRID_SIZE: 1,
FLOOR_RED: 0.01,
FLOOR_GREEN: 0.14,
FLOOR_BLUE: 0.35,
FLOOR_TEXTURE: "textures/aaold/floor.png",*/
FLOOR_MIRROR: false,
FLOOR_MIRROR_INT: 1,
CYCLE_TEXTURES: ["textures/cycle_body.png","textures/cycle_wheel.png"],
EXPLOSIONS: true,
HIGH_RIM: false,
LOW_RIM_HEIGHT: 50,
RIM_WALL_RED: 0,
RIM_WALL_GREEN: 0, // 0.533
RIM_WALL_BLUE: 0, // 1
RIM_WALL_ALPHA: 0.9,
RIM_WALL_COLOR_MODE: 3,
RIM_WALL_STRETCH_X: 50,
RIM_WALL_STRETCH_Y: 13.5,
RIM_WALL_WRAP_Y: false,
RIM_WALL_REPEAT_TOP: false,
RIM_WALL_TEXTURE: "textures/futurerim.png",
RIM_WALL_DEPTH: true,
RIM_WALL_LOWEST_HEIGHT: 0,
RIM_WALL_BELOW_HEIGHT_COLOR_R: 0,
RIM_WALL_BELOW_HEIGHT_COLOR_G: 0,
RIM_WALL_BELOW_HEIGHT_COLOR_B: 0,
/*RIM_WALL_RED: 1,
RIM_WALL_GREEN: 1,
RIM_WALL_BLUE: 1,
RIM_WALL_ALPHA: 1,
RIM_WALL_COLOR_MODE: 0,
//RIM_WALL_STRETCH_X: 300,
//RIM_WALL_STRETCH_Y: 50,
RIM_WALL_STRETCH_X: 128,
RIM_WALL_STRETCH_Y: 32,
LOW_RIM_HEIGHT: 32,
RIM_WALL_WRAP_Y: false,
RIM_WALL_TEXTURE: "textures/moviepack_eddkeefe/rim_wall.png",
RIM_WALL_LOWEST_HEIGHT: 32,
RIM_WALL_BELOW_HEIGHT_COLOR_R: 166/255,
RIM_WALL_BELOW_HEIGHT_COLOR_G: 45/255,
RIM_WALL_BELOW_HEIGHT_COLOR_B: 237/255,//*/
RIM_WALL_RED: 1,
RIM_WALL_GREEN: 1,
RIM_WALL_BLUE: 1,
RIM_WALL_ALPHA: 1,
RIM_WALL_COLOR_MODE: 0,
//RIM_WALL_STRETCH_X: 300,
//RIM_WALL_STRETCH_Y: 50,
RIM_WALL_STRETCH_X: 1536,
RIM_WALL_STRETCH_Y: 32,
LOW_RIM_HEIGHT: 32,
RIM_WALL_WRAP_Y: false,
RIM_WALL_TEXTURE: "textures/moviepack_t_r_u_e/movie-rim-wall.png",
RIM_WALL_DEPTH: true,
RIM_WALL_LOWEST_HEIGHT: 32,
/*RIM_WALL_BELOW_HEIGHT_COLOR_R: 188/255,
RIM_WALL_BELOW_HEIGHT_COLOR_G: 206/255,
RIM_WALL_BELOW_HEIGHT_COLOR_B: 250/255,//*/
RIM_WALL_BELOW_HEIGHT_COLOR_R: 0.5,
RIM_WALL_BELOW_HEIGHT_COLOR_G: 0.5,
RIM_WALL_BELOW_HEIGHT_COLOR_B: 0.7,
COLOR_MODE_3_COLORS: "1,0,0;1,1,0;0,1,0;0,1,1;0,0,1;1,0,1",
COLOR_MODE_3_SPEED: 0.2,
ALPHA_BLEND: true,
MENU_RENDER: "img",
REDRAW_MODE: 0,
TARGET_FPS: 1,
MAX_TARGET_FPS: 1000,
//DEDICATED_FPS: Infinity,
DEDICATED_FPS: 40,
GRAB_SENSORS_ON_TURN: true,
CYCLE_SENSORS_RANGE: 100,
GAME_LOOP: 0.5,
TIME_FACTOR: 1,
HUD_MAP: true,
ADMIN_KILL_MESSAGE: true,
//SOUNDS
SOUNDS_INTRO: false,
SOUNDS_EXTRO: false,
SOUNDS_COUNTDOWN: true,
SOUNDS_GO: false,
SOUNDS_ZONES: false,
MUSIC: 0,
//ZONES
ZONE_HEIGHT: 5,
ZONE_SEGMENTS: 11,//arma render only
ZONE_SEG_LENGTH: 0.5,//arma render only
ZONE_ALPHA: 0.7,
ZONE_SPIN_SPEED: 0.05,
ZONE_RENDER_TYPE: 'arma',//cylinder or arma
//player (for armagetron nabs) //can't have people changing these on a server
PLAYER_1: function(val) { if(engine.dedicated) return (settings.PLAYER_1 = "Player 1"); if(typeof(val) != "undefined") {settings.players[0].name=val;} return settings.players[0].name; },
COLOR_R_1: function(r=undefined) { if(engine.dedicated) return (settings.COLOR_R_1=13); return plnumcolors({r:r}).r },
COLOR_G_1: function(g=undefined) { if(engine.dedicated) return (settings.COLOR_G_1=13); return plnumcolors({g:g}).g },
COLOR_B_1: function(b=undefined) { if(engine.dedicated) return (settings.COLOR_B_1=0); return plnumcolors({b:b}).b },
PLAYER_DEL_HIST_PERROUND: true, //what was this?
TIMESTEP_MAX: 0.2,
//debug
DEBUG_EVERYONE_IS_AI: false,
HACK_TURN_LEFT_WHEN_POSSIBLE: 0,
HACK_TURN_RIGHT_WHEN_POSSIBLE: 0,
HACK_TURN_SENSOR_DIST: 5,
CHATBOT_ALWAYS_ACTIVE: false,
//NETWORK
CONNECT_PORT: 5331,
CONNECT_HOST: "armagetron.kevinh.us",
CONNECT_SSL: true,
CYCLE_SMOOTH_TIME: 0.3,
CYCLE_SYNC_INTERVAL: 0.1,
DEBUG_NETWORK_TURN_WAIT: true,
SERVER_PORT: 5331,
SERVER_NAME: "Unnamed Server",
SERVER_DNS: "",
SERVER_SSL_ENABLED: false,
SERVER_SSL_KEY: "",
SERVER_SSL_CERT: "",
};
if(!Detector.webgl)
{
//choose better defaults for the software renderer
settings.HIGH_RIM = false;
settings.LOW_RIM_HEIGHT = 4;
settings.RIM_WALL_TEXTURE = "";
settings.RIM_WALL_DEPTH = false;
settings.ALPHA_BLEND = false;
}
game_settings_default = {
AI_FORCE_BRAKE: false,
AI_TEAM: false,
AI_DUAL_COLOR_NAME: false,
//CYCLE
CYCLE_ACCEL: 10,
CYCLE_ACCEL_ENEMY: 1,
CYCLE_ACCEL_OFFSET: 2,
CYCLE_ACCEL_RIM: 0,
CYCLE_ACCEL_SELF: 1,
CYCLE_ACCEL_SLINGSHOT: 1,
CYCLE_ACCEL_TEAM: 1,
CYCLE_ACCEL_TUNNEL: 1,
CYCLE_WALL_NEAR: 6,
CYCLE_BRAKE: 30,
CYCLE_BRAKE_DEPLETE: 1,
CYCLE_BRAKE_REFILL: 0.1,
CYCLE_BOOST: 0,
CYCLE_JUMP: 0.5,
CYCLE_JUMP: 0,
CYCLE_MIDAIR_JUMP: false,
CYCLE_MIDAIR_TURN: false,
CYCLE_WALL_RAMP_ENABLE: true,
CYCLE_DELAY: 0.02,
CYCLE_RUBBER: 5,
CYCLE_RUBBER_TIME: 10,
//CYCLE_RUBBER_TIMEBASED: 0,
CYCLE_RUBBER_MINDISTANCE: 0.03,
CYCLE_RUBBER_MINADJUST: 0.05,
CYCLE_RUBBER_DEPLETE_RIM: true,
CYCLE_RUBBER_DEPLETE_SELF: true,
CYCLE_RUBBER_DEPLETE_ENEMY: true,
CYCLE_SOUND_SPEED: 30,
CYCLE_SPEED: 20,
CYCLE_SPEED_DECAY_ABOVE: 0.1,
CYCLE_SPEED_DECAY_BELOW: 5,
CYCLE_SPEED_MAX: 0,
CYCLE_SPEED_MIN: 0.25,
CYCLE_START_SPEED: 20,
CYCLE_TURN_MEMORY: 3,
CYCLE_TURN_SPEED_FACTOR: 0.95,
WALLS_LENGTH: 600,
//WALLS_LENGTH: 30,
RESPAWN_TIME: -1,
CYCLE_FIRST_SPAWN_PROTECTION: false,
CYCLE_WALL_TIME: 5,
CYCLE_INVULNERABILITY_TIME: -1,
WALLS_STAY_UP_DELAY: 1,
SP_HUMANS_COUNT: 1,
//TEAMS
TEAMS_MAX_PLAYERS: 1,
TEAMS_MIN_PLAYERS: 1,
TEAMS_MAX: 16,
//TEAMS_MIN: 4,
TEAMS_MIN: 2,
TEAM_ALLOW_SHUFFLE_UP: 0,
ALLOW_TEAM_NAME_PLAYER: true,
ALLOW_TEAM_NAME_COLOR: true,
MIN_PLAYERS: 1,
NUM_AIS: 0,
SP_NUM_AIS: 3,
TEAM_NAME_1: "Team Blue", //name of team 1
TEAM_RED_1: 4, //red portion of team 1's color
TEAM_GREEN_1: 8, //green portion of team 1's color
TEAM_BLUE_1: 15, //blue portion of team 1's color
TEAM_NAME_2: "Team Gold", //name of team 2
TEAM_RED_2: 15, //red portion of team 2's color
TEAM_GREEN_2: 15, //green portion of team 2's color
TEAM_BLUE_2: 4, //blue portion of team 2's color
TEAM_NAME_3: "Team Red", //name of team 3
TEAM_RED_3: 15, //red portion of team 3's color
TEAM_GREEN_3: 4, //green portion of team 3's color
TEAM_BLUE_3: 4, //blue portion of team 3's color
TEAM_NAME_4: "Team Green", //name of team 4
TEAM_RED_4: 4, //red portion of team 4's color
TEAM_GREEN_4: 15, //green portion of team 4's color
TEAM_BLUE_4: 4, //blue portion of team 4's color
TEAM_NAME_5: "Team Violet", //name of team 5
TEAM_RED_5: 15, //red portion of team 5's color
TEAM_GREEN_5: 4, //green portion of team 5's color
TEAM_BLUE_5: 15, //blue portion of team 5's color
TEAM_NAME_6: "Team Cyan", //name of team 6
TEAM_RED_6: 4, //red portion of team 6's color
TEAM_GREEN_6: 15, //green portion of team 6's color
TEAM_BLUE_6: 15, //blue portion of team 6's color
TEAM_NAME_7: "Team White", //name of team 7
TEAM_RED_7: 15, //red portion of team 7's color
TEAM_GREEN_7: 15, //green portion of team 7's color
TEAM_BLUE_7: 15, //blue portion of team 7's color
TEAM_NAME_8: "Team Black", //name of team 8
TEAM_RED_8: 0, //red portion of team 8's color
TEAM_GREEN_8: 0, //green portion of team 8's color
TEAM_BLUE_8: 0, //blue portion of team 8's color
//MAP
ARENA_AXES: 4,
STRICT_AXES_SPAWN: true,
RESOURCE_REPOSITORY_CACHE: './cache/resource/',
MAP_FILE: 'Anonymous/polygon/regular/square-1.0.1.aamap.xml',
MAP_ROTATION: "",
ROTATION_TYPE: 0, //1:round, 2:match
RESOURCE_REPOSITORY_SERVER: 'https://www.armanelgtron.tk/armagetronad/resource/',
//RESOURCE_REPOSITORY_BACKUP: 'http://resource.armagetronad.net/resource/',
SIZE_FACTOR: -3,
ARENA_BOUNDARY: -10,
ARENA_BOUNDARY_KILLS: true,
ZONE_ALPHA_SERVER: 1,
//GAME PLAY
GAME_TYPE: 1,
FINISH_TYPE: 2,
LIMIT_ROUNDS: 10,
LIMIT_TIME: 30,
LIMIT_SCORE: 100,
ROUND_WAIT: false,
//SHOOTING
SHOT_THRESH: 2,
//WIN ZONE
WIN_ZONE_DEATHS: false,
WIN_ZONE_EXPANSION: 1,
WIN_ZONE_INITIAL_SIZE: 5,
WIN_ZONE_RANDOMNESS: 0.8,
WIN_ZONE_MIN_LAST_DEATH: 30,
WIN_ZONE_MIN_ROUND_TIME: Infinity, //60
//FORTRESS
FORTRESS_CONQUEST_RATE: 0.5,
FORTRESS_CONQUEST_DECAY_RATE: 0.1,
//SPAWN
SPAWN_WINGMEN_SIDE: 2.75362,
SPAWN_WINGMEN_BACK: 2.202896,
//ROUNDLY
ROUND_COMMAND: "",
ROUND_CONSOLE_MESSAGE: "",
ROUND_CENTER_MESSAGE: "",
//TARGET
DEFAULT_TARGET_COMMAND: "",
//TARGET_DECLARE_WINNER: true,
//TARGET_LIFETIME: -1,
TARGET_INITIAL_SCORE: 10,
//TARGET_SCORE_DEPLETE: 2,
//TARGET_SURVIVE_TIME: 10,
//BALL
BALL_SPEED_DECAY: 0,
BALL_SPEED_HIT_DECAY: 0,
};
var sets = Object.keys(game_settings_default);
for(var i=0;i<sets.length;i++)
{
settings[sets[i]] = game_settings_default[sets[i]];
}
//possible admin commands (methods)
var commands = {
TOGGLE: function(params)
{
var split = params.split(" ");
if(split.length == 0)
{
engine.console.print("Usage: TOGGLE command <arguments to toggle between, seperated by a space>");
engine.console.print("If no additional arguments, toggles boolean commands between true and false.")
return false;
}
var cmd = split[0].toUpperCase();
if(split.length > 1)
{
var curr = chsetting(cmd,undefined,true), s = 0;
for(var i=0;i<split.length;i++)
{
if(curr = split[i]) s = i+1;
}
chsetting(cmd,split[s]);
}
else
{
chsetting(cmd,!chsetting(cmd,undefined,true));
}
},
CMD_VAL_ADD: function(params)
{
var split = params.split(" ");
split[0] = split[0].toUpperCase();
var from = chsetting(split[0],"",true);
var to = null;
switch(typeof(from))
{
case "number":
to = from+(split[1]*1);
break;
case "string":
to = from+split[1];
break;
}
chsetting(split[0],to);
},
CMD_PASS_FUNC: function(params)
{
params=params.replace(/rand\((\d+),(\d+)\)/g,function(arg,v1,v2)
{
console.log(arg,v1,v2);
return Math.round((Math.random()*(v2-v1))+v1);
});
loadcfg(params);
},
DELAY_COMMAND: function(params)
{
var interval=0,delay=0,cmd="";
var s = params.split(" ");
if(s[0][0] == "r") //assume repeat
{
interval = 1*(s.slice(0,1)[0].substr(1));
}
if(s[0][0] == "+")
{
delay = engine.gtime+(1*(s.slice(0,1)[0].substr(1)));
}
else
{
delay = 1*s.slice(0,1);
}
cmd = s.join(" ");
engine.delayedcommands[delay] = [cmd,interval];
engine.console.print("Delay command: \""+cmd+"\" at "+delay+"s, interval "+interval+"s.");
},
DELAY_COMMAND_CLEAR: function(params)
{
engine.delayedcommands = {};
engine.console.print("Cleared all delayed commands.");
},
MERGE_OBJ: function(params)
{
var pos = params.indexOf(" ");
var name = params.substr(0,pos), cfg = JSON.parse(params.substr(pos+1));
var sets = Object.keys(cfg);
for(var i=0;i<sets.length;i++)
{
if(typeof(settings[name][sets[i]]) != "undefined") settings[name][sets[i]] = cfg[sets[i]];
}
},
FLOOR_RED: updategrid, FLOOR_GREEN: updategrid, FLOOR_BLUE: updategrid, GRID_SIZE: updategrid,
CAMERA_FOV: function() {if(engine.camera){engine.camera.fov=settings.CAMERA_FOV;engine.camera.updateProjectionMatrix()}},
CAMERA_NEAR_RENDER: function() {if(engine.camera){engine.camera.near=settings.CAMERA_NEAR_RENDER;engine.camera.updateProjectionMatrix()}},
CAMERA_FAR_RENDER: function() {if(engine.camera){engine.camera.far=settings.CAMERA_FAR_RENDER;engine.camera.updateProjectionMatrix()}},
HUD_MAP: function()
{
document.getElementById("canvas").style.display = settings.HUD_MAP?"block":"none";
},
START_NEW_MATCH: function()
{
engine.round = 0;
engine.console.print("Resetting scores and starting new match after this round.");
centerMessage("New Match");
},
CONSOLE_MESSAGE: function(param) { engine.console.print(param+"\n") },
CENTER_MESSAGE: function(param) { centerMessage(param) },
SET_CYCLE_SPEED: function(params)
{
var s = params.split(" ");
var p = getPlayer(s[0]);
if(p) p.speed = s[1]*1;
},
SET_CYCLE_RUBBER: function(params)
{
var s = params.split(" ");
var p = getPlayer(s[0]);
if(p) p.rubber = s[1]*1;
},
SET_CYCLE_BRAKING: function(params)
{
var s = params.split(" ");
var p = getPlayer(s[0]);
if(p) p.braking = Boolean(1*s[1]);
},
SET_CYCLE_BRAKE: function(params)
{
var s = params.split(" ");
var p = getPlayer(s[0]);
if(p) p.brakes = s[2]*1;
},
RESPAWN: function(params)
{
var s = params.split(" ")
var p = getPlayer(s[0]);
if(p)
{
var cfg = {x:0,y:0,z:0,dir:0};
if(s.length > 2)
{
cfg.x = s[1]*engine.REAL_ARENA_SIZE_FACTOR; cfg.y = s[2]*engine.REAL_ARENA_SIZE_FACTOR;
if(s.length > 4)
{
cfg.dir = Math.atan2(s[4],s[3]);
if(settings.STRICT_AXES_SPAWN)
{
var deg = (pi(2)/settings.ARENA_AXES);
cfg.dir = Math.round(cfg.dir/deg)*deg;
}
}
}
p.spawn(cfg);
}
},
KILL: function(params)
{
var p = getPlayer(params);
if(p)
{
p.kill();
if(settings.ADMIN_KILL_MESSAGE)
engine.console.print(p.getColoredName()+"0xRESETT has been smitten by an administrator.\n");
}
},
KILL_ALL: function()
{
for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined")
{
engine.players[x].kill();
}
},
RESPAWN_ALL: function()
{
for(var x=engine.players.length-1;x>=0;--x) if(typeof(engine.players[x]) != "undefined")
{
var cycle = engine.players[x];
cycle.spawn({x:cycle.position.x||0,y:cycle.position.y||0,z:cycle.position.z||0,dir:cycle.rotation.z||0});
}
},
INCLUDE: function(params,silent=false,callback=undefined)
{
var file = params.replace(/\(.+\)/g,"");
var s = localStorage.getItem(file);
if(s == null && !engine.dedicated)
{
var incfile = settings.RESOURCE_REPOSITORY_CACHE+"../config/"+params;
engine.console.print("Loading CFG from "+incfile+"...\n");
httpGetAsync(incfile,function(txt){loadcfg(txt,silent);if(callback != undefined)callback();});
}
else
{
loadcfg(s,silent); if(callback != undefined)callback();
}
},
SINCLUDE: function(params) { commands.INCLUDE(params,true) },
RINCLUDE: function(params,callback=undefined)
{
var file = params.replace(/\(.+\)/g,"");
var incfile = settings.RESOURCE_REPOSITORY_SERVER+params;
engine.console.print("Downloading CFG from "+incfile+"...\n");
httpGetAsync(incfile,function(txt){loadcfg(txt);if(callback != undefined)callback();});
},
SPAWN_ZONE: function(params)
{
if(params == "")
{
engine.console.print("Usage:\nSPAWN_ZONE <win|death|ball|target|blast|object|koh> <x> <y> <size> <growth> <xdir> <ydir> <interactive> <r> <g> <b>\nSPAWN_ZONE <acceleration|speed> <speed> <x> <y> <size> <growth> <xdir> <ydir> <interactive> <r> <g> <b>\nSPAWN_ZONE <rubber|rubberadjust> <x> <y> <size> <growth> <xdir> <ydir> <rubber> <interactive> <r> <g> <b>\nSPAWN_ZONE <fortress|flag> <x> <y> <size> <growth> <xdir> <ydir> <interactive> <r> <g> <b>\n\nInstead of <x> <y> one can write: L <x1> <y1> <x2> <y2> [...] Z\nInstead of <size> one can write: P <scale> <x1> <y1> <x2> <y2> [...] Z");
}
else
{
var zone = {}, args = params.split(" ");
if(args[0] == "n")
{
zone.name = args.slice(0,2)[1];
}
zone.type = args[0];
if(zone.type == "acceleration" || zone.type == "speed")
{
zone.value = args.slice(1,2)[0];
}
if(args[1] === "L")
{
for(var i=2;args[i]=="Z"||i>args.length;i+=2)
{
if(i == 2)
{
zone.x = args[i] *engine.REAL_ARENA_SIZE_FACTOR;
zone.y = args[i+1]*engine.REAL_ARENA_SIZE_FACTOR;
}
}
args.slice(2,i);
}
else
{
zone.x = args[1]*engine.REAL_ARENA_SIZE_FACTOR;
zone.y = args[2]*engine.REAL_ARENA_SIZE_FACTOR;
}
if(args[3] === "P")
{
engine.console.print("WARNING: ShapePolygon may not currently work. Use at your own risk.\n",false);
for(var i=3;args[i]=="Z"||i>args.length;i+=2)
{
}
args.slice(3,i);
}
else
{
zone.radius = args[3]*engine.REAL_ARENA_SIZE_FACTOR;
}
zone.expansion = args[4]*1;
zone.xdir = args[5]*1; zone.ydir = args[6]*1;
zone.bounce = Boolean(parseInt+(args[7]))&&args[7]!="false";
if(args[7] != undefined)
{
zone.color = new THREE.Color(args[7]/15,args[8]/15,args[9]/15);
}
new Zone(zone).spawn().netSync();
//console.log("new Zone: "+zone);
}
},
SPAWN_WALL: function(params)
{
if(params == "")
{
engine.console.print("Usage:\nSPAWN_WALL <height> <x1> <y1> <x2> <y2> [...]\n");
}
else
{
var params = params.split(" "), height = params.slice(0,1)[0]*1, points = [];
for(var q=0;q<params.length;q+=2)
{
points.push(
[
params[q]*engine.REAL_ARENA_SIZE_FACTOR,
params[q+1]*engine.REAL_ARENA_SIZE_FACTOR,
0, height
]
);
}
engine.walls.add(buildWall(points,height));
engine.map.walls.push(points);
}
},
SET_ZONE_POSITION: function(params)
{
var args = params.split(" ");
for(var x=engine.zones.children.length-1;x>=0;x--)
{
if(x == args[0])
{
engine.zones.children[x].position.x = args[1]*engine.REAL_ARENA_SIZE_FACTOR;
engine.zones.children[x].position.y = args[2]*engine.REAL_ARENA_SIZE_FACTOR;
engine.zones.children[x].netSync();
return true;
}
}
engine.console.print("Invalid zone ID\n");
},
SET_AI_PATH: function(params)
{
var args = params.split(" ");
if(args[0] == "*")
{
}
else
{
var cycle = getPlayer(args.shift());
if(cycle)
{
for(var x=0,len=args.length;x<0;x+=2)
{
cycle.push([args[x],args[x+1]]);
}
}
else
{
engine.console.print("Usage: <AI Player name> <x1> <y1> <x2> <y2> ...");
}
}
},
CLEAR_AI_POSITION: function(params)
{
},
LIST_ZONES: function(params="")
{
var found = 0;
for(var x=0,len=engine.zones.children.length;x<len;x++)
{
var outputstr = "ID "+x+": ";
if(params == "" || outputstr.indexOf(params))
{
var zone = engine.zones[x];
engine.console.print(outputstr+zone.cfg.type+" zone @ "+zone.position.x/engine.REAL_ARENA_SIZE_FACTOR+","+zone.position.y/engine.REAL_ARENA_SIZE_FACTOR+".\n");
found++;
}
}
engine.console.print("Listed "+found+"/"+len+" zones.\n");
},
};
function updategrid() { if(!window.engine || !engine.scene) return; engine.scene.remove(engine.grid); buildGrid(); engine.scene.add(engine.grid); }
function armaColor(cycl,tail)
{
if(tail > 0.25) return 31-(tail*15);
else return cycl*15;
}
function plnumcolors(o)
{
var r,g,b;
if(typeof(o) == "object")
{
r=o.r; g=o.g; b=o.b;
}
var retr = typeof(r) != "undefined",retb=typeof(g) != "undefined",retg=typeof(b) != "undefined";
var cycl=new THREE.Color(settings.players[0].cycleColor),
tail=new THREE.Color(settings.players[0].tailColor);
if(retr||retb||retg)
{
if(!retr) r=armaColor(cycl.r,tail.r);
if(!retg) g=armaColor(cycl.g,tail.g);
if(!retb) b=armaColor(cycl.r,tail.r);
var c_red=r&15,c_grn=g&15,c_blue=b&15;
var t_red=Math.max(15,r),t_grn=Math.max(15,g),t_blue=Math.max(15,b);
settings.players[0].cycleColor = "#"+(new THREE.Color(c_red,c_grn,c_blue)).getHexString();
settings.players[0].tailColor = "#"+(new THREE.Color(t_red,t_grn,t_blue)).getHexString();
}
return {r:armaColor(cycl.r,tail.r),g:armaColor(cycl.g,tail.g),b:armaColor(cycl.b,tail.b)};
}
function preset(name)
{
var leave = function() { for(var x=2;x--;) menu('exitmenu');
if(settings.TEXT_OUT_MODE == 1)
{
var lines = engine.console.scrollback,lnnum = engine.console.scrollby;
}
else
{
var lines = engine.console.innerText.split("\n"),lnnum = (-(parseFloat(engine.console.style.top)/engine.console.scrollby));
}
engine.console.scroll(lines.length-lnnum-6);
};
if(name != "default")
{
var tmp_settings = JSON.parse(JSON.stringify(game_settings_default));
tmp_settings.CYCLE_SPEED = 20;
tmp_settings.CYCLE_SPEED_DECAY_ABOVE = 0.1;
tmp_settings.CYCLE_SPEED_DECAY_BELOW = 5;
tmp_settings.CYCLE_BRAKE = 30;
tmp_settings.CYCLE_RUBBER = 1;
tmp_settings.WALLS_LENGTH = -1;
tmp_settings.CYCLE_JUMP = 0;
}
switch(name)
{
case "default":
applysettings(game_settings_default);
break;
case "zonetest":
chsetting("MAP_FILE","nelg/test/zonetest-0.1.aamap.xml");
chsetting("SIZE_FACTOR",6);
break;
case "classic":
applysettings(tmp_settings);
break;
case "fort":
applysettings(tmp_settings);
commands.RINCLUDE("vov/configs/fortress.cfg",leave);
break;
case "styball":
applysettings(tmp_settings);
commands.INCLUDE("styball.cfg",false,leave);
break;
case "df":
applysettings(tmp_settings);
var rsrc = settings.RESOURCE_REPOSITORY_SERVER;
commands.RINCLUDE("CFGs/df.cfg",function(){leave();chsetting("RESOURCE_REPOSITORY_SERVER",rsrc)});
break;
case "hr":
applysettings(tmp_settings);
commands.INCLUDE("tilthr_old.cfg",false,leave);
break;
case "ft":
applysettings(tmp_settings);
- commands.RINCLUDE("vov/configs/fasttrack.cfg",function(){leave();loadcfg("TEAMS_MIN 4\nALLOW_TEAM_NAME_COLOR 1")});
+ commands.RINCLUDE("vov/configs/fasttrack.cfg",function(){leave();loadcfg("SP_NUM_AIS 4\nALLOW_TEAM_NAME_COLOR 1")});
break;
case "racing":
applysettings(tmp_settings);
settings.CYCLE_JUMP = 0;
settings.ARENA_AXES = 16;
commands.INCLUDE("AoT/AdvancedRacing.cfg",false,leave);
break;
case "snake":
applysettings(tmp_settings);
settings.CYCLE_JUMP = 0;
commands.INCLUDE("nelg/snake.cfg",false,leave);
break;
+ case "ctf":
+ applysettings(tmp_settings);
+ commands.RINCLUDE("vov/configs/ctf.cfg",function(){leave();loadcfg("SP_NUM_AIS 1\nALLOW_TEAM_NAME_COLOR 0")});
+ break;
}
commands.KILL_ALL();
return "";
}
function aamenurender(value)
{
if(typeof(value) != "undefined") settings.MENU_RENDER = ""+value;
var specificState = engine.inputState.split(':');
if(specificState[0] == "menu") document.getElementById('menu').className = "noselect mainbg_"+settings.MENU_RENDER;
document.getElementById('menu').style.backgroundColor = "rgb("+settings.FLOOR_RED*255+","+settings.FLOOR_GREEN*255+","+settings.FLOOR_BLUE*255+")";
return settings.MENU_RENDER;
}
var cmds = Object.keys(settings).concat(Object.keys(commands)).sort();
settings.controls = { //defaults declared
left: [65,68,70,83],//a s d f
right: [74,75,76,186],//j k l ;
north:[], south:[], east:[], west:[],
jump: [73],
brake: [32],//space bar
togglebrake: [86],//v
boost: [],//up arrow or w
toggleboost: [69],//v
chat: [84],//t
console: [192],//~
camera: [67],//c
look_left: [], look_right: [],
look_forward: [], look_back: [],
pause: [13],//enter
// fullscreen: [122],//f11
esc: [27],
score: [9],
scroll_up: [33],
scroll_down: [34],
scroll_end: [35],
//add glancing late
};
settings.instantchats = [
{
input: [49],
text: "Well done!",
},
{
input: [50],
text: "Thank you!",
},
{
input: [51],
text: "Good match!",
},
{
input: [115,52],
text: "LOL!",
},
]
function init_key(x=false) // ?
{
switch(x)
{
case 0:
break;
case 1:
break;
}
return 1*x;
}
settings.players = [];
settings.player = settings.players[0] = {
name: 'Player 1',
cycleColor: '#dddd00',
tailColor: '#dddd00',
engineType: 5,
spectating: false,
};
function applysettings(array1)
{
var sets = Object.keys(array1);
for(i=0;i<sets.length;i++)
{
chsetting(sets[i],array1[i]);
}
}
function loadcfg(str,silent=false,dontforcecase=false)
{
if(str == null) return false;
var lines = str.split("\n");
for(var i=0;i<lines.length;i++)
{
split = lines[i].replace(/\t/," ").trimLeft().split(" ");
var cmd = "";
if(!dontforcecase || (cmd != "FLOOR_RED" && cmd != "FLOOR_GREEN" && cmd != "FLOOR_BLUE" && cmd != "MENU_RENDER")) //HACK for user.cfg
{
cmd = split.shift();
}
chsetting(dontforcecase?cmd:cmd.toUpperCase(),split.join(" ").trimLeft(),silent);
}
}
function importSets()
{
fileOpen(loadcfg);
}
var _aacompatvars = ["PLAYER_1","COLOR_R_1","COLOR_G_1","COLOR_B_1"];
var uservars = [
// "GRID_SIZE","FLOOR_RED","FLOOR_GREEN","FLOOR_BLUE",
"EXPLOSIONS","HIGH_RIM",
/*"MENU_RENDER",*/"REDRAW_MODE","MAX_TARGET_FPS",//"GAME_LOOP",
"ZONE_HEIGHT","ZONE_SEGMENTS","ZONE_SEG_LENGTH","ZONE_ALPHA","ZONE_SPIN_SPEED","ZONE_RENDER_TYPE",
"player","controls"
];
function exportUsrSets()
{
var txt = "# Warning: Do NOT replace user.cfg with this file. This file doesn't directly replace their user.cfg and I claim no reponsibility for lost settings and/or broken clients.\n\n# Armagetron Compatibility\n";
for(var i=0;i<_aacompatvars.length;i++)
{
txt += _aacompatvars[i]+" "+chsetting(_aacompatvars[i],undefined,true)+"\n";
}
for(var i=0;i<settings.instantchats.length;i++)
{
txt += "INSTANT_CHAT_STRING_1_"+(i+1)+" "+settings.instantchats[i].text+"\n";
}
txt += "\n# Native 3DCycles user.cfg settings. Most, but not all, also work with Armagetron.\n";
for(var i=0;i<uservars.length;i++)
{
if(typeof(settings[uservars[i]]) == "object")
{
txt += "MERGE_OBJ "+uservars[i]+" "+JSON.stringify(settings[uservars[i]]);
}
else
{
txt += uservars[i]+" ";
if(typeof(settings[uservars[i]]) == "boolean")
txt += settings[uservars[i]]?1:0;
else
txt += settings[uservars[i]];
}
txt += "\n";
}
fileSave("user_3dcexport.cfg",txt);
}
/*function netcfg(setting,value)
{
setting = setting.toUpperCase();
for(var i=uservars.length;i--;)
{
if(uservars[i] == setting) return false;
}
return chsetting(setting,value,false," on net order");
}*/
var netChanged = [];
function netcfg(setting,value)
{
setting = setting.toUpperCase();
for(var i=sets.length-1;i>=0;--i)
{
if(sets[i] == setting)
{
var settingFound = false;
for(var i=netChanged.length-1;i>=0;--i)
{
if(netChanged[i][0] == setting) settingFound = true;
}
if(!settingFound) netChanged.push([setting,chsetting(setting,undefined,true)]);
return "0xff7f7f"+chsetting(setting,value,false," on server order","0x808080");
}
}
return false;
}
function saveusercfg()
{
var usercfg = "";
for(var i=0;i<uservars.length;i++)
{
if(typeof(settings[uservars[i]]) == "object")
{
usercfg += "MERGE_OBJ "+uservars[i]+" "+JSON.stringify(settings[uservars[i]]);
}
else
{
usercfg += uservars[i]+" ";
if(typeof(settings[uservars[i]]) == "boolean")
usercfg += settings[uservars[i]]?1:0;
else
usercfg += settings[uservars[i]];
}
usercfg += "\n";
}
localStorage.setItem("user.cfg",usercfg);
}
function chsetting(setting,value,silent=false,txt="",pretxt="")
{
if(setting[0] == "#" || setting == "") return;
if(engine.network && txt == "" && typeof(value) != "undefined" && value != "")
{
for(var i=netChanged.length-1;i>=0;--i)
{
if(netChanged[i][0] == setting) return;
}
}
var exec = false, ret = undefined;
var event = getVarFromString(setting);
if(typeof(event[0][event[1]]) != "undefined")
{
var from = event[0][event[1]];
var isfunction = (typeof(from) == "function");
if(isfunction) from = event[0][event[1]]();
if(typeof(value) != "undefined" && value != "")
{
switch(typeof(from))
{
case "number":
var to = parseFloat(value);
if(isNaN(to))
to = 0;
break;
case "string":
var to = ""+value;
break;
case "boolean":
var int = parseInt(value);
if(isNaN(int))
var to = value[0]!="f"&&value[0]!="n";
else
var to = Boolean(int);
break;
case "object":
silent = true;
from = JSON.stringify(settings[uservars[i]]);
var to = JSON.parse(value);
break;
default:
engine.console.print("Unknown/unimplemented setting type "+typeof(event[0][event[1]])+".\n",false);
//return false;
}
if(isfunction) event[0][event[1]](to);
else event[0][event[1]] = to;
if(from != to)
{
if(!silent) engine.console.print(pretxt+event[1]+" changed from "+from+" to "+to+txt+".\n");
if(window.svr && typeof(game_settings_default[event[1]]) !== "undefined")
{
if(to == Infinity) to = Number.MAX_VALUE;
var data = JSON.stringify({type:"setting",setting:event[1],data:to});
window.svr.clients.forEach(function(ws){ws.send(data);});
}
}
ret = to;
}
else
{
if(!silent) engine.console.print(event[1]+" is currently set to "+from+"\n",false);
ret = from;
}
var exec = true;
}
if(event[2] && typeof(event[2][event[1]]) == "function")
{
event[2][event[1]](value);
var exec = true;
}
if(exec) return ret==undefined?exec:ret;
if(!silent)
{
engine.console.print("Unknown command "+event[1]+"\n",false);
if(inround())
{
var len = 0, print="";
for(i=0;i<cmds.length;i++)
{
if(cmds[i].search(setting) > -1)
{
if(len != 0) print += ", ";
len++; print += cmds[i];
}
}
if(len > 0) engine.console.print("Perhaps you meant: "+print+"\n",false);
}
}
return exec;
}
function mkSettingCallback(setting,stringify=false)
{
if(stringify)
return function(set){return ""+chsetting(setting,set,true)}
else
return function(set){return chsetting(setting,set,true)}
}
function getargs()
{
var s = window.location.hash.replace("#","").split("&");
_GET = {};
for(var i=0,len=s.length;i<len;i++)
{
var e = s[i].split("=");
_GET[e[0]] = e[1];
}
}
if(typeof(_GET) == "undefined")
{
getargs();
}
//variables used by init and the engine - do not touch
engine = {
dedicated: false,
paused: false,//
inputState: '', inputStatePrev: '',
lastRenderTime: 0,//used in rendering loop
lastGameTime: 0,
fpsTime: 0, //render loop
timeStart: 0,
timeEnd: 0,//timer vars
totalPauseTime: 0,
startOfPause: 0,//used to prevent delta from offsetting due to pause
framesCount: 0,
avgTimeStep: 0,
gtime:-Infinity,
lastSyncTime:-Infinity,
lastScoreTime:-Infinity,
cMFadeOutAfter: Infinity,
//net
network: false,
activePlayer: 0,
//game stats
fastestPlayer: 0, fastestSpeed: 0,
deaths: 0,
//render loop toggles
//hasplayed: false,//used for playing again, reinitializing the render for another go (after having gone back to menus from it first)
currrim3clr: 0,
//info
usingWebgl: true,//variable to toggle webgl features
usingPostProcessing: false,//toggle for post processing features
concatch: undefined, msgcatch: undefined,
//fonts
font: 'Armagetronad',//active font face
fonts: ['Armagetronad','Flynn','monospace','nicefont','sans-serif','serif'],
textures: {},
//map data
currrot: 0, //rotation
loadedMap: "Anonymous/polygon/regular/square-1.0.1.aamap.xml",
//default:
mapString: '\<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\>\n\<!DOCTYPE Resource SYSTEM \"AATeam/map-0.2.8.0_rc4.dtd\"\>\n\<Resource type=\"aamap\" name=\"square\" version=\"1.0.1\" author=\"Anonymous\" category=\"polygon/regular\"\>\n\t\<Map version=\"2\"\>\n\t\t\<!-- The original square map, technically created by z-man.\n\t Converted to XML by philippeqc.\n\t License: Public Domain. Do with it what you want.\n --\>\n\n\t\t\<World\>\n\t\t\t\<Field\>\n\t\t\t\t\<Spawn\tx=\"255\"\ty=\"50\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"245\"\ty=\"450\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"50\"\ty=\"245\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"450\"\ty=\"255\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"305\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"195\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"195\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"305\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"205\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"295\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"295\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"205\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Wall\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\</Wall\>\n\t\t\t\</Field\>\n\t\t\</World\>\n\t\</Map\>\n\</Resource\>',
//mapString: '\<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\>\n\<!DOCTYPE Resource SYSTEM \"AATeam/map-0.2.8.0_rc4.dtd\"\>\n\<Resource type=\"aamap\" name=\"square\" version=\"1.0.1\" author=\"Anonymous\" category=\"polygon/regular\"\>\n\t\<Map version=\"2\"\>\n\t\t\<!-- The original square map, technically created by z-man.\n\t Converted to XML by philippeqc.\n\t License: Public Domain. Do with it what you want.\n --\>\n\n\t\t\<World\>\n\t\t\t\<Field\>\n\t\t\t\t\<Spawn\tx=\"255\"\ty=\"50\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"245\"\ty=\"450\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"50\"\ty=\"245\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"450\"\ty=\"255\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"305\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"195\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"195\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"305\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"205\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"295\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"295\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"205\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Wall\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\</Wall\>\n\t\t\t\</Field\>\n\t\t\</World\>\n\t\</Map\>\n\</Resource\>',
//two zones:
//mapString: '\<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\>\n\<!DOCTYPE Resource SYSTEM \"AATeam/map-0.2.8.0_rc4.dtd\"\>\n\<Resource type=\"aamap\" name=\"square\" version=\"1.0.1\" author=\"Anonymous\" category=\"polygon/regular\"\>\n\t\<Map version=\"2\"\>\n\t\t\<!-- The original square map, technically created by z-man.\n\t Converted to XML by philippeqc.\n\t License: Public Domain. Do with it what you want.\n --\>\n\n\t\t\<World\>\n\t\t\t\<Field\>\n\t\t\t\t\<Spawn\tx=\"255\"\ty=\"50\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"245\"\ty=\"450\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"50\"\ty=\"245\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"450\"\ty=\"255\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"305\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"195\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"195\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"305\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"205\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"295\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"295\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"205\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Wall\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\</Wall\>\n\t\t\t\<Zone effect=\"death\"\>\<ShapeCircle radius=\"20\"\>\<Point y=\"275\" x=\"275\"/\>\n\t\t\t\</ShapeCircle\>\n\t\t\t\</Zone\>\n\t\t\t\<Zone effect=\"win\"\>\n\t\t\t\t\<ShapeCircle radius=\"10\"\>\n\t\t\t\t\t\<Point y=\"240\" x=\"250\"/\>\n\t\t\t\t\</ShapeCircle\>\n\t\t\t\</Zone\>\t\t\t\</Field\>\n\t\t\</World\>\n\t\</Map\>\n\</Resource\>',
//one zone:
//mapString: '\<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\>\n\<!DOCTYPE Resource SYSTEM \"AATeam/map-0.2.8.0_rc4.dtd\"\>\n\<Resource type=\"aamap\" name=\"square\" version=\"1.0.1\" author=\"Anonymous\" category=\"polygon/regular\"\>\n\t\<Map version=\"2\"\>\n\t\t\<!-- The original square map, technically created by z-man.\n\t Converted to XML by philippeqc.\n\t License: Public Domain. Do with it what you want.\n --\>\n\n\t\t\<World\>\n\t\t\t\<Field\>\n\t\t\t\t\<Spawn\tx=\"255\"\ty=\"50\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"245\"\ty=\"450\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"50\"\ty=\"245\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"450\"\ty=\"255\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"305\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"195\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"195\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"305\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"205\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"295\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"295\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"205\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Wall\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\</Wall\>\n\t\t\t\<Zone effect=\"win\"\>\n\t\t\t\t\<ShapeCircle radius=\"10\"\>\n\t\t\t\t\t\<Point y=\"240\" x=\"250\"/\>\n\t\t\t\t\</ShapeCircle\>\n\t\t\t\</Zone\>\t\t\t\</Field\>\n\t\t\</World\>\n\t\</Map\>\n\</Resource\>',
//two zones + two walls:
//mapString: '\<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\>\n\<!DOCTYPE Resource SYSTEM \"AATeam/map-0.2.8.0_rc4.dtd\"\>\n\<Resource type=\"aamap\" name=\"square\" version=\"1.0.1\" author=\"Anonymous\" category=\"polygon/regular\"\>\n\t\<Map version=\"2\"\>\n\t\t\<!-- The original square map, technically created by z-man.\n\t Converted to XML by philippeqc.\n\t License: Public Domain. Do with it what you want.\n --\>\n\n\t\t\<World\>\n\t\t\t\<Field\>\n\t\t\t\t\<Spawn\tx=\"255\"\ty=\"50\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"245\"\ty=\"450\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"50\"\ty=\"245\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"450\"\ty=\"255\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"305\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"195\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"195\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"305\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Spawn\tx=\"205\"\ty=\"100\"\txdir=\"0\"\tydir=\"1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"295\"\ty=\"400\"\txdir=\"0\"\tydir=\"-1\"\t/\>\n\t\t\t\t\<Spawn\tx=\"100\"\ty=\"295\"\txdir=\"1\"\tydir=\"0\"\t/\>\n\t\t\t\t\<Spawn\tx=\"400\"\ty=\"205\"\txdir=\"-1\"\tydir=\"0\"\t/\>\n\n\t\t\t\t\<Wall\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"500\"\t/\>\n\t\t\t\t\t\<Point\tx=\"500\"\ty=\"0\"\t/\>\n\t\t\t\t\t\<Point\tx=\"0\"\ty=\"0\"\t/\>\n\t\t\t\t\</Wall\>\n<Wall height=\"1\"\>\n\t\t\t\t\t\<Point\tx=\"200\"\ty=\"200\"\t/\>\n\t\t\t\t\t\<Point\tx=\"200\"\ty=\"300\"\t/\>\n\t\t\t\t\t\<Point\tx=\"300\"\ty=\"300\"\t/\>\n\t\t\t\t\t\<Point\tx=\"300\"\ty=\"200\"\t/\>\n\t\t\t\t\t\<Point\tx=\"200\"\ty=\"200\"\t/\>\n\t\t\t\t\</Wall\>\n\t\t\t\<Zone effect=\"death\"\>\<ShapeCircle radius=\"20\"\>\<Point y=\"275\" x=\"275\"/\>\n\t\t\t\</ShapeCircle\>\n\t\t\t\</Zone\>\n\t\t\t\<Zone effect=\"win\"\>\n\t\t\t\t\<ShapeCircle radius=\"10\"\>\n\t\t\t\t\t\<Point y=\"240\" x=\"250\"/\>\n\t\t\t\t\</ShapeCircle\>\n\t\t\t\</Zone\>\t\t\t\</Field\>\n\t\t\</World\>\n\t\</Map\>\n\</Resource\>',
mapXML: false,//xmlify(mapString);
//scene vars
renderer: false,
scene: false,
composer: false,//for post processing
//camera stuff
camera: false,//needed or any camera
cameraOrbit: false,//
view: 'smart',
views: ['smart','chase','stationary','track','topdown','birdseye','cockpit'],
cameraEase: 0.08,
viewTarget: 0,
menus: [],
//sound
useSound: true,
retroSound: true,
//
//scene objects (just used for render)
grid: false,
walls: false,
zones: {children:0},
//a_zone: [],//not needed with children?
//is running
gameRunning: false,
renderRunning: false,
uRound: false, //timeout ID for new round
//FOR PLAYER OBJECTS
//game stuff
playersById: [],//array of player objects (info)
playersByScore: [],
teams: [],//array of team objects
round: 0,
delayedcommands: {},
};
if(window.Proxy)
{
engine.players = new Proxy(engine.playersById,{
apply: function(t,arg,ls)
{
return arg[t].apply(this,ls);
},
deleteProperty: function(t,id)
{
if(!isNaN(id))
{
for(var x=engine.playersByScore.length-1;x>=0;--x)
{
if(t[id] == engine.playersByScore[x])
{
engine.playersByScore.splice(x,1);
}
}
}
return true;
},
set: function(t,id,val)
{
if(!isNaN(id))
{
for(var x=engine.playersByScore.length-1;x>=0;--x)
{
if(t[id] == engine.playersByScore[x])
{
engine.playersByScore[x] = val;
updateScoreBoard();
t[id] = val;
return true;
}
}
engine.playersByScore.push(val);
}
t[id] = val;
return true;
},
});
}
else
{
//hacky workaround, only for browsers without Proxy support (very few)
engine.players = engine.playersById;
engine.players.prevLength = -1;
setInterval(function()
{
if(engine.players.length != engine.players.prevLength)
{
engine.players.prevLength = engine.players.length;
engine.playersByScore.splice(0);
for(var x=engine.playersById.length-1;x>=0;--x)
{
engine.playersByScore.push(engine.playersById[x]);
}
updateScoreBoard();
}
},1000);
}
settings.engine = engine; //hack to allow menu to change engine config. (Potentially insecure?)
//CONSOLE, HUD
if(typeof(document) != "undefined")
{
engine.console = document.getElementById("console");
engine.console.time = 0;
engine.console.time_manual = 0;
engine.console.print = function(str)
{
//this.append(" "+str);
if(engine.concatch)
{
if(engine.concatch.type == "all") engine.concatch.to.append(str);
else if(engine.concatch.type == "list") engine.concatch.to.push(str);
else engine.concatch.to.innerText = str;
}
if(settings.TEXT_OUT_MODE == 1)
{
this.scrollback.push(str);
}
this.innerHTML += " "+replaceColors(htmlEntities(str));
//console.log(replaceColors(str));
this.time = performance.now()+this.scrolltime;
if(!inround()||!settings.TEXT_OUT()) console.log("[CON] "+str);
}
engine.console.scrollby = 0;
engine.console.scrolltime = 5000;
engine.console.scrolltime_manual = 30000;
engine.console.time_manual -= engine.console.scrolltime_manual;
engine.console.scroll = function(times=1)
{
if(settings.TEXT_OUT_MODE == 1)
{
this.scrollby+=times; this.innerHTML = "";
for(var i=this.scrollby;i<engine.console.scrollback.length;i++)
{
this.innerHTML += " "+replaceColors(htmlEntities(this.scrollback[i]));
}
}
else
{
//this.scrollby = parseFloat(window.getComputedStyle(this).getPropertyValue('font-size'))+6;
//this.scrollby = this.children[0].offsetHeight;
var orig = parseFloat(this.style.top)/this.scrollby;
this.scrollby = this.offsetHeight/this.innerText.split("\n").length;
if(this.style.top == '') this.style.top = 0;
//this.style.top = (parseFloat(this.style.top)-(this.scrollby*times))+"px";
this.style.top = ((this.scrollby*orig)-(this.scrollby*times))+"px";
}
}
if(settings.TEXT_OUT_MODE == 1)
{
engine.console.scrollback = [];
engine.console.style.top = "-16px";
}
engine.console.scroll();
engine.hud = document.getElementById("HUD");
engine.hud.hide = function(){this.style.opacity=0;};
engine.hud.show = function(){this.style.opacity=1;};
engine.hud.basic = document.getElementById("gui_stats");
engine.hud.game = document.getElementById("game_stats");
engine.hud.fadein = true;
}
else
{
engine.console = {style:{}};
engine.console.print = function(str,netSend=true)
{
process.stdout.write(removeColors(str));
if(engine.concatch)
{
if(engine.concatch.type == "all") engine.concatch.to.append(str);
else if(engine.concatch.type == "list") engine.concatch.to.push(str);
else engine.concatch.to.innerText = str;
}
if(netSend && global.svr) //send over network
{
var data = JSON.stringify({type:"con",data:str});
switch(typeof(netSend))
{
case "boolean":
global.svr.clients.forEach(function(ws) //I know this is slow, but I'm not aware of any other way
{
ws.send(data);
});
break;
case "object":
var lookForID = engine.players.indexOf(netSend);
global.svr.clients.forEach(function(ws)
{
if(ws.netid == lookForID)
{
ws.send(data);
}
});
break;
}
}
};
}
/*///team objects:
-name
-array of player IDs (order of shuffle)
-team score
/**/
//which controls are pressed down get added to arrays
var temp_items = Object.keys(settings.controls);
engine.controls = {pressed:[]};
for(var i=0;i<temp_items.length;i++)
{
engine.controls[temp_items[i]] = []; //array of keycodes that are pressed within a frame, removed when lifted
}
engine.map = { //virtual map data (used for positions, lines and stuff to calculate)
zones: [],
spawns: [],
walls: [],
};
function loadsettingcfgs()
{
loadcfg(localStorage.getItem("user.cfg"),true,true);
loadcfg(localStorage.getItem("server_info.cfg"),true);
loadcfg(localStorage.getItem("settings_custom.cfg"),true);
loadcfg(localStorage.getItem("autoexec.cfg"),true);
}
loadsettingcfgs();
window.onbeforeunload = saveusercfg;
diff --git a/scripts/game.js b/scripts/game.js
index 538f430..a1c5234 100644
--- a/scripts/game.js
+++ b/scripts/game.js
@@ -1,1145 +1,1185 @@
/*
* 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()
{
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
}
function endRound()
{
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("Deleting objects...\n",false);
if(!engine.network)
{
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()
{
endRound();
engine.players.splice(0);
engine.round = 0;
}
function playGame()
{
engine.playGame = true;
if(!engine.scene)
{
init();
}
else
{
engine.paused = false;
if(engine.hud) engine.hud.show();
}
hideMenu(); 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()
{
engine.console.print("Unable to load map file. Ignoring for now...\n",false);
loadRound();
});
}
}
function newRound()
{
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));
}
else
{
loadRound();
}
}
function teamColor(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].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)
{
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)
{
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)
{
if(typeof(dlmap) != "undefined")
{
engine.mapString = dlmap;
engine.loadedMap = settings.MAP_FILE;
}
engine.mapXML = xmlify(engine.mapString);
engine.console.print("Creating objects...\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();
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();
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();
}//end of init main
function game(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;}
//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});
window.svr.clients.forEach(function(ws){ws.send(data)});
}
}
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();
}
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();
}
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 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)
{
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)
{
console.warn("Deprecated call to simulatePlayer");
cycle.update(timestep);
}
function getGoing()
{
if(!engine.gameRunning) game();
if(!engine.renderRunning) render();
}
function pauseRender()
{
engine.paused = true;//cuts off the loop
engine.startOfPause = performance.now();
audioStop();
}
function unpauseRender()
{
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
}
}
function changeViewTarget(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()
{
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;
}//*/
}
function startNewRound()
{
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);
}
function updateScoreBoard()
{
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+" ";
}
}*/
diff --git a/scripts/player.js b/scripts/player.js
index ace904f..2d465f2 100644
--- a/scripts/player.js
+++ b/scripts/player.js
@@ -1,633 +1,640 @@
/*
* 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();
}
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.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.add(wallmod = newWall(this.tailColor,wmap[x-1][0],wmap[x-1][1],wmap[x-1][2]));
}
else
{
wallmod = this.walls.children[x-1];
if(wallmod == undefined) break;
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(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);
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();
+ 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
}
}
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);
}
}
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/zone.js b/scripts/zone.js
index 46451bd..e9dd84f 100644
--- a/scripts/zone.js
+++ b/scripts/zone.js
@@ -1,360 +1,371 @@
/*
* 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');
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); }
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.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)
{
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(!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;
+ }
+ 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:25 PM (3 d, 23 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10798

Event Timeline