├── server ├── config.cfg ├── wsc-chrome.min.js.txt ├── js │ ├── Console.js │ ├── V.js │ ├── SyncServerSys.js │ ├── Sys.js │ ├── SZ.js │ ├── Def.js │ ├── Cvar.js │ ├── Protocol.js │ ├── SyncClientSys.js │ ├── CRC.js │ ├── MSG.js │ ├── Q.js │ ├── Vec.js │ ├── Cmd.js │ ├── NET.js │ ├── COM.js │ ├── ED.js │ ├── NET_Datagram.js │ ├── Mod.js │ ├── NET_WEBS.js │ ├── PF.js │ ├── PR.js │ └── Host.js ├── server.html ├── chromenodews.js └── server.js ├── TODO ├── earthquake-icone-4663-128.png ├── earthquake-icone-4663-16.png ├── earthquake-icone-4663-32.png ├── earthquake-icone-4663-48.png ├── earthquake-icone-4663-64.png ├── earthquake-icone-4663-96.png ├── .gitmodules ├── common.js ├── index.html ├── package.sh ├── buy.js ├── README.md ├── manifest.json ├── background.js ├── launch.html ├── index.js └── launch.js /server/config.cfg: -------------------------------------------------------------------------------- 1 | registered 0 2 | coop 1 3 | deathmatch 0 4 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - xbox 360 gamepad deadzone problem. maybe when polling if value is unchanged for several frames, call it 0 2 | -------------------------------------------------------------------------------- /earthquake-icone-4663-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kzahel/WebQuake-Chrome/HEAD/earthquake-icone-4663-128.png -------------------------------------------------------------------------------- /earthquake-icone-4663-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kzahel/WebQuake-Chrome/HEAD/earthquake-icone-4663-16.png -------------------------------------------------------------------------------- /earthquake-icone-4663-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kzahel/WebQuake-Chrome/HEAD/earthquake-icone-4663-32.png -------------------------------------------------------------------------------- /earthquake-icone-4663-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kzahel/WebQuake-Chrome/HEAD/earthquake-icone-4663-48.png -------------------------------------------------------------------------------- /earthquake-icone-4663-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kzahel/WebQuake-Chrome/HEAD/earthquake-icone-4663-64.png -------------------------------------------------------------------------------- /earthquake-icone-4663-96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kzahel/WebQuake-Chrome/HEAD/earthquake-icone-4663-96.png -------------------------------------------------------------------------------- /server/wsc-chrome.min.js.txt: -------------------------------------------------------------------------------- 1 | this file should come from github.com/kzahel/web-server-chrome by running the minimize.sh script 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "WebQuake"] 2 | path = WebQuake-sync 3 | url = git@github.com:kzahel/WebQuake 4 | [submodule "WebQuake-async"] 5 | path = WebQuake-async 6 | url = git@bitbucket.org:kzahel/WebQuake 7 | -------------------------------------------------------------------------------- /common.js: -------------------------------------------------------------------------------- 1 | 2 | function deleteServerSockets() { 3 | chrome.sockets.tcpServer.getSockets(function(infos) { 4 | infos.forEach( function(info) { 5 | chrome.sockets.tcpServer.close(info.socketId, 6 | function(i) { console.log('closed server socket',i) }) 7 | }) 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /server/js/Console.js: -------------------------------------------------------------------------------- 1 | Con = {}; 2 | 3 | Con.Print = function(msg) 4 | { 5 | if (msg.charCodeAt(0) >= 3) 6 | process.stdout.write(msg); 7 | else 8 | process.stdout.write(msg.substring(1)); 9 | }; 10 | 11 | Con.DPrint = function(msg) 12 | { 13 | if (Host.developer.value !== 0) 14 | Con.Print(msg); 15 | }; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | rm package.zip 2 | 3 | zip package.zip -r manifest.json *.png *.js *.html WebQuake-async/Client server 4 | 5 | #zip package.zip -r manifest.json *.png *.js *.html WebQuake/Client web-server-chrome/*.js 6 | 7 | #zip package.zip -r * -x package.sh -x *.git* -x "*.*~" -x web-server-chrome/manifest.json -x web-server-chrome/*.png -x WebQuake/Server/* WebQuake/Server/id1/* 8 | 9 | #web-server-chrome/*.js *.html *.js manifest.json WebQuake/* WebQuake/Client/* WebQuake/Client/id1/* WebQuake/Client/WebQuake/* *.png 10 | -------------------------------------------------------------------------------- /server/js/V.js: -------------------------------------------------------------------------------- 1 | V = {}; 2 | 3 | V.CalcRoll = function(angles, velocity) 4 | { 5 | var right = []; 6 | Vec.AngleVectors(angles, null, right); 7 | var side = velocity[0] * right[0] + velocity[1] * right[1] + velocity[2] * right[2]; 8 | var sign = side < 0 ? -1 : 1; 9 | side = Math.abs(side); 10 | if (side < V.rollspeed.value) 11 | return side * sign * V.rollangle.value / V.rollspeed.value; 12 | return V.rollangle.value * sign; 13 | }; 14 | 15 | V.Init = function() 16 | { 17 | V.rollspeed = Cvar.RegisterVariable('cl_rollspeed', '200'); 18 | V.rollangle = Cvar.RegisterVariable('cl_rollangle', '2.0'); 19 | }; -------------------------------------------------------------------------------- /buy.js: -------------------------------------------------------------------------------- 1 | (function() { var f=this,g=function(a,d){var c=a.split("."),b=window||f;c[0]in b||!b.execScript||b.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)c.length||void 0===d?b=b[e]?b[e]:b[e]={}:b[e]=d};var h=function(a){var d=chrome.runtime.connect("nmmhkkegccagdldgiimedpiccmgmieda",{}),c=!1;d.onMessage.addListener(function(b){c=!0;"response"in b&&!("errorType"in b.response)?a.success&&a.success(b):a.failure&&a.failure(b)});d.onDisconnect.addListener(function(){!c&&a.failure&&a.failure({request:{},response:{errorType:"INTERNAL_SERVER_ERROR"}})});d.postMessage(a)};g("google.payments.inapp.buy",function(a){a.method="buy";h(a)}); 2 | g("google.payments.inapp.getPurchases",function(a){a.method="getPurchases";h(a)});g("google.payments.inapp.getSkuDetails",function(a){a.method="getSkuDetails";h(a)}); })(); 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Get it in the Chrome Web Store! 2 | 3 | ![Try it now in CWS](https://raw.github.com/GoogleChrome/chrome-app-samples/master/tryitnowbutton.png "Install Web Quake") 4 | 5 | [Available to install in the Chrome web store](https://chrome.google.com/webstore/detail/web-quake/ibkbfanmkmadbbgggonficloplenbefh) 6 | 7 | 8 | ### WebQuake (Fork by kzahel (Fork by efess)) original by https://github.com/3angel/WebQuake 9 | 10 | **WebQuake** is an HTML5 WebGL port of the game Quake by id Software. 11 | 12 | ### Features added in this fork (kzahel) (https://bitbucket.org/kzahel/webquake) 13 | * multiplayer server using chrome.sockets and websockets 14 | * gamepad support 15 | * restore web audio api 16 | * remove localStorage 17 | -------------------------------------------------------------------------------- /server/js/SyncServerSys.js: -------------------------------------------------------------------------------- 1 | Sys = {}; 2 | 3 | Sys.Quit = function() 4 | { 5 | process.exit(0); 6 | }; 7 | 8 | Sys.Print = function(text) 9 | { 10 | process.stdout.write(text); 11 | }; 12 | 13 | Sys.Error = function(text) 14 | { 15 | console.log(text); 16 | throw new Error(text); 17 | }; 18 | 19 | Sys.FloatTime = function() 20 | { 21 | var time = process.hrtime(Sys.oldtime); 22 | return time[0] + (time[1] / 1000000000.0); 23 | }; 24 | 25 | Sys.cmd = ''; 26 | Sys.ConsoleInput = function() 27 | { 28 | var text = Sys.cmd; 29 | if (text.length === 0) 30 | return; 31 | Sys.cmd = ''; 32 | return text; 33 | }; 34 | 35 | Sys.main = function() 36 | { 37 | COM.InitArgv(process.argv.slice(1)); 38 | Sys.oldtime = process.hrtime(); 39 | Sys.Print('Host.Init\n'); 40 | Host.Init(); 41 | process.stdin.resume(); 42 | process.stdin.on('data', Sys.StdinOnData); 43 | process.nextTick(Host.Frame); 44 | }; 45 | 46 | Sys.StdinOnData = function(data) 47 | { 48 | Sys.cmd += Q.memstr(data); 49 | }; -------------------------------------------------------------------------------- /server/js/Sys.js: -------------------------------------------------------------------------------- 1 | Sys = {}; 2 | 3 | Sys.Quit = function() 4 | { 5 | process.exit(0); 6 | }; 7 | 8 | Sys.Print = function(text) 9 | { 10 | process.stdout.write(text); 11 | }; 12 | 13 | Sys.Error = function(text) 14 | { 15 | console.log(text); 16 | throw new Error(text); 17 | }; 18 | 19 | Sys.FloatTime = function() 20 | { 21 | var time = process.hrtime(Sys.oldtime); 22 | return time[0] + (time[1] / 1000000000.0); 23 | }; 24 | 25 | Sys.cmd = ''; 26 | Sys.ConsoleInput = function() 27 | { 28 | var text = Sys.cmd; 29 | if (text.length === 0) 30 | return; 31 | Sys.cmd = ''; 32 | return text; 33 | }; 34 | 35 | Sys.main = function() 36 | { 37 | COM.InitArgv(process.argv.slice(1)); 38 | Sys.oldtime = process.hrtime(); 39 | Sys.Print('Host.Init\n'); 40 | Host.Init(); 41 | process.stdin.resume(); 42 | process.stdin.on('data', Sys.StdinOnData); 43 | process.nextTick(Host.Frame); 44 | }; 45 | 46 | Sys.StdinOnData = function(data) 47 | { 48 | Sys.cmd += Q.memstr(data); 49 | }; 50 | -------------------------------------------------------------------------------- /server/js/SZ.js: -------------------------------------------------------------------------------- 1 | SZ = {}; 2 | 3 | SZ.GetSpace = function(buf, length) 4 | { 5 | if ((buf.cursize + length) > buf.data.byteLength) 6 | { 7 | if (buf.allowoverflow !== true) 8 | Sys.Error('SZ.GetSpace: overflow without allowoverflow set'); 9 | if (length > buf.byteLength) 10 | Sys.Error('SZ.GetSpace: ' + length + ' is > full buffer size'); 11 | buf.overflowed = true; 12 | Con.Print('SZ.GetSpace: overflow\n'); 13 | buf.cursize = 0; 14 | } 15 | var cursize = buf.cursize; 16 | buf.cursize += length; 17 | return cursize; 18 | }; 19 | 20 | SZ.Write = function(sb, data, length) 21 | { 22 | (new Uint8Array(sb.data, SZ.GetSpace(sb, length), length)).set(data.subarray(0, length)); 23 | }; 24 | 25 | SZ.Print = function(sb, data) 26 | { 27 | var buf = new Uint8Array(sb.data); 28 | var dest; 29 | if (sb.cursize !== 0) 30 | { 31 | if (buf[sb.cursize - 1] === 0) 32 | dest = SZ.GetSpace(sb, data.length - 1) - 1; 33 | else 34 | dest = SZ.GetSpace(sb, data.length); 35 | } 36 | else 37 | dest = SZ.GetSpace(sb, data.length); 38 | var i; 39 | for (i = 0; i < data.length; ++i) 40 | buf[dest + i] = data.charCodeAt(i); 41 | }; -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6ZBSt2PX2520oXWQSOrJXbfCMVmgtBFsAnk0feDkb1rT42aIhym0kENWhICYY1ZD8skCBlpeuFcx4Eo5nlVr+dihyUw9f3Rliik2sHceSJbpyqhT0EjQY0bCvqyh6fEWJBFsKAuuazQlbK9gS7H4Zm4yhTbaH+5CEkVQtVXYVLQIDAQAB", 3 | "short_name": "Quake", 4 | "name": "Web Quake", 5 | "description": "Quake by id Software for Chrome", 6 | "version": "1.0.5", 7 | "manifest_version": 2, 8 | "offline_enabled": true, 9 | "sockets": { 10 | "udp": { 11 | "send": [""], 12 | "bind": [""], 13 | "multicastMembership": "" 14 | }, 15 | "tcp": { 16 | "connect": [""] 17 | }, 18 | "tcpServer": { 19 | "listen": [""] 20 | } 21 | }, 22 | "permissions": [ 23 | {"fileSystem":["write"]}, 24 | "pointerLock", 25 | "system.network", 26 | "fullscreen", 27 | "identity", 28 | "storage", 29 | "webview", 30 | "http://*/", 31 | "https://*/", 32 | "https://www.googleapis.com/" 33 | ], 34 | "app": { 35 | "background": { 36 | "scripts": ["background.js"] 37 | } 38 | }, 39 | "webview": { 40 | "partitions": [ 41 | { "name": "trusted*", 42 | "accessible_resources": ["*.*"] 43 | } 44 | ] 45 | }, 46 | "icons": { 47 | "16": "earthquake-icone-4663-16.png", 48 | "32": "earthquake-icone-4663-32.png", 49 | "48": "earthquake-icone-4663-48.png", 50 | "64": "earthquake-icone-4663-64.png", 51 | "96": "earthquake-icone-4663-96.png", 52 | "128": "earthquake-icone-4663-128.png" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /server/js/Def.js: -------------------------------------------------------------------------------- 1 | Def = {}; 2 | 3 | Def.timedate = 'Exe: 10:13:04 Dec 8 2013\n'; 4 | 5 | Def.max_edicts = 600; 6 | 7 | Def.stat = { 8 | health: 0, 9 | frags: 1, 10 | weapon: 2, 11 | ammo: 3, 12 | armor: 4, 13 | weaponframe: 5, 14 | shells: 6, 15 | nails: 7, 16 | rockets: 8, 17 | cells: 9, 18 | activeweapon: 10, 19 | totalsecrets: 11, 20 | totalmonsters: 12, 21 | secrets: 13, 22 | monsters: 14 23 | }; 24 | 25 | Def.it = { 26 | shotgun: 1, 27 | super_shotgun: 2, 28 | nailgun: 4, 29 | super_nailgun: 8, 30 | grenade_launcher: 16, 31 | rocket_launcher: 32, 32 | lightning: 64, 33 | super_lightning: 128, 34 | shells: 256, 35 | nails: 512, 36 | rockets: 1024, 37 | cells: 2048, 38 | axe: 4096, 39 | armor1: 8192, 40 | armor2: 16384, 41 | armor3: 32768, 42 | superhealth: 65536, 43 | key1: 131072, 44 | key2: 262144, 45 | invisibility: 524288, 46 | invulnerability: 1048576, 47 | suit: 2097152, 48 | quad: 4194304 49 | }; 50 | 51 | Def.rit = { 52 | shells: 128, 53 | nails: 256, 54 | rockets: 512, 55 | cells: 1024, 56 | axe: 2048, 57 | lava_nailgun: 4096, 58 | lava_super_nailgun: 8192, 59 | multi_grenade: 16384, 60 | multi_rocket: 32768, 61 | plasma_gun: 65536, 62 | armor1: 8388608, 63 | armor2: 16777216, 64 | armor3: 33554432, 65 | lava_nails: 67108864, 66 | plasma_ammo: 134217728, 67 | multi_rockets: 268435456, 68 | shield: 536870912, 69 | antigrav: 1073741824, 70 | superhealth: 2147483648 71 | }; 72 | 73 | Def.hit = { 74 | proximity_gun_bit: 16, 75 | mjolnir_bit: 7, 76 | laser_cannon_bit: 23, 77 | proximity_gun: 65536, 78 | mjolnir: 128, 79 | laser_cannon: 8388608, 80 | wetsuit: 33554432, 81 | empathy_shields: 67108864 82 | }; -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | console.log('background.js') 2 | chrome.app.runtime.onLaunched.addListener(function(launchData) { 3 | onstarted() 4 | }) 5 | 6 | chrome.runtime.onMessage.addListener( function(message) { 7 | if (message == 'restart_server') { 8 | setTimeout( doserver, 1 ) 9 | } 10 | }) 11 | 12 | function onstarted() { 13 | launch() 14 | 15 | } 16 | 17 | function launch() { 18 | chrome.app.window.create('launch.html', 19 | { defaultWidth: 512, 20 | id:'WebQuake-launch', 21 | defaultHeight: 384 }, 22 | function(w) { 23 | console.log('window created'); 24 | }) 25 | } 26 | function doserver() { 27 | // this is only for debugging. look in launch.js for actual server launch 28 | var server = chrome.app.window.get('server') 29 | if (server) { 30 | console.log('closing server window') 31 | server.close() 32 | setTimeout( doserver, 500 ) 33 | return 34 | } 35 | 36 | //var arg = encodeURIComponent('+ map start') 37 | var arg = '' 38 | chrome.app.window.create('server/server.html?' + arg, 39 | { defaultWidth: 512, 40 | id:'server', 41 | hidden: true, 42 | defaultHeight: 384 }, 43 | function(w) { 44 | console.log('server window created'); 45 | w.onClosed.addListener( function() { 46 | console.log('server window closed') 47 | localServer = false 48 | deleteServerSockets() 49 | }) 50 | }) 51 | 52 | } 53 | 54 | var reload = chrome.runtime.reload 55 | -------------------------------------------------------------------------------- /server/js/Cvar.js: -------------------------------------------------------------------------------- 1 | Cvar = {}; 2 | 3 | Cvar.vars = []; 4 | 5 | Cvar.FindVar = function(name) 6 | { 7 | var i; 8 | for (i = 0; i < Cvar.vars.length; ++i) 9 | { 10 | if (Cvar.vars[i].name === name) 11 | return Cvar.vars[i]; 12 | } 13 | }; 14 | 15 | Cvar.Set = function(name, value) 16 | { 17 | var i, v, changed; 18 | for (i = 0; i < Cvar.vars.length; ++i) 19 | { 20 | v = Cvar.vars[i]; 21 | if (v.name !== name) 22 | continue; 23 | if (v.string !== value) 24 | changed = true; 25 | v.string = value; 26 | v.value = Q.atof(value); 27 | if ((v.server === true) && (changed === true) && (SV.server.active === true)) 28 | Host.BroadcastPrint('"' + v.name + '" changed to "' + v.string + '"\n'); 29 | return; 30 | } 31 | Con.Print('Cvar.Set: variable ' + name + ' not found\n'); 32 | }; 33 | 34 | Cvar.SetValue = function(name, value) 35 | { 36 | Cvar.Set(name, value.toFixed(6)); 37 | }; 38 | 39 | Cvar.RegisterVariable = function(name, value, archive, server) 40 | { 41 | var i; 42 | for (i = 0; i < Cvar.vars.length; ++i) 43 | { 44 | if (Cvar.vars[i].name === name) 45 | { 46 | Con.Print('Can\'t register variable ' + name + ', allready defined\n'); 47 | return; 48 | } 49 | } 50 | Cvar.vars[Cvar.vars.length] = 51 | { 52 | name: name, 53 | string: value, 54 | archive: archive, 55 | server: server, 56 | value: Q.atof(value) 57 | }; 58 | return Cvar.vars[Cvar.vars.length - 1]; 59 | }; 60 | 61 | Cvar.Command = function() 62 | { 63 | var v = Cvar.FindVar(Cmd.argv[0]); 64 | if (v == null) 65 | return; 66 | if (Cmd.argv.length <= 1) 67 | { 68 | Con.Print('"' + v.name + '" is "' + v.string + '"\n'); 69 | return true; 70 | } 71 | Cvar.Set(v.name, Cmd.argv[1]); 72 | return true; 73 | }; 74 | 75 | Cvar.WriteVariables = function() 76 | { 77 | var f = [], i, v; 78 | for (i = 0; i < Cvar.vars.length; ++i) 79 | { 80 | v = Cvar.vars[i]; 81 | if (v.archive === true) 82 | f[f.length] = v.name + ' "' + v.string + '"\n'; 83 | } 84 | return f.join(''); 85 | }; -------------------------------------------------------------------------------- /launch.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 |

Web Quake for Chrome

11 | 12 |
13 |

14 | 15 |
16 | Start playing Quake now! 17 |

18 | 19 |

20 | 21 |
22 | Launch a multiplayer server 23 |

24 |

25 | Options 26 |
27 | 28 | Disable sound
29 |

30 | 31 |
32 |

33 | 34 |
35 | Consider donating! Your donation means more features such as multiplayer, gamepad support, full version, etc. Please leave a rating in the Chrome Web Store 36 |

37 | 38 |

39 | 40 |
41 | If you have the files for the full version of Quake (pak1.pak), you can select the folder and play the full version 42 |

43 | 44 | 45 |
46 | 47 |

Credits

48 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /server/js/Protocol.js: -------------------------------------------------------------------------------- 1 | Protocol = {}; 2 | 3 | Protocol.version = 15; 4 | 5 | Protocol.u = { 6 | morebits: 1, 7 | origin1: 1 << 1, 8 | origin2: 1 << 2, 9 | origin3: 1 << 3, 10 | angle2: 1 << 4, 11 | nolerp: 1 << 5, 12 | frame: 1 << 6, 13 | signal: 1 << 7, 14 | 15 | angle1: 1 << 8, 16 | angle3: 1 << 9, 17 | model: 1 << 10, 18 | colormap: 1 << 11, 19 | skin: 1 << 12, 20 | effects: 1 << 13, 21 | longentity: 1 << 14 22 | }; 23 | 24 | Protocol.su = { 25 | viewheight: 1, 26 | idealpitch: 1 << 1, 27 | punch1: 1 << 2, 28 | punch2: 1 << 3, 29 | punch3: 1 << 4, 30 | velocity1: 1 << 5, 31 | velocity2: 1 << 6, 32 | velocity3: 1 << 7, 33 | items: 1 << 9, 34 | onground: 1 << 10, 35 | inwater: 1 << 11, 36 | weaponframe: 1 << 12, 37 | armor: 1 << 13, 38 | weapon: 1 << 14 39 | }; 40 | 41 | Protocol.default_viewheight = 22; 42 | 43 | Protocol.svc = { 44 | nop: 1, 45 | disconnect: 2, 46 | updatestat: 3, 47 | version: 4, 48 | setview: 5, 49 | sound: 6, 50 | time: 7, 51 | print: 8, 52 | stufftext: 9, 53 | setangle: 10, 54 | serverinfo: 11, 55 | lightstyle: 12, 56 | updatename: 13, 57 | updatefrags: 14, 58 | clientdata: 15, 59 | stopsound: 16, 60 | updatecolors: 17, 61 | particle: 18, 62 | damage: 19, 63 | spawnstatic: 20, 64 | spawnbaseline: 22, 65 | temp_entity: 23, 66 | setpause: 24, 67 | signonnum: 25, 68 | centerprint: 26, 69 | killedmonster: 27, 70 | foundsecret: 28, 71 | spawnstaticsound: 29, 72 | intermission: 30, 73 | finale: 31, 74 | cdtrack: 32, 75 | sellscreen: 33, 76 | cutscene: 34 77 | }; 78 | 79 | Protocol.clc = { 80 | nop: 1, 81 | disconnect: 2, 82 | move: 3, 83 | stringcmd: 4 84 | }; 85 | 86 | Protocol.te = { 87 | spike: 0, 88 | superspike: 1, 89 | gunshot: 2, 90 | explosion: 3, 91 | tarexplosion: 4, 92 | lightning1: 5, 93 | lightning2: 6, 94 | wizspike: 7, 95 | knightspike: 8, 96 | lightning3: 9, 97 | lavasplash: 10, 98 | teleport: 11, 99 | explosion2: 12, 100 | beam: 13 101 | }; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // foo 2 | document.addEventListener('DOMContentLoaded', onready) 3 | 4 | function decode_arguments_qp() { 5 | if (window.location.search) { 6 | var s = window.location.search.slice(1,window.location.search.length) 7 | var parts = s.split('&') 8 | var d = {} 9 | for (var i=0; i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 56 |
57 | Command Help 58 |

59 | Server address: 60 |

61 |
62 | hint: you can open the quake console and type "connect ws://127.0.0.1:26000" (where 127.0.0.1 is the ip address) to connect. Server does not yet support full quake files (e.g. e2m2 etc). 63 | 64 | 65 | -------------------------------------------------------------------------------- /server/js/SyncClientSys.js: -------------------------------------------------------------------------------- 1 | Sys = {}; 2 | 3 | Sys.Quit = function() 4 | { 5 | if (Sys.frame != null) 6 | clearInterval(Sys.frame); 7 | var i; 8 | for (i = 0; i < Sys.events.length; ++i) 9 | window[Sys.events[i]] = null; 10 | Host.Shutdown(); 11 | throw new Error; 12 | }; 13 | 14 | Sys.Print = function(text) 15 | { 16 | if (window.console != null) 17 | if (stdoutwrite) stdoutwrite(text) 18 | console.log(text); 19 | }; 20 | 21 | Sys.Error = function(text) 22 | { 23 | console.log(text) 24 | if (stdoutwrite) stdoutwrite(text) 25 | if (Host.initialized === true) 26 | Host.Shutdown(); 27 | throw new Error(text); 28 | }; 29 | 30 | Sys.FloatTime = function() 31 | { 32 | return Date.now() * 0.001 - Sys.oldtime; 33 | }; 34 | 35 | Sys.cmd = '' 36 | Sys.ConsoleInput = function() 37 | { 38 | var text = Sys.cmd; 39 | if (text.length === 0) 40 | return; 41 | Sys.cmd = ''; 42 | return text; 43 | }; 44 | 45 | Sys.main = function() 46 | { 47 | if (Number.isNaN != null) 48 | Q.isNaN = Number.isNaN; 49 | else 50 | Q.isNaN = isNaN; 51 | 52 | var i; 53 | 54 | var cmdline = decodeURIComponent(document.location.search); 55 | var location = document.location; 56 | var argv = [location.href.substring(0, location.href.length - location.search.length)]; 57 | if (cmdline.charCodeAt(0) === 63) 58 | { 59 | var text = ''; 60 | var quotes = false; 61 | var c; 62 | for (i = 1; i < cmdline.length; ++i) 63 | { 64 | c = cmdline.charCodeAt(i); 65 | if ((c < 32) || (c > 127)) 66 | continue; 67 | if (c === 34) 68 | { 69 | quotes = !quotes; 70 | continue; 71 | } 72 | if ((quotes === false) && (c === 32)) 73 | { 74 | if (text.length === 0) 75 | continue; 76 | argv[argv.length] = text; 77 | text = ''; 78 | continue; 79 | } 80 | text += cmdline.charAt(i); 81 | } 82 | if (text.length !== 0) 83 | argv[argv.length] = text; 84 | } 85 | COM.InitArgv(argv); 86 | 87 | Sys.oldtime = Date.now() * 0.001; 88 | 89 | Sys.Print('Host.Init\n'); 90 | Host.Init(); 91 | 92 | setTimeout( Host.Frame, 1 ) 93 | //Sys.frame = setInterval(Host.Frame, 1000.0 / Sys.framerate); 94 | }; 95 | 96 | 97 | Sys.StdinOnData = function(data) 98 | { 99 | Sys.cmd += Q.memstr(data); 100 | }; 101 | -------------------------------------------------------------------------------- /server/js/CRC.js: -------------------------------------------------------------------------------- 1 | CRC = {}; 2 | 3 | CRC.table = [ 4 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 5 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 6 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 7 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 8 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 9 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 10 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 11 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 12 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 13 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 14 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 15 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 16 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 17 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 18 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 19 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 20 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 21 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 22 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 23 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 24 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 25 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 26 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 27 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 28 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 29 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 30 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 31 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 32 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 33 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 34 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 35 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 36 | ]; 37 | 38 | CRC.Block = function(start) 39 | { 40 | var crcvalue = 0xffff; 41 | var i; 42 | for (i = 0; i < start.length; ++i) 43 | crcvalue = ((crcvalue << 8) & 0xffff) ^ CRC.table[(crcvalue >> 8) ^ start[i]]; 44 | return crcvalue; 45 | }; -------------------------------------------------------------------------------- /server/js/MSG.js: -------------------------------------------------------------------------------- 1 | MSG = {}; 2 | 3 | MSG.WriteChar = function(sb, c) 4 | { 5 | (new DataView(sb.data)).setInt8(SZ.GetSpace(sb, 1), c); 6 | }; 7 | 8 | MSG.WriteByte = function(sb, c) 9 | { 10 | (new DataView(sb.data)).setUint8(SZ.GetSpace(sb, 1), c); 11 | }; 12 | 13 | MSG.WriteShort = function(sb, c) 14 | { 15 | (new DataView(sb.data)).setInt16(SZ.GetSpace(sb, 2), c, true); 16 | }; 17 | 18 | MSG.WriteLong = function(sb, c) 19 | { 20 | (new DataView(sb.data)).setInt32(SZ.GetSpace(sb, 4), c, true); 21 | }; 22 | 23 | MSG.WriteFloat = function(sb, f) 24 | { 25 | (new DataView(sb.data)).setFloat32(SZ.GetSpace(sb, 4), f, true); 26 | }; 27 | 28 | MSG.WriteString = function(sb, s) 29 | { 30 | if (s != null) 31 | SZ.Write(sb, new Uint8Array(Q.strmem(s)), s.length); 32 | MSG.WriteChar(sb, 0) 33 | }; 34 | 35 | MSG.WriteCoord = function(sb, f) 36 | { 37 | MSG.WriteShort(sb, f * 8.0); 38 | }; 39 | 40 | MSG.WriteAngle = function(sb, f) 41 | { 42 | MSG.WriteByte(sb, ((f >> 0) * (256.0 / 360.0)) & 255); 43 | }; 44 | 45 | MSG.BeginReading = function() 46 | { 47 | MSG.readcount = 0; 48 | MSG.badread = false; 49 | }; 50 | 51 | MSG.ReadChar = function() 52 | { 53 | if (MSG.readcount >= NET.message.cursize) 54 | { 55 | MSG.badread = true; 56 | return -1; 57 | } 58 | var c = (new Int8Array(NET.message.data, MSG.readcount, 1))[0]; 59 | ++MSG.readcount; 60 | return c; 61 | }; 62 | 63 | MSG.ReadByte = function() 64 | { 65 | if (MSG.readcount >= NET.message.cursize) 66 | { 67 | MSG.badread = true; 68 | return -1; 69 | } 70 | var c = (new Uint8Array(NET.message.data, MSG.readcount, 1))[0]; 71 | ++MSG.readcount; 72 | return c; 73 | }; 74 | 75 | MSG.ReadShort = function() 76 | { 77 | if ((MSG.readcount + 2) > NET.message.cursize) 78 | { 79 | MSG.badread = true; 80 | return -1; 81 | } 82 | var c = (new DataView(NET.message.data)).getInt16(MSG.readcount, true); 83 | MSG.readcount += 2; 84 | return c; 85 | }; 86 | 87 | MSG.ReadLong = function() 88 | { 89 | if ((MSG.readcount + 4) > NET.message.cursize) 90 | { 91 | MSG.badread = true; 92 | return -1; 93 | } 94 | var c = (new DataView(NET.message.data)).getInt32(MSG.readcount, true); 95 | MSG.readcount += 4; 96 | return c; 97 | }; 98 | 99 | MSG.ReadFloat = function() 100 | { 101 | if ((MSG.readcount + 4) > NET.message.cursize) 102 | { 103 | MSG.badread = true; 104 | return -1; 105 | } 106 | var f = (new DataView(NET.message.data)).getFloat32(MSG.readcount, true); 107 | MSG.readcount += 4; 108 | return f; 109 | }; 110 | 111 | MSG.ReadString = function() 112 | { 113 | var string = [], l, c; 114 | for (l = 0; l < 2048; ++l) 115 | { 116 | c = MSG.ReadByte(); 117 | if (c <= 0) 118 | break; 119 | string[l] = String.fromCharCode(c); 120 | } 121 | return string.join(''); 122 | }; 123 | 124 | MSG.ReadCoord = function() 125 | { 126 | return MSG.ReadShort() * 0.125; 127 | }; 128 | 129 | MSG.ReadAngle = function() 130 | { 131 | return MSG.ReadChar() * 1.40625; 132 | }; -------------------------------------------------------------------------------- /server/js/Q.js: -------------------------------------------------------------------------------- 1 | Q = {}; 2 | 3 | Q.memstr = function(src) 4 | { 5 | var dest = [], i; 6 | for (i = 0; i < src.length; ++i) 7 | { 8 | if (src[i] === 0) 9 | break; 10 | dest[i] = String.fromCharCode(src[i]); 11 | } 12 | return dest.join(''); 13 | }; 14 | 15 | Q.strmem = function(src) 16 | { 17 | var buf = new ArrayBuffer(src.length); 18 | var dest = new Uint8Array(buf); 19 | var i; 20 | for (i = 0; i < src.length; ++i) 21 | dest[i] = src.charCodeAt(i) & 255; 22 | return buf; 23 | }; 24 | 25 | Q.atoi = function(str) 26 | { 27 | if (str == null) 28 | return 0; 29 | var ptr, val = 0, sign, c, c2; 30 | if (str.charCodeAt(0) === 45) 31 | { 32 | sign = -1; 33 | ptr = 1; 34 | } 35 | else 36 | { 37 | sign = 1; 38 | ptr = 0; 39 | } 40 | c = str.charCodeAt(ptr); 41 | c2 = str.charCodeAt(ptr + 1); 42 | if ((c === 48) && ((c2 === 120) || (c2 === 88))) 43 | { 44 | ptr += 2; 45 | for (;;) 46 | { 47 | c = str.charCodeAt(ptr++); 48 | if ((c >= 48) && (c <= 57)) 49 | val = (val << 4) + c - 48; 50 | else if ((c >= 97) && (c <= 102)) 51 | val = (val << 4) + c - 87; 52 | else if ((c >= 65) && (c <= 70)) 53 | val = (val << 4) + c - 55; 54 | else 55 | return val * sign; 56 | } 57 | } 58 | if (c === 39) 59 | { 60 | if (Number.isNaN(c2) === true) 61 | return 0; 62 | return sign * c2; 63 | } 64 | for (;;) 65 | { 66 | c = str.charCodeAt(ptr++); 67 | if ((Number.isNaN(c) === true) || (c <= 47) || (c >= 58)) 68 | return val * sign; 69 | val = val * 10 + c - 48; 70 | } 71 | return 0; 72 | }; 73 | 74 | Q.atof = function(str) 75 | { 76 | if (str == null) 77 | return 0.0; 78 | var ptr, val, sign, c, c2; 79 | if (str.charCodeAt(0) === 45) 80 | { 81 | sign = -1.0; 82 | ptr = 1; 83 | } 84 | else 85 | { 86 | sign = 1.0; 87 | ptr = 0; 88 | } 89 | c = str.charCodeAt(ptr); 90 | c2 = str.charCodeAt(ptr + 1); 91 | if ((c === 48) && ((c2 === 120) || (c2 === 88))) 92 | { 93 | ptr += 2; 94 | val = 0.0; 95 | for (;;) 96 | { 97 | c = str.charCodeAt(ptr++); 98 | if ((c >= 48) && (c <= 57)) 99 | val = (val * 16.0) + c - 48; 100 | else if ((c >= 97) && (c <= 102)) 101 | val = (val * 16.0) + c - 87; 102 | else if ((c >= 65) && (c <= 70)) 103 | val = (val * 16.0) + c - 55; 104 | else 105 | return val * sign; 106 | } 107 | } 108 | if (c === 39) 109 | { 110 | if (Number.isNaN(c2) === true) 111 | return 0.0; 112 | return sign * c2; 113 | } 114 | val = parseFloat(str); 115 | if (Number.isNaN(val) === true) 116 | return 0.0; 117 | return val; 118 | }; 119 | 120 | Q.btoa = function(src) 121 | { 122 | var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 123 | var val = []; 124 | var len = src.length - (src.length % 3); 125 | var c, i; 126 | for (i = 0; i < len; i += 3) 127 | { 128 | c = (src[i] << 16) + (src[i + 1] << 8) + src[i + 2]; 129 | val[val.length] = str.charAt(c >> 18) + str.charAt((c >> 12) & 63) + str.charAt((c >> 6) & 63) + str.charAt(c & 63); 130 | } 131 | if ((src.length - len) === 1) 132 | { 133 | c = src[len]; 134 | val[val.length] = str.charAt(c >> 2) + str.charAt((c & 3) << 4) + '=='; 135 | } 136 | else if ((src.length - len) === 2) 137 | { 138 | c = (src[len] << 8) + src[len + 1]; 139 | val[val.length] = str.charAt(c >> 10) + str.charAt((c >> 4) & 63) + str.charAt((c & 15) << 2) + '='; 140 | } 141 | return val.join(''); 142 | }; -------------------------------------------------------------------------------- /server/js/Vec.js: -------------------------------------------------------------------------------- 1 | Vec = {}; 2 | 3 | Vec.origin = [0.0, 0.0, 0.0]; 4 | 5 | Vec.Anglemod = function(a) 6 | { 7 | return (a % 360.0 + 360.0) % 360.0; 8 | }; 9 | 10 | Vec.BoxOnPlaneSide = function(emins, emaxs, p) 11 | { 12 | if (p.type <= 2) 13 | { 14 | if (p.dist <= emins[p.type]) 15 | return 1; 16 | if (p.dist >= emaxs[p.type]) 17 | return 2; 18 | return 3; 19 | } 20 | var dist1, dist2; 21 | switch (p.signbits) 22 | { 23 | case 0: 24 | dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2]; 25 | dist2 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2]; 26 | break; 27 | case 1: 28 | dist1 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2]; 29 | dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2]; 30 | break; 31 | case 2: 32 | dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2]; 33 | dist2 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2]; 34 | break; 35 | case 3: 36 | dist1 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2]; 37 | dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2]; 38 | break; 39 | case 4: 40 | dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2]; 41 | dist2 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2]; 42 | break; 43 | case 5: 44 | dist1 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emins[2]; 45 | dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emaxs[2]; 46 | break; 47 | case 6: 48 | dist1 = p.normal[0] * emaxs[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2]; 49 | dist2 = p.normal[0] * emins[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2]; 50 | break; 51 | case 7: 52 | dist1 = p.normal[0] * emins[0] + p.normal[1] * emins[1] + p.normal[2] * emins[2]; 53 | dist2 = p.normal[0] * emaxs[0] + p.normal[1] * emaxs[1] + p.normal[2] * emaxs[2]; 54 | break; 55 | default: 56 | Sys.Error('Vec.BoxOnPlaneSide: Bad signbits'); 57 | } 58 | var sides = 0; 59 | if (dist1 >= p.dist) 60 | sides = 1; 61 | if (dist2 < p.dist) 62 | sides += 2; 63 | return sides; 64 | }; 65 | 66 | Vec.AngleVectors = function(angles, forward, right, up) 67 | { 68 | var angle; 69 | 70 | angle = angles[0] * Math.PI / 180.0; 71 | var sp = Math.sin(angle); 72 | var cp = Math.cos(angle); 73 | angle = angles[1] * Math.PI / 180.0; 74 | var sy = Math.sin(angle); 75 | var cy = Math.cos(angle); 76 | angle = angles[2] * Math.PI / 180.0; 77 | var sr = Math.sin(angle); 78 | var cr = Math.cos(angle); 79 | 80 | if (forward != null) 81 | { 82 | forward[0] = cp * cy; 83 | forward[1] = cp * sy; 84 | forward[2] = -sp; 85 | } 86 | if (right != null) 87 | { 88 | right[0] = cr * sy - sr * sp * cy; 89 | right[1] = -sr * sp * sy - cr * cy; 90 | right[2] = -sr * cp; 91 | } 92 | if (up != null) 93 | { 94 | up[0] = cr * sp * cy + sr * sy; 95 | up[1] = cr * sp * sy - sr * cy; 96 | up[2] = cr * cp; 97 | } 98 | }; 99 | 100 | Vec.CrossProduct = function(v1, v2) 101 | { 102 | return [ 103 | v1[1] * v2[2] - v1[2] * v2[1], 104 | v1[2] * v2[0] - v1[0] * v2[2], 105 | v1[0] * v2[1] - v1[1] * v2[0] 106 | ]; 107 | }; 108 | 109 | Vec.Length = function(v) 110 | { 111 | return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 112 | }; 113 | 114 | Vec.Normalize = function(v) 115 | { 116 | var length = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 117 | if (length === 0.0) 118 | { 119 | v[0] = v[1] = v[2] = 0.0; 120 | return 0.0; 121 | } 122 | v[0] /= length; 123 | v[1] /= length; 124 | v[2] /= length; 125 | return length; 126 | }; -------------------------------------------------------------------------------- /server/chromenodews.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | function ExampleWebSocketHandler(n) { 3 | this.n = n 4 | WSC.WebSocketHandler.prototype.constructor.call(this) 5 | } 6 | var ExampleWebSocketHandler_prototype = { 7 | open: function() { 8 | console.log('websocket handler handler.open()',this.request) 9 | window.ws = this 10 | //this.ws_connection.mask_outgoing = false 11 | this.set_nodelay() 12 | this.n.trigger('request',this) 13 | this.origin = 'localhost' 14 | this.socket = this.request.connection.stream 15 | this.socket.remoteAddress = '???' 16 | //this.write_message("hello!") 17 | 18 | this.closeReasonCode = -1 19 | this._listeners = {} 20 | 21 | }, 22 | drop: function(code) { 23 | this.close(code) 24 | }, 25 | sendBytes: function(data) { 26 | if (! this.ws_connection) return -1 27 | //console.log('writing data',data.data.byteLength) 28 | this.write_message(data.buffer,true) 29 | }, 30 | select_subprotocols: function(subprots) { 31 | this.requestedProtocols = subprots 32 | if (subprots.length > 0 && subprots[0] == 'quake') return 'quake' 33 | }, 34 | reject: function() { 35 | this.close() 36 | }, 37 | accept: function(subprot, origin) { 38 | return this 39 | }, 40 | on_message: function(msg) { 41 | //console.log('got ws message',msg) 42 | //this.n.trigger('message',msg) 43 | this.trigger('message',{type:'binary',binaryData:msg}) 44 | //this.write_message('pong') 45 | }, 46 | on_close: function() { 47 | this.closeReasonCode = 100 48 | //this.n.trigger('close') 49 | this.trigger('close') 50 | 51 | }, 52 | trigger: function(evt,data) { 53 | var l = this._listeners[evt] 54 | if (l && l.length > 0) { 55 | l.forEach( function(cb) { cb(data) } ) 56 | } 57 | }, 58 | on: function(evt, cb) { 59 | if (! this._listeners[evt]) 60 | this._listeners[evt] = [] 61 | this._listeners[evt].push(cb) 62 | } 63 | } 64 | for (var m in WSC.WebSocketHandler.prototype) { 65 | ExampleWebSocketHandler.prototype[m] = WSC.WebSocketHandler.prototype[m] 66 | } 67 | for (var m in ExampleWebSocketHandler_prototype) { 68 | ExampleWebSocketHandler.prototype[m] = ExampleWebSocketHandler_prototype[m] 69 | } 70 | 71 | 72 | 73 | function ChromeNodeWS() { 74 | // wrapper for WSC websocket impl 75 | this._listeners = {} 76 | 77 | var opts = {} 78 | opts.port = 26000 79 | opts.optAllInterfaces = true 80 | opts.optDoPortMapping = true 81 | opts.optTryOtherPorts = false 82 | opts.optRetryInterfaces = false 83 | //WSC.VERBOSE = WSC.DEBUG = 1 84 | opts.optBackground = false 85 | opts.handlers = [] 86 | window.webapp = new WSC.WebApplication(opts) 87 | webapp.add_handler(['.*', ExampleWebSocketHandler.bind(null,this)]) 88 | webapp.init_handlers() 89 | webapp.start( function(result) { 90 | var selt = document.getElementById('server-addresses') 91 | selt.innerHTML = '' 92 | var ul = document.createElement('ul') 93 | console.log('webapp start result',result) 94 | if (result.error) { 95 | selt.innerText = JSON.stringify(result.error) 96 | } else { 97 | var t = '' 98 | for (var i=0; i 0) { 121 | l.forEach( function(cb) { cb(data) } ) 122 | } 123 | }, 124 | on: function(evt, cb) { 125 | //console.log('register',evt,cb) 126 | if (! this._listeners[evt]) 127 | this._listeners[evt] = [] 128 | this._listeners[evt].push(cb) 129 | } 130 | } 131 | 132 | window.ChromeNodeWS = ChromeNodeWS 133 | })(); 134 | -------------------------------------------------------------------------------- /server/js/Cmd.js: -------------------------------------------------------------------------------- 1 | Cmd = {}; 2 | 3 | Cmd.alias = []; 4 | 5 | Cmd.Wait_f = function() 6 | { 7 | Cmd.wait = true; 8 | }; 9 | 10 | Cmd.text = ''; 11 | 12 | Cmd.Execute = function() 13 | { 14 | var i, c, line = '', quotes = false; 15 | while (Cmd.text.length !== 0) 16 | { 17 | c = Cmd.text.charCodeAt(0); 18 | Cmd.text = Cmd.text.substring(1); 19 | if (c === 34) 20 | { 21 | quotes = !quotes; 22 | line += '\42'; 23 | continue; 24 | } 25 | if (((quotes === false) && (c === 59)) || (c === 10)) 26 | { 27 | if (line.length === 0) 28 | continue; 29 | Cmd.ExecuteString(line); 30 | if (Cmd.wait === true) 31 | { 32 | Cmd.wait = false; 33 | return; 34 | } 35 | line = ''; 36 | continue; 37 | } 38 | line += String.fromCharCode(c); 39 | } 40 | Cmd.text = ''; 41 | }; 42 | 43 | Cmd.StuffCmds_f = function() 44 | { 45 | var i, s = false, build = '', c; 46 | for (i = 0; i < COM.argv.length; ++i) 47 | { 48 | c = COM.argv[i].charCodeAt(0); 49 | if (s === true) 50 | { 51 | if (c === 43) 52 | { 53 | build += ('\n' + COM.argv[i].substring(1) + ' '); 54 | continue; 55 | } 56 | if (c === 45) 57 | { 58 | s = false; 59 | build += '\n'; 60 | continue; 61 | } 62 | build += (COM.argv[i] + ' '); 63 | continue; 64 | } 65 | if (c === 43) 66 | { 67 | s = true; 68 | build += (COM.argv[i].substring(1) + ' '); 69 | } 70 | } 71 | if (build.length !== 0) 72 | Cmd.text = build + '\n' + Cmd.text; 73 | }; 74 | 75 | Cmd.Exec_f = function() 76 | { 77 | if (Cmd.argv.length !== 2) 78 | { 79 | Con.Print('exec : execute a script file\n'); 80 | return; 81 | } 82 | var f = COM.LoadTextFile(Cmd.argv[1]); 83 | if (f == null) 84 | { 85 | Con.Print('couldn\'t exec ' + Cmd.argv[1] + '\n'); 86 | return; 87 | } 88 | Con.Print('execing ' + Cmd.argv[1] + '\n'); 89 | Cmd.text = f + Cmd.text; 90 | }; 91 | 92 | Cmd.Echo_f = function() 93 | { 94 | var i; 95 | for (i = 1; i < Cmd.argv.length; ++i) 96 | Con.Print(Cmd.argv[i] + ' '); 97 | Con.Print('\n'); 98 | }; 99 | 100 | Cmd.Alias_f = function() 101 | { 102 | var i; 103 | if (Cmd.argv.length <= 1) 104 | { 105 | Con.Print('Current alias commands:\n'); 106 | for (i = 0; i < Cmd.alias.length; ++i) 107 | Con.Print(Cmd.alias[i].name + ' : ' + Cmd.alias[i].value + '\n'); 108 | } 109 | var s = Cmd.argv[1], value = ''; 110 | for (i = 0; i < Cmd.alias.length; ++i) 111 | { 112 | if (Cmd.alias[i].name === s) 113 | break; 114 | } 115 | var j; 116 | for (j = 2; j < Cmd.argv.length; ++j) 117 | { 118 | value += Cmd.argv[j]; 119 | if (j !== Cmd.argv.length) 120 | value += ' '; 121 | } 122 | Cmd.alias[i] = {name: s, value: value + '\n'}; 123 | }; 124 | 125 | Cmd.argv = []; 126 | Cmd.functions = []; 127 | 128 | Cmd.Init = function() 129 | { 130 | Cmd.AddCommand('stuffcmds', Cmd.StuffCmds_f); 131 | Cmd.AddCommand('exec', Cmd.Exec_f); 132 | Cmd.AddCommand('echo', Cmd.Echo_f); 133 | Cmd.AddCommand('alias', Cmd.Alias_f); 134 | Cmd.AddCommand('wait', Cmd.Wait_f); 135 | }; 136 | 137 | Cmd.TokenizeString = function(text) 138 | { 139 | Cmd.argv = []; 140 | var i, c; 141 | for (;;) 142 | { 143 | for (i = 0; i < text.length; ++i) 144 | { 145 | c = text.charCodeAt(i); 146 | if ((c > 32) || (c === 10)) 147 | break; 148 | } 149 | if (Cmd.argv.length === 1) 150 | Cmd.args = text.substring(i); 151 | if ((text.charCodeAt(i) === 10) || (i >= text.length)) 152 | return; 153 | text = COM.Parse(text); 154 | if (text == null) 155 | return; 156 | Cmd.argv[Cmd.argv.length] = COM.token; 157 | } 158 | }; 159 | 160 | Cmd.AddCommand = function(name, command) 161 | { 162 | var i; 163 | for (i = 0; i < Cvar.vars.length; ++i) 164 | { 165 | if (Cvar.vars[i].name === name) 166 | { 167 | Con.Print('Cmd.AddCommand: ' + name + ' already defined as a var\n'); 168 | return; 169 | } 170 | } 171 | for (i = 0; i < Cmd.functions.length; ++i) 172 | { 173 | if (Cmd.functions[i].name === name) 174 | { 175 | Con.Print('Cmd.AddCommand: ' + name + ' already defined\n'); 176 | return; 177 | } 178 | } 179 | Cmd.functions[Cmd.functions.length] = {name: name, command: command}; 180 | }; 181 | 182 | Cmd.ExecuteString = function(text, client) 183 | { 184 | Cmd.client = client; 185 | Cmd.TokenizeString(text); 186 | if (Cmd.argv.length === 0) 187 | return; 188 | var name = Cmd.argv[0].toLowerCase(); 189 | var i; 190 | for (i = 0; i < Cmd.functions.length; ++i) 191 | { 192 | if (Cmd.functions[i].name === name) 193 | { 194 | Cmd.functions[i].command(); 195 | return; 196 | } 197 | } 198 | for (i = 0; i < Cmd.alias.length; ++i) 199 | { 200 | if (Cmd.alias[i].name === name) 201 | { 202 | Cmd.text = Cmd.alias[i].value + Cmd.text; 203 | return; 204 | } 205 | } 206 | if (Cvar.Command() !== true) 207 | Con.Print('Unknown command "' + name + '"\n'); 208 | }; -------------------------------------------------------------------------------- /launch.js: -------------------------------------------------------------------------------- 1 | document.addEventListener("DOMContentLoaded",onready) 2 | var reload = chrome.runtime.reload 3 | var localServer = false 4 | function getel(id) { return document.getElementById(id) } 5 | window.delay = 1000 6 | window.g_retained = [] 7 | window.g_paks = {} 8 | function onstorage(items) { 9 | console.log('storage',items) 10 | return 11 | if (items.retained) { 12 | // restore all retained entries 13 | console.log('need to restore entries',items.retained) 14 | g_retained = items.retained 15 | 16 | for (var i=0; i SV.svs.maxclientslimit) 62 | { 63 | n = SV.svs.maxclientslimit; 64 | Con.Print('"maxplayers" set to "' + n + '"\n'); 65 | } 66 | if ((n === 1) && (NET.listening === true)) 67 | Cmd.text += 'listen 0\n'; 68 | else if ((n >= 2) && (NET.listening !== true)) 69 | Cmd.text += 'listen 1\n'; 70 | SV.svs.maxclients = n; 71 | if (n === 1) 72 | Cvar.Set('deathmatch', '0'); 73 | else 74 | Cvar.Set('deathmatch', '1'); 75 | }; 76 | 77 | NET.Port_f = function() 78 | { 79 | if (Cmd.argv.length !== 2) 80 | { 81 | Con.Print('"port" is "' + NET.hostport + '"\n'); 82 | return; 83 | } 84 | var n = Q.atoi(Cmd.argv[1]); 85 | if ((n <= 0) || (n >= 65535)) 86 | { 87 | Con.Print('Bad value, must be between 1 and 65534\n'); 88 | return; 89 | } 90 | NET.hostport = n; 91 | if (NET.listening === true) 92 | Cmd.text += 'listen 0\nlisten 1\n'; 93 | }; 94 | 95 | NET.CheckNewConnections = function() 96 | { 97 | NET.time = Sys.FloatTime(); 98 | var dfunc, ret; 99 | for (NET.driverlevel = 0; NET.driverlevel < NET.drivers.length; ++NET.driverlevel) 100 | { 101 | dfunc = NET.drivers[NET.driverlevel]; 102 | if (dfunc.initialized !== true) 103 | continue; 104 | ret = dfunc.CheckNewConnections(); 105 | if (ret != null) 106 | return ret; 107 | } 108 | }; 109 | 110 | NET.Close = function(sock) 111 | { 112 | if (sock == null) 113 | return; 114 | if (sock.disconnected === true) 115 | return; 116 | NET.time = Sys.FloatTime(); 117 | NET.drivers[sock.driver].Close(sock); 118 | sock.disconnected = true; 119 | }; 120 | 121 | NET.GetMessage = function(sock) 122 | { 123 | if (sock == null) 124 | return -1; 125 | if (sock.disconnected === true) 126 | { 127 | Con.Print('NET.GetMessage: disconnected socket\n'); 128 | return -1; 129 | } 130 | NET.time = Sys.FloatTime(); 131 | var ret = NET.drivers[sock.driver].GetMessage(sock); 132 | if (ret === 0) 133 | { 134 | if ((NET.time - sock.lastMessageTime) > NET.messagetimeout.value) 135 | { 136 | NET.Close(sock); 137 | return -1; 138 | } 139 | } 140 | else if (ret > 0) 141 | sock.lastMessageTime = NET.time; 142 | return ret; 143 | }; 144 | 145 | NET.SendMessage = function(sock, data) 146 | { 147 | if (sock == null) 148 | return -1; 149 | if (sock.disconnected === true) 150 | { 151 | Con.Print('NET.SendMessage: disconnected socket\n'); 152 | return -1; 153 | } 154 | NET.time = Sys.FloatTime(); 155 | return NET.drivers[sock.driver].SendMessage(sock, data); 156 | }; 157 | 158 | NET.SendUnreliableMessage = function(sock, data) 159 | { 160 | if (sock == null) 161 | return -1; 162 | if (sock.disconnected === true) 163 | { 164 | Con.Print('NET.SendUnreliableMessage: disconnected socket\n'); 165 | return -1; 166 | } 167 | NET.time = Sys.FloatTime(); 168 | return NET.drivers[sock.driver].SendUnreliableMessage(sock, data); 169 | }; 170 | 171 | NET.CanSendMessage = function(sock) 172 | { 173 | if (sock == null) 174 | return; 175 | if (sock.disconnected === true) 176 | return; 177 | NET.time = Sys.FloatTime(); 178 | return NET.drivers[sock.driver].CanSendMessage(sock); 179 | }; 180 | 181 | NET.SendToAll = function(data) 182 | { 183 | var i, count = 0, state1 = [], state2 = []; 184 | for (i = 0; i < SV.svs.maxclients; ++i) 185 | { 186 | Host.client = SV.svs.clients[i]; 187 | if (Host.client.netconnection == null) 188 | continue; 189 | if (Host.client.active !== true) 190 | { 191 | state1[i] = state2[i] = true; 192 | continue; 193 | } 194 | ++count; 195 | state1[i] = state2[i] = false; 196 | } 197 | var start = Sys.FloatTime(); 198 | for (; count !== 0; ) 199 | { 200 | count = 0; 201 | for (i = 0; i < SV.svs.maxclients; ++i) 202 | { 203 | Host.client = SV.svs.clients[i]; 204 | if (state1[i] !== true) 205 | { 206 | if (NET.CanSendMessage(Host.client.netconnection) === true) 207 | { 208 | state1[i] = true; 209 | NET.SendMessage(Host.client.netconnection, data); 210 | } 211 | else 212 | NET.GetMessage(Host.client.netconnection); 213 | ++count; 214 | continue; 215 | } 216 | if (state2[i] !== true) 217 | { 218 | if (NET.CanSendMessage(Host.client.netconnection) === true) 219 | state2[i] = true; 220 | else 221 | NET.GetMessage(Host.client.netconnection); 222 | ++count; 223 | } 224 | } 225 | if ((Sys.FloatTime() - start) > 5.0) 226 | return count; 227 | } 228 | return count; 229 | }; 230 | 231 | NET.Init = function() 232 | { 233 | var i = COM.CheckParm('-port'); 234 | if (i != null) 235 | { 236 | i = Q.atoi(COM.argv[i + 1]); 237 | if ((i > 0) && (i <= 65534)) 238 | NET.hostport = i; 239 | } 240 | 241 | NET.listening = true; 242 | 243 | NET.time = Sys.FloatTime(); 244 | 245 | NET.messagetimeout = Cvar.RegisterVariable('net_messagetimeout', '300'); 246 | var buff = Node.os.hostname().substring(0, 15), local = []; 247 | for (i = 0; i < buff.length; ++i) 248 | local[i] = String.fromCharCode(buff.charCodeAt(i) & 255); 249 | NET.hostname = Cvar.RegisterVariable('hostname', local.join('')); 250 | Cmd.AddCommand('listen', NET.Listen_f); 251 | Cmd.AddCommand('maxplayers', NET.MaxPlayers_f); 252 | Cmd.AddCommand('port', NET.Port_f); 253 | 254 | //NET.drivers = [Datagram, WEBS]; 255 | NET.drivers = [WEBS]; 256 | var dfunc; 257 | for (NET.driverlevel = 0; NET.driverlevel < NET.drivers.length; ++NET.driverlevel) 258 | { 259 | dfunc = NET.drivers[NET.driverlevel]; 260 | dfunc.initialized = dfunc.Init(); 261 | if (dfunc.initialized === true) 262 | dfunc.Listen(); 263 | } 264 | }; 265 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | /* 2 | Node = { 3 | dgram: require('dgram'), 4 | fs: require('fs'), 5 | http: require('http'), 6 | os: require('os'), 7 | url: require('url'), 8 | websocket: require('websocket') 9 | };*/ 10 | 11 | 12 | 13 | console.log('server.js') 14 | document.addEventListener("DOMContentLoaded",ondom) 15 | var reload = function() { 16 | if (window.webapp) { 17 | webapp.stop('reload', function() { 18 | chrome.runtime.sendMessage('restart_server') 19 | }) 20 | } else { 21 | chrome.runtime.sendMessage('restart_server') 22 | } 23 | 24 | } 25 | 26 | function wait_for_devtools( callback, giveup_after ) { 27 | return callback() 28 | giveup_after = giveup_after || 10 29 | var start = Date.now() 30 | var timeout 31 | var triggered = false 32 | var element = new Image(); 33 | element.__defineGetter__('id', done) 34 | 35 | function done() { 36 | if (triggered) return '' 37 | console.log('devtools attached') 38 | triggered = true 39 | setTimeout(callback, 1000) // its actually still not ready, need to do setTimeout 40 | return '' 41 | } 42 | 43 | function checkit() { 44 | if (triggered) { return } 45 | console.log('waiting for devtools...',element) 46 | if (Date.now() - start > giveup_after * 1000) { 47 | console.log('giving up, just going') 48 | callback() 49 | } else { 50 | timeout = setTimeout( checkit, 200 ) 51 | } 52 | } 53 | checkit() 54 | } 55 | 56 | function showhelp(evt) { 57 | var dialog = document.getElementById('help') 58 | dialog.style.display = '' 59 | dialog.showModal() 60 | evt.preventDefault() 61 | } 62 | function hidehelp() { 63 | var dialog = document.getElementById('help') 64 | //dialog.style.display = 'none' 65 | dialog.close() 66 | } 67 | 68 | function ondom() { 69 | document.getElementById('showhelp').addEventListener('click',showhelp) 70 | document.getElementById('help').addEventListener('click',hidehelp) 71 | celt = document.getElementById('console') 72 | ielt = document.getElementById('input') 73 | wait_for_devtools( go ) 74 | 75 | ielt.addEventListener('keypress', inputkey) 76 | } 77 | 78 | function inputkey(evt) { 79 | //console.log('input',evt.keyCode) 80 | if (evt.keyCode == 13) { 81 | Sys.cmd = ielt.value + '\n' 82 | ielt.value = '' 83 | } 84 | //var char = String.fromCharCode(evt.keyCode) 85 | //Sys.StdinOnData([evt.keyCode]) 86 | } 87 | 88 | /* 89 | Key = {Init:function(){}} 90 | Chase = {Init:function(){}} 91 | VID = {Init:function(){}} 92 | Draw = {Init:function(){}} 93 | SCR = {Init:function(){}} 94 | R = {Init:function(){}} 95 | S = {Init:function(){}} 96 | M = {Init:function(){}} 97 | CDAudio = {Init:function(){}} 98 | Sbar = {Init:function(){}} 99 | CL = {Init:function(){}} 100 | IN = {Init:function(){}} 101 | */ 102 | 103 | function WrapFile(file) { 104 | this.file = file 105 | this.pos = 0 106 | this.length = this.file.length 107 | } 108 | 109 | function openSync(filename, mode) { 110 | if (PAKS[filename]) { 111 | return new WrapFile(PAKS[filename]) 112 | } else { 113 | throw new Error("Not found") 114 | } 115 | } 116 | function closeSync(fd) { 117 | // nothing 118 | } 119 | 120 | function readFileSync(filename) { 121 | if (PAKS[filename]) { 122 | return new Buffer(PAKS[filename]) 123 | } else { 124 | throw new Error("Not found") 125 | } 126 | } 127 | 128 | function readSync(src, dst, dst_offset, length, src_position) { 129 | var a = (src_position !== undefined) ? src_position : src.pos 130 | if (dst_offset === undefined) dst_offset = 0 131 | 132 | var slice = new Uint8Array(src.file.slice(a, a+length)) 133 | dst.set(slice, dst_offset) 134 | } 135 | 136 | var celt 137 | function stdoutwrite(msg) { 138 | console.log(msg) 139 | if (celt) { 140 | var d = document.createElement('div') 141 | d.innerText = msg 142 | celt.appendChild(d) 143 | var obj = document.body 144 | if( (obj.scrollHeight - obj.offsetHeight) - obj.scrollTop < 50) { 145 | obj.scrollTop = obj.scrollHeight + 1000 146 | } 147 | 148 | } 149 | } 150 | process = { stdout: { write: stdoutwrite } } 151 | Node = { 152 | dgram: window.ChromeUDP, 153 | websocket: {server:ChromeNodeWS}, 154 | fs: { 155 | openSync: openSync, 156 | readSync: readSync, 157 | readFileSync: readFileSync, 158 | closeSync: closeSync 159 | 160 | }, 161 | os: { hostname: function() { return navigator.platform } } 162 | } 163 | window.Datagram = null 164 | 165 | 166 | //Loop = {Init:function(){}} // loopback? 167 | 168 | 169 | function decode_arguments_hash() { 170 | var hash = window.location.hash.slice(1,window.location.hash.length) 171 | if (hash.length == 0) { 172 | return {} 173 | } 174 | var parts = hash.split('&') 175 | var args = {} 176 | 177 | for (var i=0; i 1) { 270 | e.getDirectory(state.path.shift(), {create:false}, recurse, recurse) 271 | } else { 272 | state.e = e 273 | e.getFile(state.path.shift(), {create:false}, recurse, recurse) 274 | } 275 | } else { 276 | if (e.name == 'NotFoundError') { 277 | callback({error:e}) 278 | } else { 279 | callback({error:e,mymsg:'file exists'}) 280 | } 281 | } 282 | } 283 | recurse(root) 284 | } 285 | -------------------------------------------------------------------------------- /server/js/COM.js: -------------------------------------------------------------------------------- 1 | COM = {}; 2 | 3 | COM.argv = []; 4 | 5 | COM.standard_quake = true; 6 | 7 | COM.Parse = function(data) 8 | { 9 | COM.token = ''; 10 | var i = 0, c; 11 | if (data.length === 0) 12 | return; 13 | 14 | var skipwhite = true; 15 | for (;;) 16 | { 17 | if (skipwhite !== true) 18 | break; 19 | skipwhite = false; 20 | for (;;) 21 | { 22 | if (i >= data.length) 23 | return; 24 | c = data.charCodeAt(i); 25 | if (c > 32) 26 | break; 27 | ++i; 28 | } 29 | if ((c === 47) && (data.charCodeAt(i + 1) == 47)) 30 | { 31 | for (;;) 32 | { 33 | if ((i >= data.length) || (data.charCodeAt(i) === 10)) 34 | break; 35 | ++i; 36 | } 37 | skipwhite = true; 38 | } 39 | } 40 | 41 | if (c === 34) 42 | { 43 | ++i; 44 | for (;;) 45 | { 46 | c = data.charCodeAt(i); 47 | ++i; 48 | if ((i >= data.length) || (c === 34)) 49 | return data.substring(i); 50 | COM.token += String.fromCharCode(c); 51 | } 52 | } 53 | 54 | for (;;) 55 | { 56 | if ((i >= data.length) || (c <= 32)) 57 | break; 58 | COM.token += String.fromCharCode(c); 59 | ++i; 60 | c = data.charCodeAt(i); 61 | } 62 | 63 | return data.substring(i); 64 | }; 65 | 66 | COM.CheckParm = function(parm) 67 | { 68 | var i; 69 | for (i = 1; i < COM.argv.length; ++i) 70 | { 71 | if (COM.argv[i] === parm) 72 | return i; 73 | } 74 | }; 75 | 76 | COM.CheckRegistered = function() 77 | { 78 | var h = COM.LoadFile('gfx/pop.lmp'); 79 | if (h == null) 80 | { 81 | Con.Print('Playing shareware version.\n'); 82 | if (COM.modified === true) 83 | Sys.Error('You must have the registered version to use modified games'); 84 | return; 85 | } 86 | var check = new Uint8Array(h); 87 | var pop = 88 | [ 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 91 | 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 92 | 0x00, 0x00, 0x66, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x66, 0x00, 93 | 0x00, 0x63, 0x65, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x65, 0x63, 94 | 0x00, 0x64, 0x65, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x65, 0x64, 95 | 0x00, 0x64, 0x65, 0x64, 0x00, 0x00, 0x64, 0x69, 0x69, 0x69, 0x64, 0x00, 0x00, 0x64, 0x65, 0x64, 96 | 0x00, 0x63, 0x65, 0x68, 0x62, 0x00, 0x00, 0x64, 0x68, 0x64, 0x00, 0x00, 0x62, 0x68, 0x65, 0x63, 97 | 0x00, 0x00, 0x65, 0x67, 0x69, 0x63, 0x00, 0x64, 0x67, 0x64, 0x00, 0x63, 0x69, 0x67, 0x65, 0x00, 98 | 0x00, 0x00, 0x62, 0x66, 0x67, 0x69, 0x6A, 0x68, 0x67, 0x68, 0x6A, 0x69, 0x67, 0x66, 0x62, 0x00, 99 | 0x00, 0x00, 0x00, 0x62, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x65, 0x62, 0x00, 0x00, 100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x63, 0x64, 0x66, 0x64, 0x63, 0x62, 0x00, 0x00, 0x00, 0x00, 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x66, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x66, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 105 | ]; 106 | var i; 107 | for (i = 0; i < 256; ++i) 108 | { 109 | if (check[i] !== pop[i]) 110 | Sys.Error('Corrupted data file.'); 111 | } 112 | Cvar.Set('registered', '1'); 113 | Con.Print('Playing registered version.\n'); 114 | }; 115 | 116 | COM.InitArgv = function(argv) 117 | { 118 | COM.cmdline = (argv.join(' ') + ' ').substring(0, 256); 119 | var i; 120 | for (i = 0; i < argv.length; ++i) 121 | COM.argv[i] = argv[i]; 122 | if (COM.CheckParm('-rogue') != null) 123 | { 124 | COM.rogue = true; 125 | COM.standard_quake = false; 126 | } 127 | else if (COM.CheckParm('-hipnotic') != null) 128 | { 129 | COM.hipnotic = true; 130 | COM.standard_quake = false; 131 | } 132 | }; 133 | 134 | COM.Init = function() 135 | { 136 | var swaptest = new ArrayBuffer(2); 137 | var swaptestview = new Uint8Array(swaptest); 138 | swaptestview[0] = 1; 139 | swaptestview[1] = 0; 140 | COM.bigendien = ((new Uint16Array(swaptest))[0] !== 1); 141 | COM.registered = Cvar.RegisterVariable('registered', '0'); 142 | Cvar.RegisterVariable('cmdline', COM.cmdline, false, true); 143 | Cmd.AddCommand('path', COM.Path_f); 144 | COM.InitFilesystem(); 145 | COM.CheckRegistered(); 146 | }; 147 | 148 | COM.searchpaths = []; 149 | 150 | COM.LoadFile = function(filename) 151 | { 152 | filename = filename.toLowerCase(); 153 | var src, i, j, k, search, pak, file, fd; 154 | for (i = COM.searchpaths.length - 1; i >= 0; --i) 155 | { 156 | search = COM.searchpaths[i]; 157 | for (j = search.pack.length - 1; j >= 0; --j) 158 | { 159 | pak = search.pack[j]; 160 | for (k = 0; k < pak.length; ++k) 161 | { 162 | file = pak[k]; 163 | if (file.name !== filename) 164 | continue; 165 | if (file.filelen === 0) 166 | return new ArrayBuffer(0); 167 | try 168 | { 169 | fd = Node.fs.openSync(search.filename + '/pak' + j + '.pak', 'r'); 170 | } 171 | catch (e) 172 | { 173 | break; 174 | } 175 | Sys.Print('PackFile: ' + search.filename + '/pak' + j + '.pak : ' + filename + '\n') 176 | src = new Buffer(file.filelen); 177 | Node.fs.readSync(fd, src, 0, file.filelen, file.filepos); 178 | Node.fs.closeSync(fd); 179 | break; 180 | } 181 | } 182 | if (src != null) 183 | break; 184 | try 185 | { 186 | src = Node.fs.readFileSync(search.filename + '/' + filename); 187 | Sys.Print('FindFile: ' + search.filename + '/' + filename + '\n'); 188 | break; 189 | } 190 | catch (e) 191 | { 192 | } 193 | } 194 | if (src == null) 195 | { 196 | Sys.Print('FindFile: can\'t find ' + filename + '\n'); 197 | return; 198 | } 199 | var size = src.length; 200 | var dest = new ArrayBuffer(size), view = new DataView(dest); 201 | var count = size >> 2; 202 | if (count !== 0) 203 | { 204 | if (COM.bigendien !== true) 205 | { 206 | for (i = 0; i < count; ++i) 207 | view.setUint32(i << 2, src.readUInt32LE(i << 2), true); 208 | } 209 | else 210 | { 211 | for (i = 0; i < count; ++i) 212 | view.setUint32(i << 2, src.readUInt32BE(i << 2)); 213 | } 214 | } 215 | count <<= 2; 216 | switch (size & 3) 217 | { 218 | case 1: 219 | view.setUint8(count, src[count]); 220 | break; 221 | case 2: 222 | view.setUint16(count, src.readUInt16LE(count), true); 223 | break; 224 | case 3: 225 | view.setUint16(count, src.readUInt16LE(count), true); 226 | view.setUint8(count + 2, src[count + 2]); 227 | } 228 | return dest; 229 | }; 230 | 231 | COM.LoadTextFile = function(filename) 232 | { 233 | var buf = COM.LoadFile(filename); 234 | if (buf == null) 235 | return; 236 | var bufview = new Uint8Array(buf); 237 | var f = []; 238 | var i; 239 | for (i = 0; i < bufview.length; ++i) 240 | { 241 | if (bufview[i] !== 13) 242 | f[f.length] = String.fromCharCode(bufview[i]); 243 | } 244 | return f.join(''); 245 | }; 246 | 247 | COM.LoadPackFile = function(packfile) 248 | { 249 | var fd; 250 | try 251 | { 252 | fd = Node.fs.openSync(packfile, 'r'); 253 | } 254 | catch (e) 255 | { 256 | return; 257 | } 258 | var buf = new Buffer(12); 259 | Node.fs.readSync(fd, buf, 0, 12, 0); 260 | if (buf.readUInt32LE(0) !== 0x4b434150) 261 | Sys.Error(packfile + ' is not a packfile'); 262 | var dirofs = buf.readUInt32LE(4); 263 | var dirlen = buf.readUInt32LE(8); 264 | var numpackfiles = dirlen >> 6; 265 | if (numpackfiles !== 339) 266 | COM.modified = true; 267 | var pack = []; 268 | if (numpackfiles !== 0) 269 | { 270 | buf = new Buffer(dirlen); 271 | Node.fs.readSync(fd, buf, 0, dirlen, dirofs); 272 | if (CRC.Block(buf) !== 32981) 273 | COM.modified = true; 274 | var i; 275 | for (i = 0; i < numpackfiles; ++i) 276 | { 277 | pack[pack.length] = 278 | { 279 | name: Q.memstr(buf.slice(i << 6, (i << 6) + 56)).toLowerCase(), 280 | filepos: buf.readUInt32LE((i << 6) + 56), 281 | filelen: buf.readUInt32LE((i << 6) + 60) 282 | } 283 | } 284 | } 285 | Node.fs.closeSync(fd); 286 | Con.Print('Added packfile ' + packfile + ' (' + numpackfiles + ' files)\n'); 287 | return pack; 288 | }; 289 | 290 | COM.AddGameDirectory = function(dir) 291 | { 292 | var search = {filename: dir, pack: []}; 293 | var pak, i = 0; 294 | for (;;) 295 | { 296 | pak = COM.LoadPackFile(dir + '/' + 'pak' + i + '.pak'); 297 | if (pak == null) 298 | break; 299 | search.pack[search.pack.length] = pak; 300 | ++i; 301 | } 302 | COM.searchpaths[COM.searchpaths.length] = search; 303 | }; 304 | 305 | COM.InitFilesystem = function() 306 | { 307 | var i; 308 | var search; 309 | 310 | i = COM.CheckParm('-basedir'); 311 | if (i != null) 312 | { 313 | search = COM.argv[i + 1]; 314 | if (search != null) 315 | COM.AddGameDirectory(search); 316 | } 317 | else 318 | COM.AddGameDirectory('id1'); 319 | 320 | if (COM.rogue === true) 321 | COM.AddGameDirectory('rogue'); 322 | else if (COM.hipnotic === true) 323 | COM.AddGameDirectory('hipnotic'); 324 | 325 | i = COM.CheckParm('-game'); 326 | if (i != null) 327 | { 328 | search = COM.argv[i + 1]; 329 | if (search != null) 330 | { 331 | COM.modified = true; 332 | COM.AddGameDirectory(search); 333 | } 334 | } 335 | }; -------------------------------------------------------------------------------- /server/js/ED.js: -------------------------------------------------------------------------------- 1 | ED = {}; 2 | 3 | ED.ClearEdict = function(e) 4 | { 5 | var i; 6 | for (i = 0; i < PR.entityfields; ++i) 7 | e.v_int[i] = 0; 8 | e.free = false; 9 | }; 10 | 11 | ED.Alloc = function() 12 | { 13 | var i, e; 14 | for (i = SV.svs.maxclients + 1; i < SV.server.num_edicts; ++i) 15 | { 16 | e = SV.server.edicts[i]; 17 | if ((e.free === true) && ((e.freetime < 2.0) || ((SV.server.time - e.freetime) > 0.5))) 18 | { 19 | ED.ClearEdict(e); 20 | return e; 21 | } 22 | } 23 | if (i === Def.max_edicts) 24 | Sys.Error('ED.Alloc: no free edicts'); 25 | e = SV.server.edicts[SV.server.num_edicts++]; 26 | ED.ClearEdict(e); 27 | return e; 28 | }; 29 | 30 | ED.Free = function(ed) 31 | { 32 | SV.UnlinkEdict(ed); 33 | ed.free = true; 34 | ed.v_int[PR.entvars.model] = 0; 35 | ed.v_float[PR.entvars.takedamage] = 0.0; 36 | ed.v_float[PR.entvars.modelindex] = 0.0; 37 | ed.v_float[PR.entvars.colormap] = 0.0; 38 | ed.v_float[PR.entvars.skin] = 0.0; 39 | ed.v_float[PR.entvars.frame] = 0.0; 40 | ED.SetVector(ed, PR.entvars.origin, Vec.origin); 41 | ED.SetVector(ed, PR.entvars.angles, Vec.origin); 42 | ed.v_float[PR.entvars.nextthink] = -1.0; 43 | ed.v_float[PR.entvars.solid] = 0.0; 44 | ed.freetime = SV.server.time; 45 | }; 46 | 47 | ED.GlobalAtOfs = function(ofs) 48 | { 49 | var i, def; 50 | for (i = 0; i < PR.globaldefs.length; ++i) 51 | { 52 | def = PR.globaldefs[i]; 53 | if (def.ofs === ofs) 54 | return def; 55 | } 56 | }; 57 | 58 | ED.FieldAtOfs = function(ofs) 59 | { 60 | var i, def; 61 | for (i = 0; i < PR.fielddefs.length; ++i) 62 | { 63 | def = PR.fielddefs[i]; 64 | if (def.ofs === ofs) 65 | return def; 66 | } 67 | }; 68 | 69 | ED.FindField = function(name) 70 | { 71 | var def, i; 72 | for (i = 0; i < PR.fielddefs.length; ++i) 73 | { 74 | def = PR.fielddefs[i]; 75 | if (PR.GetString(def.name) === name) 76 | return def; 77 | } 78 | }; 79 | 80 | ED.FindGlobal = function(name) 81 | { 82 | var def, i; 83 | for (i = 0; i < PR.globaldefs.length; ++i) 84 | { 85 | def = PR.globaldefs[i]; 86 | if (PR.GetString(def.name) === name) 87 | return def; 88 | } 89 | }; 90 | 91 | ED.FindFunction = function(name) 92 | { 93 | var i; 94 | for (i = 0; i < PR.functions.length; ++i) 95 | { 96 | if (PR.GetString(PR.functions[i].name) === name) 97 | return i; 98 | } 99 | }; 100 | 101 | ED.Print = function(ed) 102 | { 103 | if (ed.free === true) 104 | { 105 | Con.Print('FREE\n'); 106 | return; 107 | } 108 | Con.Print('\nEDICT ' + ed.num + ':\n'); 109 | var i, d, name, v, l; 110 | for (i = 1; i < PR.fielddefs.length; ++i) 111 | { 112 | d = PR.fielddefs[i]; 113 | name = PR.GetString(d.name); 114 | if (name.charCodeAt(name.length - 2) === 95) 115 | continue; 116 | v = d.ofs; 117 | if (ed.v_int[v] === 0) 118 | { 119 | if ((d.type & 0x7fff) === 3) 120 | { 121 | if ((ed.v_int[v + 1] === 0) && (ed.v_int[v + 2] === 0)) 122 | continue; 123 | } 124 | else 125 | continue; 126 | } 127 | for (; name.length <= 14; ) 128 | name += ' '; 129 | Con.Print(name + PR.ValueString(d.type, ed.v, v) + '\n'); 130 | } 131 | }; 132 | 133 | ED.PrintEdicts = function() 134 | { 135 | if (SV.server.active !== true) 136 | return; 137 | Con.Print(SV.server.num_edicts + ' entities\n'); 138 | var i; 139 | for (i = 0; i < SV.server.num_edicts; ++i) 140 | ED.Print(SV.server.edicts[i]); 141 | }; 142 | 143 | ED.PrintEdict_f = function() 144 | { 145 | if (SV.server.active !== true) 146 | return; 147 | var i = Q.atoi(Cmd.argv[1]); 148 | if ((i >= 0) && (i < SV.server.num_edicts)) 149 | ED.Print(SV.server.edicts[i]); 150 | }; 151 | 152 | ED.Count = function() 153 | { 154 | if (SV.server.active !== true) 155 | return; 156 | var i, ent, active = 0, models = 0, solid = 0, step = 0; 157 | for (i = 0; i < SV.server.num_edicts; ++i) 158 | { 159 | ent = SV.server.edicts[i]; 160 | if (ent.free === true) 161 | continue; 162 | ++active; 163 | if (ent.v_float[PR.entvars.solid] !== 0.0) 164 | ++solid; 165 | if (ent.v_int[PR.entvars.model] !== 0) 166 | ++models; 167 | if (ent.v_float[PR.entvars.movetype] === SV.movetype.step) 168 | ++step; 169 | } 170 | var num_edicts = SV.server.num_edicts; 171 | Con.Print('num_edicts:' + (num_edicts <= 9 ? ' ' : (num_edicts <= 99 ? ' ' : '')) + num_edicts + '\n'); 172 | Con.Print('active :' + (active <= 9 ? ' ' : (active <= 99 ? ' ' : '')) + active + '\n'); 173 | Con.Print('view :' + (models <= 9 ? ' ' : (models <= 99 ? ' ' : '')) + models + '\n'); 174 | Con.Print('touch :' + (solid <= 9 ? ' ' : (solid <= 99 ? ' ' : '')) + solid + '\n'); 175 | Con.Print('step :' + (step <= 9 ? ' ' : (step <= 99 ? ' ' : '')) + step + '\n'); 176 | }; 177 | 178 | ED.ParseGlobals = function(data) 179 | { 180 | var keyname, key; 181 | for (;;) 182 | { 183 | data = COM.Parse(data); 184 | if (COM.token.charCodeAt(0) === 125) 185 | return; 186 | if (data == null) 187 | Sys.Error('ED.ParseGlobals: EOF without closing brace'); 188 | keyname = COM.token; 189 | data = COM.Parse(data); 190 | if (data == null) 191 | Sys.Error('ED.ParseGlobals: EOF without closing brace'); 192 | if (COM.token.charCodeAt(0) === 125) 193 | Sys.Error('ED.ParseGlobals: closing brace without data'); 194 | key = ED.FindGlobal(keyname); 195 | if (key == null) 196 | { 197 | Con.Print('\'' + keyname + '\' is not a global\n'); 198 | continue; 199 | } 200 | if (ED.ParseEpair(PR.globals, key, COM.token) !== true) 201 | Host.Error('ED.ParseGlobals: parse error'); 202 | } 203 | }; 204 | 205 | ED.NewString = function(string) 206 | { 207 | var newstring = [], i, c; 208 | for (i = 0; i < string.length; ++i) 209 | { 210 | c = string.charCodeAt(i); 211 | if ((c === 92) && (i < (string.length - 1))) 212 | { 213 | ++i; 214 | newstring[newstring.length] = (string.charCodeAt(i) === 110) ? '\n' : '\\'; 215 | } 216 | else 217 | newstring[newstring.length] = String.fromCharCode(c); 218 | } 219 | return PR.NewString(newstring.join(''), string.length + 1); 220 | }; 221 | 222 | ED.ParseEpair = function(base, key, s) 223 | { 224 | var d_float = new Float32Array(base); 225 | var d_int = new Int32Array(base); 226 | var d, v; 227 | switch (key.type & 0x7fff) 228 | { 229 | case PR.etype.ev_string: 230 | d_int[key.ofs] = ED.NewString(s); 231 | return true; 232 | case PR.etype.ev_float: 233 | d_float[key.ofs] = Q.atof(s); 234 | return true; 235 | case PR.etype.ev_vector: 236 | v = s.split(' '); 237 | d_float[key.ofs] = Q.atof(v[0]); 238 | d_float[key.ofs + 1] = Q.atof(v[1]); 239 | d_float[key.ofs + 2] = Q.atof(v[2]); 240 | return true; 241 | case PR.etype.ev_entity: 242 | d_int[key.ofs] = Q.atoi(s); 243 | return true; 244 | case PR.etype.ev_field: 245 | d = ED.FindField(s); 246 | if (d == null) 247 | { 248 | Con.Print('Can\'t find field ' + s + '\n'); 249 | return; 250 | } 251 | d_int[key.ofs] = d.ofs; 252 | return true; 253 | case PR.etype.ev_function: 254 | d = ED.FindFunction(s); 255 | if (d == null) 256 | { 257 | Con.Print('Can\'t find function ' + s + '\n'); 258 | return; 259 | } 260 | d_int[key.ofs] = d; 261 | } 262 | return true; 263 | }; 264 | 265 | ED.ParseEdict = function(data, ent) 266 | { 267 | var i, init, anglehack, keyname, n, key; 268 | if (ent !== SV.server.edicts[0]) 269 | { 270 | for (i = 0; i < PR.entityfields; ++i) 271 | ent.v_int[i] = 0; 272 | } 273 | for (;;) 274 | { 275 | data = COM.Parse(data); 276 | if (COM.token.charCodeAt(0) === 125) 277 | break; 278 | if (data == null) 279 | Sys.Error('ED.ParseEdict: EOF without closing brace'); 280 | if (COM.token === 'angle') 281 | { 282 | COM.token = 'angles'; 283 | anglehack = true; 284 | } 285 | else 286 | { 287 | anglehack = false; 288 | if (COM.token === 'light') 289 | COM.token = 'light_lev'; 290 | } 291 | for (n = COM.token.length; n > 0; --n) 292 | { 293 | if (COM.token.charCodeAt(n - 1) !== 32) 294 | break; 295 | } 296 | keyname = COM.token.substring(0, n); 297 | data = COM.Parse(data); 298 | if (data == null) 299 | Sys.Error('ED.ParseEdict: EOF without closing brace'); 300 | if (COM.token.charCodeAt(0) === 125) 301 | Sys.Error('ED.ParseEdict: closing brace without data'); 302 | init = true; 303 | if (keyname.charCodeAt(0) === 95) 304 | continue; 305 | key = ED.FindField(keyname); 306 | if (key == null) 307 | { 308 | Con.Print('\'' + keyname + '\' is not a field\n'); 309 | continue; 310 | } 311 | if (anglehack == true) 312 | COM.token = '0 ' + COM.token + ' 0'; 313 | if (ED.ParseEpair(ent.v, key, COM.token) !== true) 314 | Host.Error('ED.ParseEdict: parse error'); 315 | } 316 | if (init !== true) 317 | ent.free = true; 318 | return data; 319 | }; 320 | 321 | ED.LoadFromFile = function(data) 322 | { 323 | var ent, spawnflags, inhibit = 0, func; 324 | PR.globals_float[PR.globalvars.time] = SV.server.time; 325 | 326 | for (;;) 327 | { 328 | data = COM.Parse(data); 329 | if (data == null) 330 | break; 331 | if (COM.token.charCodeAt(0) !== 123) 332 | Sys.Error('ED.LoadFromFile: found ' + COM.token + ' when expecting {'); 333 | 334 | if (ent == null) 335 | ent = SV.server.edicts[0]; 336 | else 337 | ent = ED.Alloc(); 338 | data = ED.ParseEdict(data, ent); 339 | 340 | spawnflags = ent.v_float[PR.entvars.spawnflags] >> 0; 341 | if (Host.deathmatch.value !== 0) 342 | { 343 | if ((spawnflags & 2048) !== 0) 344 | { 345 | ED.Free(ent); 346 | ++inhibit; 347 | continue; 348 | } 349 | } 350 | else if (((Host.current_skill === 0) && ((spawnflags & 256) !== 0)) 351 | || ((Host.current_skill === 1) && ((spawnflags & 512) !== 0)) 352 | || ((Host.current_skill >= 2) && ((spawnflags & 1024) !== 0))) 353 | { 354 | ED.Free(ent); 355 | ++inhibit; 356 | continue; 357 | } 358 | 359 | if (ent.v_int[PR.entvars.classname] === 0) 360 | { 361 | Con.Print('No classname for:\n'); 362 | ED.Print(ent); 363 | ED.Free(ent); 364 | continue; 365 | } 366 | 367 | func = ED.FindFunction(PR.GetString(ent.v_int[PR.entvars.classname])); 368 | if (func == null) 369 | { 370 | Con.Print('No spawn function for:\n'); 371 | ED.Print(ent); 372 | ED.Free(ent); 373 | continue; 374 | } 375 | 376 | PR.globals_int[PR.globalvars.self] = ent.num; 377 | PR.ExecuteProgram(func); 378 | } 379 | 380 | Con.DPrint(inhibit + ' entities inhibited\n'); 381 | }; 382 | 383 | ED.Vector = function(e, o) 384 | { 385 | return [e.v_float[o], e.v_float[o + 1], e.v_float[o + 2]]; 386 | }; 387 | 388 | ED.SetVector = function(e, o, v) 389 | { 390 | e.v_float[o] = v[0]; 391 | e.v_float[o + 1] = v[1]; 392 | e.v_float[o + 2] = v[2]; 393 | }; -------------------------------------------------------------------------------- /server/js/NET_Datagram.js: -------------------------------------------------------------------------------- 1 | Datagram = {}; 2 | 3 | Datagram.sockets = []; 4 | Datagram.acceptsockets = []; 5 | 6 | Datagram.Init = function() 7 | { 8 | if (COM.CheckParm('-noudp') != null) 9 | return; 10 | 11 | var i, newsocket; 12 | for (i = 0; i < SV.svs.maxclientslimit; ++i) 13 | { 14 | newsocket = Node.dgram.createSocket('udp4'); 15 | Datagram.sockets[i] = newsocket; 16 | newsocket.bind(); 17 | newsocket.on('listening', Datagram.DgramOnListening); 18 | newsocket.on('message', Datagram.DgramOnMessage); 19 | } 20 | 21 | var local = Node.os.networkInterfaces(), j, k, addr; 22 | for (i in local) 23 | { 24 | j = local[i]; 25 | for (k = 0; k < j.length; ++k) 26 | { 27 | addr = j[k]; 28 | if ((addr.family !== 'IPv4') || (addr.internal === true)) 29 | continue; 30 | Datagram.myAddr = addr.address; 31 | break; 32 | } 33 | if (Datagram.myAddr != null) 34 | break; 35 | } 36 | if (Datagram.myAddr == null) 37 | Datagram.myAddr = '127.0.0.1'; 38 | 39 | return true; 40 | }; 41 | 42 | Datagram.Listen = function() 43 | { 44 | if (NET.listening !== true) 45 | { 46 | if (Datagram.controlsocket == null) 47 | return; 48 | Datagram.controlsocket.close(); 49 | Datagram.controlsocket = null; 50 | return; 51 | } 52 | var controlsocket = Node.dgram.createSocket('udp4'); 53 | try 54 | { 55 | controlsocket.bind(NET.hostport); 56 | } 57 | catch (e) 58 | { 59 | Con.Print('Unable to bind to ' + Datagram.myAddr + ':' + NET.hostport + '\n'); 60 | controlsocket.close(); 61 | return; 62 | } 63 | controlsocket.on('message', Datagram.ControlOnMessage); 64 | Datagram.controlsocket = controlsocket; 65 | }; 66 | 67 | Datagram.CheckNewConnections = function() 68 | { 69 | if (Datagram.acceptsockets.length === 0) 70 | return; 71 | var sock = NET.NewQSocket(); 72 | var address = Datagram.acceptsockets.shift(); 73 | var i, newsocket; 74 | for (i = 0; i < Datagram.sockets.length; ++i) 75 | { 76 | newsocket = Datagram.sockets[i]; 77 | if ((newsocket.data_port != null) && (newsocket.data_socket == null)) 78 | break; 79 | } 80 | if (i === Datagram.sockets.length) 81 | return; 82 | newsocket.data_socket = sock; 83 | sock.lastSendTime = NET.time; 84 | sock.canSend = true; 85 | sock.driverdata = newsocket; 86 | sock.ackSequence = 0; 87 | sock.sendSequence = 0; 88 | sock.unreliableSendSequence = 0; 89 | sock.sendMessageLength = 0; 90 | sock.sendMessage = new Buffer(8192); 91 | sock.receiveSequence = 0; 92 | sock.unreliableReceiveSequence = 0; 93 | sock.receiveMessageLength = 0; 94 | sock.receiveMessage = new Buffer(8192); 95 | sock.addr = address; 96 | sock.address = address[0] + ':' + address[1]; 97 | sock.messages = []; 98 | var buf = new Buffer(1032); 99 | buf.writeUInt32LE(0x09000080, 0); 100 | buf[4] = 0x81; 101 | buf.writeUInt32LE(newsocket.data_port, 5); 102 | Datagram.controlsocket.send(buf, 0, 9, address[1], address[0]); 103 | return sock; 104 | }; 105 | 106 | Datagram.GetMessage = function(sock) 107 | { 108 | if (sock.driverdata == null) 109 | return -1; 110 | if ((sock.canSend !== true) && ((NET.time - sock.lastSendTime) > 1.0)) 111 | Datagram.SendMessageNext(sock, true); 112 | var message, length, flags, ret = 0, sequence, i; 113 | for (; sock.messages.length > 0; ) 114 | { 115 | message = sock.messages.shift(); 116 | length = (message[2] << 8) + message[3] - 8; 117 | flags = message[1]; 118 | sequence = message.readUInt32BE(4); 119 | if ((flags & 16) !== 0) 120 | { 121 | if (sequence < sock.unreliableReceiveSequence) 122 | { 123 | Con.DPrint('Got a stale datagram\n'); 124 | ret = 0; 125 | break; 126 | } 127 | if (sequence !== sock.unreliableReceiveSequence) 128 | Con.DPrint('Dropped ' + (sequence - sock.unreliableReceiveSequence) + ' datagram(s)\n'); 129 | sock.unreliableReceiveSequence = sequence + 1; 130 | NET.message.cursize = length; 131 | for (i = 0; i < length; ++i) 132 | NET.message.data[i] = message[8 + i]; 133 | ret = 2; 134 | break; 135 | } 136 | if ((flags & 2) !== 0) 137 | { 138 | if (sequence !== (sock.sendSequence - 1)) 139 | { 140 | Con.DPrint('Stale ACK received\n'); 141 | continue; 142 | } 143 | if (sequence === sock.ackSequence) 144 | { 145 | if (++sock.ackSequence !== sock.sendSequence) 146 | Con.DPrint('ack sequencing error\n'); 147 | } 148 | else 149 | { 150 | Con.DPrint('Duplicate ACK received\n'); 151 | continue; 152 | } 153 | sock.sendMessageLength -= 1024; 154 | if (sock.sendMessageLength > 0) 155 | { 156 | sock.sendMessage.copy(sock.sendMessage, 0, 1024, 1024 + sock.sendMessageLength); 157 | sock.sendNext = true; 158 | continue; 159 | } 160 | sock.sendMessageLength = 0; 161 | sock.canSend = true; 162 | continue; 163 | } 164 | if ((flags & 1) !== 0) 165 | { 166 | sock.driverdata.send(new Buffer([0, 2, 0, 8, sequence >>> 24, (sequence & 0xff0000) >>> 16, (sequence & 0xff00) >>> 8, (sequence & 0xff) >>> 0]), 167 | 0, 8, sock.addr[1], sock.addr[0]); 168 | if (sequence !== sock.receiveSequence) 169 | continue; 170 | ++sock.receiveSequence; 171 | if ((flags & 8) === 0) 172 | { 173 | message.copy(sock.receiveMessage, sock.receiveMessageLength, 8, 8 + length); 174 | sock.receiveMessageLength += length; 175 | continue; 176 | } 177 | var data = new Uint8Array(NET.message.data); 178 | for (i = 0; i < sock.receiveMessageLength; ++i) 179 | data[i] = sock.receiveMessage[i]; 180 | for (i = 0; i < length; ++i) 181 | data[sock.receiveMessageLength + i] = message[8 + i]; 182 | NET.message.cursize = sock.receiveMessageLength + length; 183 | sock.receiveMessageLength = 0; 184 | ret = 1; 185 | break; 186 | } 187 | } 188 | if (sock.sendNext === true) 189 | Datagram.SendMessageNext(sock); 190 | return ret; 191 | }; 192 | 193 | Datagram.SendMessage = function(sock, data) 194 | { 195 | if (sock.driverdata == null) 196 | return -1; 197 | var i, src = new Uint8Array(data.data); 198 | for (i = 0; i < data.cursize; ++i) 199 | sock.sendMessage[i] = src[i]; 200 | sock.sendMessageLength = data.cursize; 201 | var buf = new Buffer(1032); 202 | buf[0] = 0; 203 | var dataLen; 204 | if (data.cursize <= 1024) 205 | { 206 | dataLen = data.cursize; 207 | buf[1] = 9; 208 | } 209 | else 210 | { 211 | dataLen = 1024; 212 | buf[1] = 1; 213 | } 214 | buf.writeUInt16BE(dataLen + 8, 2); 215 | buf.writeUInt32BE(sock.sendSequence++, 4); 216 | sock.sendMessage.copy(buf, 8, 0, dataLen); 217 | sock.canSend = false; 218 | sock.driverdata.send(buf, 0, dataLen + 8, sock.addr[1], sock.addr[0]); 219 | sock.lastSendTime = NET.time; 220 | return 1; 221 | }; 222 | 223 | Datagram.SendMessageNext = function(sock, resend) 224 | { 225 | var buf = new Buffer(1032); 226 | buf[0] = 0; 227 | var dataLen; 228 | if (sock.sendMessageLength <= 1024) 229 | { 230 | dataLen = sock.sendMessageLength; 231 | buf[1] = 9; 232 | } 233 | else 234 | { 235 | dataLen = 1024; 236 | buf[1] = 1; 237 | } 238 | buf.writeUInt16BE(dataLen + 8, 2); 239 | if (resend !== true) 240 | buf.writeUInt32BE(sock.sendSequence++, 4); 241 | else 242 | buf.writeUInt32BE(sock.sendSequence - 1, 4); 243 | sock.sendMessage.copy(buf, 8, 0, dataLen); 244 | sock.sendNext = false; 245 | sock.driverdata.send(buf, 0, dataLen + 8, sock.addr[1], sock.addr[0]); 246 | sock.lastSendTime = NET.time; 247 | }; 248 | 249 | Datagram.SendUnreliableMessage = function(sock, data) 250 | { 251 | if (sock.driverdata == null) 252 | return -1; 253 | var buf = new Buffer(1032); 254 | buf.writeUInt32BE(data.cursize + 0x00100008, 0); 255 | buf.writeUInt32BE(sock.unreliableSendSequence++, 4); 256 | var i, src = new Uint8Array(data.data); 257 | for (i = 0; i < data.cursize; ++i) 258 | buf[8 + i] = src[i]; 259 | sock.driverdata.send(buf, 0, data.cursize + 8, sock.addr[1], sock.addr[0]); 260 | return 1; 261 | }; 262 | 263 | Datagram.CanSendMessage = function(sock) 264 | { 265 | if (sock.driverdata == null) 266 | return; 267 | if (sock.sendNext === true) 268 | Datagram.SendMessageNext(sock); 269 | return sock.canSend; 270 | }; 271 | 272 | Datagram.Close = function(sock) 273 | { 274 | if (sock.driverdata == null) 275 | return; 276 | sock.driverdata.data_socket = null; 277 | sock.driverdata = null; 278 | }; 279 | 280 | Datagram.ControlOnMessage = function(msg, rinfo) 281 | { 282 | if (SV.server.active !== true) 283 | return; 284 | if (rinfo.size < 4) 285 | return; 286 | if ((msg[0] !== 0x80) || (msg[1] !== 0)) 287 | return; 288 | if (((msg[2] << 8) + msg[3]) !== rinfo.size) 289 | return; 290 | var command = msg[4]; 291 | var buf = new Buffer(1032), str, cursize; 292 | buf[0] = 0x80; 293 | buf[1] = 0; 294 | 295 | if (command === 2) 296 | { 297 | if (msg.toString('ascii', 5, 11) !== 'QUAKE\0') 298 | return; 299 | buf[4] = 0x83; 300 | str = Datagram.myAddr + ':' + NET.hostport; 301 | buf.write(str, 5, str.length, 'ascii'); 302 | cursize = str.length + 5; 303 | buf[cursize++] = 0; 304 | str = NET.hostname.string.substring(0, 15); 305 | buf.write(str, cursize, str.length, 'ascii'); 306 | cursize += str.length; 307 | buf[cursize++] = 0; 308 | str = PR.GetString(PR.globals_int[PR.globalvars.mapname]); 309 | buf.write(str, cursize, str.length, 'ascii'); 310 | cursize += str.length; 311 | buf[cursize++] = 0; 312 | buf[cursize++] = NET.activeconnections; 313 | buf[cursize++] = SV.svs.maxclients; 314 | buf[cursize++] = 3; 315 | buf[2] = cursize >> 8; 316 | buf[3] = cursize & 255; 317 | Datagram.controlsocket.send(buf, 0, cursize, rinfo.port, rinfo.address); 318 | return; 319 | } 320 | 321 | var i; 322 | 323 | if (command === 3) 324 | { 325 | var playerNumber = msg[5]; 326 | if (playerNumber == null) 327 | return; 328 | var activeNumber = -1, client; 329 | for (i = 0; i < SV.svs.maxclients; ++i) 330 | { 331 | client = SV.svs.clients[i]; 332 | if (client.active !== true) 333 | continue; 334 | if (++activeNumber === playerNumber) 335 | break; 336 | } 337 | if (i === SV.svs.maxclients) 338 | return; 339 | buf[4] = 0x84; 340 | buf[5] = playerNumber; 341 | str = SV.GetClientName(client); 342 | buf.write(str, 6, str.length, 'ascii'); 343 | cursize = str.length + 6; 344 | buf[cursize++] = 0; 345 | buf.writeUInt32LE(client.colors, cursize); 346 | buf.writeInt32LE(client.edict.v_float[PR.entvars.frags] >> 0, cursize + 4); 347 | buf.writeInt32LE((Sys.FloatTime() - client.netconnection.connecttime) >> 0, cursize + 8); 348 | cursize += 12; 349 | str = client.netconnection.address; 350 | buf.write(str, cursize, str.length, 'ascii'); 351 | cursize += str.length; 352 | buf[cursize++] = 0; 353 | buf[2] = cursize >> 8; 354 | buf[3] = cursize & 255; 355 | Datagram.controlsocket.send(buf, 0, cursize, rinfo.port, rinfo.address); 356 | return; 357 | } 358 | 359 | if (command === 4) 360 | { 361 | var prevCvarName = msg.toString('ascii', 5).slice('\0')[0]; 362 | if (prevCvarName.length !== 0) 363 | { 364 | for (i = 0; i < Cvar.vars.length; ++i) 365 | { 366 | if (Cvar.vars[i].name === prevCvarName) 367 | break; 368 | } 369 | if (i === Cvar.vars.length) 370 | return; 371 | ++i; 372 | } 373 | else 374 | i = 0; 375 | var v; 376 | for (; i < Cvar.vars.length; ++i) 377 | { 378 | v = Cvar.vars[i]; 379 | if (v.server === true) 380 | break; 381 | } 382 | buf[4] = 0x85; 383 | if (i >= Cvar.vars.length) 384 | { 385 | buf[2] = 0; 386 | buf[3] = 5; 387 | Datagram.controlsocket.send(buf, 0, 5, rinfo.port, rinfo.address); 388 | return; 389 | } 390 | str = v.name; 391 | buf.write(str, 5, str.length, 'ascii'); 392 | cursize = str.length + 5; 393 | buf[cursize++] = 0; 394 | str = v.string; 395 | buf.write(str, cursize, str.length, 'ascii'); 396 | cursize += str.length; 397 | buf[cursize++] = 0; 398 | buf[2] = cursize >> 8; 399 | buf[3] = cursize & 255; 400 | Datagram.controlsocket.send(buf, 0, cursize, rinfo.port, rinfo.address); 401 | return; 402 | } 403 | 404 | if (command !== 1) 405 | return; 406 | if (msg.toString('ascii', 5, 11) !== 'QUAKE\0') 407 | return; 408 | 409 | if (msg[11] !== 3) 410 | { 411 | buf[2] = 0; 412 | buf[3] = 28; 413 | buf[4] = 0x82; 414 | buf.write('Incompatible version.\n\0', 5, 23); 415 | Datagram.controlsocket.send(buf, 0, 28, rinfo.port, rinfo.address); 416 | return; 417 | } 418 | var s; 419 | for (i = 0; i < NET.activeSockets.length; ++i) 420 | { 421 | s = NET.activeSockets[i]; 422 | if (s.disconnected === true) 423 | continue; 424 | if (NET.drivers[s.driver] !== Datagram) 425 | continue; 426 | if (rinfo.address !== s.addr[0]) 427 | continue; 428 | if ((rinfo.port !== s.addr[1]) || ((Sys.FloatTime() - s.connecttime) >= 2.0)) 429 | { 430 | NET.Close(s); 431 | return; 432 | } 433 | buf[2] = 0; 434 | buf[3] = 9; 435 | buf[4] = 0x81; 436 | buf.writeUInt32LE(s.driverdata.data_port, 5); 437 | Datagram.controlsocket.send(buf, 0, 9, rinfo.port, rinfo.address); 438 | return; 439 | } 440 | for (i = 0; i < Datagram.sockets.length; ++i) 441 | { 442 | s = Datagram.sockets[i]; 443 | if ((s.data_port != null) && (s.data_socket == null)) 444 | break; 445 | } 446 | if ((i === Datagram.sockets.length) || ((NET.activeconnections + Datagram.acceptsockets.length) >= SV.svs.maxclients)) 447 | { 448 | buf[2] = 0; 449 | buf[3] = 22; 450 | buf[4] = 0x82; 451 | buf.write('Server is full.\n\0', 5, 17); 452 | Datagram.controlsocket.send(buf, 0, 22, rinfo.port, rinfo.address); 453 | return; 454 | } 455 | Datagram.acceptsockets.push([rinfo.address, rinfo.port]); 456 | }; 457 | 458 | Datagram.DgramOnError = function(e) 459 | { 460 | this.data_port = null; 461 | if (this.data_socket != null) 462 | NET.Close(this.data_socket); 463 | }; 464 | 465 | Datagram.DgramOnListening = function() 466 | { 467 | this.data_port = this.address().port; 468 | }; 469 | 470 | Datagram.DgramOnMessage = function(msg, rinfo) 471 | { 472 | if (this.data_socket == null) 473 | return; 474 | var addr = this.data_socket.addr; 475 | if ((rinfo.address !== addr[0]) || (rinfo.port !== addr[1])) 476 | return; 477 | if (rinfo.size < 8) 478 | return; 479 | if ((msg[0] & 0x80) !== 0) 480 | return; 481 | this.data_socket.messages.push(msg); 482 | }; -------------------------------------------------------------------------------- /server/js/Mod.js: -------------------------------------------------------------------------------- 1 | Mod = {}; 2 | 3 | Mod.type = {brush: 0, sprite: 1, alias: 2}; 4 | 5 | Mod.version = {brush: 29, sprite: 1}; 6 | 7 | Mod.known = []; 8 | 9 | Mod.Init = function() 10 | { 11 | Mod.novis = []; 12 | var i; 13 | for (i = 0; i < 1024; ++i) 14 | Mod.novis[i] = 0xff; 15 | }; 16 | 17 | Mod.PointInLeaf = function(p, model) 18 | { 19 | if (model == null) 20 | Sys.Error('Mod.PointInLeaf: bad model'); 21 | if (model.nodes == null) 22 | Sys.Error('Mod.PointInLeaf: bad model'); 23 | var node = model.nodes[0]; 24 | var normal; 25 | for (;;) 26 | { 27 | if (node.contents < 0) 28 | return node; 29 | normal = node.plane.normal; 30 | if ((p[0] * normal[0] + p[1] * normal[1] + p[2] * normal[2] - node.plane.dist) > 0) 31 | node = node.children[0]; 32 | else 33 | node = node.children[1]; 34 | } 35 | }; 36 | 37 | Mod.DecompressVis = function(i, model) 38 | { 39 | var decompressed = [], c, out, row = (model.leafs.length + 7) >> 3; 40 | if (model.visdata == null) 41 | { 42 | for (; row >= 0; --row) 43 | decompressed[out++] = 0xff; 44 | return decompressed; 45 | } 46 | for (out = 0; out < row; ) 47 | { 48 | if (model.visdata[i] !== 0) 49 | { 50 | decompressed[out++] = model.visdata[i++]; 51 | continue; 52 | } 53 | for (c = model.visdata[i + 1]; c > 0; --c) 54 | decompressed[out++] = 0; 55 | i += 2; 56 | } 57 | return decompressed; 58 | }; 59 | 60 | Mod.LeafPVS = function(leaf, model) 61 | { 62 | if (leaf === model.leafs[0]) 63 | return Mod.novis; 64 | return Mod.DecompressVis(leaf.visofs, model); 65 | }; 66 | 67 | Mod.ClearAll = function() 68 | { 69 | var i, mod; 70 | for (i = 0; i < Mod.known.length; ++i) 71 | { 72 | mod = Mod.known[i]; 73 | if (mod.type !== Mod.type.brush) 74 | continue; 75 | if (mod.cmds != null) 76 | gl.deleteBuffer(mod.cmds); 77 | Mod.known[i] = { 78 | name: mod.name, 79 | needload: true 80 | }; 81 | } 82 | }; 83 | 84 | Mod.FindName = function(name) 85 | { 86 | if (name.length === 0) 87 | Sys.Error('Mod.FindName: NULL name'); 88 | var i; 89 | for (i = 0; i < Mod.known.length; ++i) 90 | { 91 | if (Mod.known[i] == null) 92 | continue; 93 | if (Mod.known[i].name === name) 94 | return Mod.known[i]; 95 | } 96 | for (i = 0; i <= Mod.known.length; ++i) 97 | { 98 | if (Mod.known[i] != null) 99 | continue; 100 | Mod.known[i] = {name: name, needload: true}; 101 | return Mod.known[i]; 102 | } 103 | }; 104 | 105 | Mod.ClearAll = function() 106 | { 107 | var i, mod; 108 | for (i = 0; i < Mod.known.length; ++i) 109 | { 110 | mod = Mod.known[i]; 111 | if (mod.type !== Mod.type.brush) 112 | continue; 113 | Mod.known[i] = { 114 | name: mod.name, 115 | needload: true 116 | }; 117 | } 118 | }; 119 | 120 | Mod.LoadModel = function(mod, crash) 121 | { 122 | if (mod.needload !== true) 123 | return mod; 124 | var buf = COM.LoadFile(mod.name); 125 | if (buf == null) 126 | { 127 | if (crash === true) 128 | Sys.Error('Mod.LoadModel: ' + mod.name + ' not found'); 129 | return; 130 | } 131 | Mod.loadmodel = mod; 132 | mod.needload = false; 133 | switch ((new DataView(buf)).getUint32(0, true)) 134 | { 135 | case 0x4f504449: 136 | Mod.loadmodel.type = Mod.type.alias; 137 | Mod.loadmodel.mins = [-16.0, -16.0, -16.0]; 138 | Mod.loadmodel.maxs = [16.0, 16.0, 16.0]; 139 | break; 140 | case 0x50534449: 141 | Mod.LoadSpriteModel(buf); 142 | break; 143 | default: 144 | Mod.LoadBrushModel(buf); 145 | } 146 | return mod; 147 | }; 148 | 149 | Mod.ForName = function(name, crash) 150 | { 151 | return Mod.LoadModel(Mod.FindName(name), crash); 152 | }; 153 | 154 | Mod.lump = 155 | { 156 | entities: 0, 157 | planes: 1, 158 | visibility: 4, 159 | nodes: 5, 160 | clipnodes: 9, 161 | leafs: 10, 162 | models: 14 163 | }; 164 | 165 | Mod.contents = { 166 | empty: -1, 167 | solid: -2, 168 | water: -3, 169 | slime: -4, 170 | lava: -5, 171 | sky: -6, 172 | origin: -7, 173 | clip: -8, 174 | current_0: -9, 175 | current_90: -10, 176 | current_180: -11, 177 | current_270: -12, 178 | current_up: -13, 179 | current_down: -14 180 | }; 181 | 182 | Mod.LoadVisibility = function(buf) 183 | { 184 | var view = new DataView(buf); 185 | var fileofs = view.getUint32((Mod.lump.visibility << 3) + 4, true); 186 | var filelen = view.getUint32((Mod.lump.visibility << 3) + 8, true); 187 | if (filelen === 0) 188 | return; 189 | Mod.loadmodel.visdata = new Uint8Array(new ArrayBuffer(filelen)); 190 | Mod.loadmodel.visdata.set(new Uint8Array(buf, fileofs, filelen)); 191 | }; 192 | 193 | Mod.LoadEntities = function(buf) 194 | { 195 | var view = new DataView(buf); 196 | var fileofs = view.getUint32((Mod.lump.entities << 3) + 4, true); 197 | var filelen = view.getUint32((Mod.lump.entities << 3) + 8, true); 198 | Mod.loadmodel.entities = Q.memstr(new Uint8Array(buf, fileofs, filelen)); 199 | }; 200 | 201 | Mod.LoadSubmodels = function(buf) 202 | { 203 | var view = new DataView(buf); 204 | var fileofs = view.getUint32((Mod.lump.models << 3) + 4, true); 205 | var filelen = view.getUint32((Mod.lump.models << 3) + 8, true); 206 | var count = filelen >> 6; 207 | if (count === 0) 208 | Sys.Error('Mod.LoadSubmodels: funny lump size in ' + Mod.loadmodel.name); 209 | Mod.loadmodel.submodels = []; 210 | 211 | Mod.loadmodel.mins = [view.getFloat32(fileofs, true) - 1.0, 212 | view.getFloat32(fileofs + 4, true) - 1.0, 213 | view.getFloat32(fileofs + 8, true) - 1.0]; 214 | Mod.loadmodel.maxs = [view.getFloat32(fileofs + 12, true) + 1.0, 215 | view.getFloat32(fileofs + 16, true) + 1.0, 216 | view.getFloat32(fileofs + 20, true) + 1.0]; 217 | Mod.loadmodel.hulls[0].firstclipnode = view.getUint32(fileofs + 36, true); 218 | Mod.loadmodel.hulls[1].firstclipnode = view.getUint32(fileofs + 40, true); 219 | Mod.loadmodel.hulls[2].firstclipnode = view.getUint32(fileofs + 44, true); 220 | fileofs += 64; 221 | 222 | var i, clipnodes = Mod.loadmodel.hulls[0].clipnodes, out; 223 | for (i = 1; i < count; ++i) 224 | { 225 | out = Mod.FindName('*' + i); 226 | out.needload = false; 227 | out.type = Mod.type.brush; 228 | out.mins = [view.getFloat32(fileofs, true) - 1.0, 229 | view.getFloat32(fileofs + 4, true) - 1.0, 230 | view.getFloat32(fileofs + 8, true) - 1.0]; 231 | out.maxs = [view.getFloat32(fileofs + 12, true) + 1.0, 232 | view.getFloat32(fileofs + 16, true) + 1.0, 233 | view.getFloat32(fileofs + 20, true) + 1.0]; 234 | out.origin = [view.getFloat32(fileofs + 24, true), view.getFloat32(fileofs + 28, true), view.getFloat32(fileofs + 32, true)]; 235 | out.hulls = [ 236 | { 237 | clipnodes: clipnodes, 238 | firstclipnode: view.getUint32(fileofs + 36, true), 239 | lastclipnode: Mod.loadmodel.nodes.length - 1, 240 | planes: Mod.loadmodel.planes, 241 | clip_mins: [0.0, 0.0, 0.0], 242 | clip_maxs: [0.0, 0.0, 0.0] 243 | }, 244 | { 245 | clipnodes: Mod.loadmodel.clipnodes, 246 | firstclipnode: view.getUint32(fileofs + 40, true), 247 | lastclipnode: Mod.loadmodel.clipnodes.length - 1, 248 | planes: Mod.loadmodel.planes, 249 | clip_mins: [-16.0, -16.0, -24.0], 250 | clip_maxs: [16.0, 16.0, 32.0] 251 | }, 252 | { 253 | clipnodes: Mod.loadmodel.clipnodes, 254 | firstclipnode: view.getUint32(fileofs + 44, true), 255 | lastclipnode: Mod.loadmodel.clipnodes.length - 1, 256 | planes: Mod.loadmodel.planes, 257 | clip_mins: [-32.0, -32.0, -24.0], 258 | clip_maxs: [32.0, 32.0, 64.0] 259 | } 260 | ]; 261 | Mod.loadmodel.submodels[i - 1] = out; 262 | fileofs += 64; 263 | } 264 | }; 265 | 266 | Mod.SetParent = function(node, parent) 267 | { 268 | node.parent = parent; 269 | if (node.contents < 0) 270 | return; 271 | Mod.SetParent(node.children[0], node); 272 | Mod.SetParent(node.children[1], node); 273 | }; 274 | 275 | Mod.LoadNodes = function(buf) 276 | { 277 | var view = new DataView(buf); 278 | var fileofs = view.getUint32((Mod.lump.nodes << 3) + 4, true); 279 | var filelen = view.getUint32((Mod.lump.nodes << 3) + 8, true); 280 | if ((filelen === 0) || ((filelen % 24) !== 0)) 281 | Sys.Error('Mod.LoadNodes: funny lump size in ' + Mod.loadmodel.name); 282 | var count = filelen / 24; 283 | Mod.loadmodel.nodes = []; 284 | var i, out; 285 | for (i = 0; i < count; ++i) 286 | { 287 | Mod.loadmodel.nodes[i] = { 288 | num: i, 289 | contents: 0, 290 | planenum: view.getUint32(fileofs, true), 291 | children: [view.getInt16(fileofs + 4, true), view.getInt16(fileofs + 6, true)], 292 | mins: [view.getInt16(fileofs + 8, true), view.getInt16(fileofs + 10, true), view.getInt16(fileofs + 12, true)], 293 | maxs: [view.getInt16(fileofs + 14, true), view.getInt16(fileofs + 16, true), view.getInt16(fileofs + 18, true)] 294 | }; 295 | fileofs += 24; 296 | } 297 | for (i = 0; i < count; ++i) 298 | { 299 | out = Mod.loadmodel.nodes[i]; 300 | out.plane = Mod.loadmodel.planes[out.planenum]; 301 | if (out.children[0] >= 0) 302 | out.children[0] = Mod.loadmodel.nodes[out.children[0]]; 303 | else 304 | out.children[0] = Mod.loadmodel.leafs[-1 - out.children[0]]; 305 | if (out.children[1] >= 0) 306 | out.children[1] = Mod.loadmodel.nodes[out.children[1]]; 307 | else 308 | out.children[1] = Mod.loadmodel.leafs[-1 - out.children[1]]; 309 | } 310 | Mod.SetParent(Mod.loadmodel.nodes[0]); 311 | }; 312 | 313 | Mod.LoadLeafs = function(buf) 314 | { 315 | var view = new DataView(buf); 316 | var fileofs = view.getUint32((Mod.lump.leafs << 3) + 4, true); 317 | var filelen = view.getUint32((Mod.lump.leafs << 3) + 8, true); 318 | if ((filelen % 28) !== 0) 319 | Sys.Error('Mod.LoadLeafs: funny lump size in ' + Mod.loadmodel.name); 320 | var count = filelen / 28; 321 | Mod.loadmodel.leafs = []; 322 | var i, j; 323 | for (i = 0; i < count; ++i) 324 | { 325 | Mod.loadmodel.leafs[i] = { 326 | num: i, 327 | contents: view.getInt32(fileofs, true), 328 | visofs: view.getInt32(fileofs + 4, true), 329 | mins: [view.getInt16(fileofs + 8, true), view.getInt16(fileofs + 10, true), view.getInt16(fileofs + 12, true)], 330 | maxs: [view.getInt16(fileofs + 14, true), view.getInt16(fileofs + 16, true), view.getInt16(fileofs + 18, true)] 331 | }; 332 | fileofs += 28; 333 | }; 334 | }; 335 | 336 | Mod.LoadClipnodes = function(buf) 337 | { 338 | var view = new DataView(buf); 339 | var fileofs = view.getUint32((Mod.lump.clipnodes << 3) + 4, true); 340 | var filelen = view.getUint32((Mod.lump.clipnodes << 3) + 8, true); 341 | var count = filelen >> 3; 342 | Mod.loadmodel.clipnodes = []; 343 | 344 | Mod.loadmodel.hulls = []; 345 | Mod.loadmodel.hulls[1] = { 346 | clipnodes: Mod.loadmodel.clipnodes, 347 | firstclipnode: 0, 348 | lastclipnode: count - 1, 349 | planes: Mod.loadmodel.planes, 350 | clip_mins: [-16.0, -16.0, -24.0], 351 | clip_maxs: [16.0, 16.0, 32.0] 352 | }; 353 | Mod.loadmodel.hulls[2] = { 354 | clipnodes: Mod.loadmodel.clipnodes, 355 | firstclipnode: 0, 356 | lastclipnode: count - 1, 357 | planes: Mod.loadmodel.planes, 358 | clip_mins: [-32.0, -32.0, -24.0], 359 | clip_maxs: [32.0, 32.0, 64.0] 360 | }; 361 | var i; 362 | for (i = 0; i < count; ++i) 363 | { 364 | Mod.loadmodel.clipnodes[i] = { 365 | planenum: view.getUint32(fileofs, true), 366 | children: [view.getInt16(fileofs + 4, true), view.getInt16(fileofs + 6, true)] 367 | }; 368 | fileofs += 8; 369 | } 370 | }; 371 | 372 | Mod.MakeHull0 = function() 373 | { 374 | var node, child, clipnodes = [], i, out; 375 | var hull = { 376 | clipnodes: clipnodes, 377 | lastclipnode: Mod.loadmodel.nodes.length - 1, 378 | planes: Mod.loadmodel.planes, 379 | clip_mins: [0.0, 0.0, 0.0], 380 | clip_maxs: [0.0, 0.0, 0.0] 381 | }; 382 | for (i = 0; i < Mod.loadmodel.nodes.length; ++i) 383 | { 384 | node = Mod.loadmodel.nodes[i]; 385 | out = {planenum: node.planenum, children: []}; 386 | child = node.children[0]; 387 | out.children[0] = child.contents < 0 ? child.contents : child.num; 388 | child = node.children[1]; 389 | out.children[1] = child.contents < 0 ? child.contents : child.num; 390 | clipnodes[i] = out; 391 | } 392 | Mod.loadmodel.hulls[0] = hull; 393 | }; 394 | 395 | Mod.LoadPlanes = function(buf) 396 | { 397 | var view = new DataView(buf); 398 | var fileofs = view.getUint32((Mod.lump.planes << 3) + 4, true); 399 | var filelen = view.getUint32((Mod.lump.planes << 3) + 8, true); 400 | if ((filelen % 20) !== 0) 401 | Sys.Error('Mod.LoadPlanes: funny lump size in ' + Mod.loadmodel.name); 402 | var count = filelen / 20; 403 | Mod.loadmodel.planes = []; 404 | var i, out; 405 | for (i = 0; i < count; ++i) 406 | { 407 | out = { 408 | normal: [view.getFloat32(fileofs, true), view.getFloat32(fileofs + 4, true), view.getFloat32(fileofs + 8, true)], 409 | dist: view.getFloat32(fileofs + 12, true), 410 | type: view.getUint32(fileofs + 16, true), 411 | signbits: 0 412 | }; 413 | if (out.normal[0] < 0) 414 | ++out.signbits; 415 | if (out.normal[1] < 0) 416 | out.signbits += 2; 417 | if (out.normal[2] < 0) 418 | out.signbits += 4; 419 | Mod.loadmodel.planes[i] = out; 420 | fileofs += 20; 421 | } 422 | }; 423 | 424 | Mod.LoadBrushModel = function(buffer) 425 | { 426 | Mod.loadmodel.type = Mod.type.brush; 427 | var version = (new DataView(buffer)).getUint32(0, true); 428 | if (version !== Mod.version.brush) 429 | Sys.Error('Mod.LoadBrushModel: ' + Mod.loadmodel.name + ' has wrong version number (' + version + ' should be ' + Mod.version.brush + ')'); 430 | Mod.LoadPlanes(buffer); 431 | Mod.LoadVisibility(buffer); 432 | Mod.LoadLeafs(buffer); 433 | Mod.LoadNodes(buffer); 434 | Mod.LoadClipnodes(buffer); 435 | Mod.MakeHull0(); 436 | Mod.LoadEntities(buffer); 437 | Mod.LoadSubmodels(buffer); 438 | }; 439 | 440 | Mod.LoadSpriteModel = function(buffer) 441 | { 442 | Mod.loadmodel.type = Mod.type.sprite; 443 | var model = new DataView(buffer); 444 | var version = model.getUint32(4, true); 445 | if (version !== Mod.version.sprite) 446 | Sys.Error(Mod.loadmodel.name + ' has wrong version number (' + version + ' should be ' + Mod.version.sprite + ')'); 447 | var width = model.getUint32(16, true) * 0.5; 448 | var height = model.getUint32(20, true); 449 | Mod.loadmodel.mins = [-width, -width, height * -0.5]; 450 | Mod.loadmodel.maxs = [width, width, height * 0.5]; 451 | } 452 | 453 | Mod.Print = function() 454 | { 455 | Con.Print('Cached models:\n'); 456 | var i; 457 | for (i = 0; i < Mod.known.length; ++i) 458 | Con.Print(Mod.known[i].name + '\n'); 459 | }; -------------------------------------------------------------------------------- /server/js/NET_WEBS.js: -------------------------------------------------------------------------------- 1 | WEBS = {}; 2 | 3 | WEBS.acceptsockets = []; 4 | WEBS.colors = []; 5 | 6 | WEBS.Init = function() 7 | { 8 | var palette = COM.LoadFile('gfx/palette.lmp'); 9 | if (palette == null) 10 | Sys.Error('Couldn\'t load gfx/palette.lmp'); 11 | var pal = new Uint8Array(palette), i, src = 24, c; 12 | for (i = 0; i <= 13; ++i) 13 | { 14 | WEBS.colors[i] = pal[src].toString() + ',' + pal[src + 1].toString() + ',' + pal[src + 2].toString(); 15 | src += 48; 16 | } 17 | 18 | WEBS.server = new Node.websocket.server; 19 | WEBS.server.on('request', WEBS.ServerOnRequest); 20 | 21 | return true; 22 | }; 23 | 24 | WEBS.Listen = function() 25 | { 26 | return 27 | if (NET.listening !== true) 28 | { 29 | WEBS.server.unmount(); 30 | if (WEBS.http == null) 31 | return; 32 | WEBS.http.close(); 33 | WEBS.http = null; 34 | return; 35 | } 36 | try 37 | { 38 | WEBS.http = Node.http.createServer(); 39 | WEBS.http.listen(NET.hostport); 40 | WEBS.http.on('request', WEBS.HTTPOnRequest); 41 | WEBS.server.mount({httpServer: WEBS.http, maxReceivedMessageSize: 8192}); 42 | } 43 | catch (e) 44 | { 45 | NET.listening = false; 46 | return; 47 | } 48 | }; 49 | 50 | WEBS.CheckNewConnections = function() 51 | { 52 | if (WEBS.acceptsockets.length === 0) 53 | return; 54 | var sock = NET.NewQSocket(); 55 | var connection = WEBS.acceptsockets.shift(); 56 | sock.driverdata = connection; 57 | sock.receiveMessage = []; 58 | sock.address = connection.socket.remoteAddress; 59 | connection.data_socket = sock; 60 | connection.on('message', WEBS.ConnectionOnMessage.bind(connection)); 61 | connection.on('close', WEBS.ConnectionOnClose.bind(connection)); 62 | return sock; 63 | }; 64 | 65 | WEBS.GetMessage = function(sock) 66 | { 67 | if (sock.driverdata == null) 68 | return -1; 69 | if (sock.driverdata.closeReasonCode !== -1) 70 | return -1; 71 | if (sock.receiveMessage.length === 0) 72 | return 0; 73 | var src = sock.receiveMessage.shift(), dest = new Uint8Array(NET.message.data); 74 | //console.log('getmessage',src) 75 | NET.message.cursize = src.length - 1; 76 | var i; 77 | for (i = 1; i < src.length; ++i) 78 | dest[i - 1] = src[i]; 79 | return src[0]; 80 | }; 81 | 82 | WEBS.SendMessage = function(sock, data) 83 | { 84 | if (sock.driverdata == null) 85 | return -1; 86 | if (sock.driverdata.closeReasonCode !== -1) 87 | return -1; 88 | var src = new Uint8Array(data.data), dest = new Buffer(data.cursize + 1), i; 89 | dest[0] = 1; 90 | var i; 91 | for (i = 0; i < data.cursize; ++i) 92 | dest[i + 1] = src[i]; 93 | sock.driverdata.sendBytes(dest); 94 | //console.log('sendmessage',data.data.byteLength,dest) 95 | return 1; 96 | }; 97 | 98 | WEBS.SendUnreliableMessage = function(sock, data) 99 | { 100 | if (sock.driverdata == null) 101 | return -1; 102 | if (sock.driverdata.closeReasonCode !== -1) 103 | return -1; 104 | var src = new Uint8Array(data.data), dest = new Buffer(data.cursize + 1), i; 105 | //console.log('sendunrelablemessage',data.data.byteLength) 106 | dest[0] = 2; 107 | var i; 108 | for (i = 0; i < data.cursize; ++i) 109 | dest[i + 1] = src[i]; 110 | sock.driverdata.sendBytes(dest); 111 | return 1; 112 | }; 113 | 114 | WEBS.CanSendMessage = function(sock) 115 | { 116 | if (sock.driverdata == null) 117 | return; 118 | if (sock.driverdata.closeReasonCode === -1) 119 | return true; 120 | }; 121 | 122 | WEBS.Close = function(sock) 123 | { 124 | if (sock.driverdata == null) 125 | return; 126 | if (sock.driverdata.closeReasonCode !== -1) 127 | return; 128 | sock.driverdata.drop(1000); 129 | sock.driverdata = null; 130 | }; 131 | 132 | WEBS.ConnectionOnMessage = function(message) 133 | { 134 | if (message.type !== 'binary') 135 | return; 136 | if (message.binaryData.length > 8000) 137 | return; 138 | var buf = new Buffer(message.binaryData) 139 | //console.log('receivemessage',buf) 140 | this.data_socket.receiveMessage.push(buf); 141 | }; 142 | 143 | WEBS.ConnectionOnClose = function() 144 | { 145 | NET.Close(this.data_socket); 146 | }; 147 | 148 | WEBS.HTMLSpecialChars = function(str) 149 | { 150 | var out = [], i, c; 151 | for (i = 0; i < str.length; ++i) 152 | { 153 | c = str.charCodeAt(i); 154 | switch (c) 155 | { 156 | case 38: out[out.length] = '&'; continue; 157 | case 60: out[out.length] = '<'; continue; 158 | case 62: out[out.length] = '>'; continue; 159 | } 160 | out[out.length] = String.fromCharCode(c); 161 | } 162 | return out.join(''); 163 | }; 164 | 165 | WEBS.HTTPOnRequest = function(request, response) 166 | { 167 | if (request.method === 'OPTIONS') 168 | { 169 | response.statusCode = 200; 170 | response.setHeader('Access-Control-Allow-Origin', '*'); 171 | response.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS'); 172 | response.setHeader('Access-Control-Allow-Headers', 'Authorization'); 173 | response.end(); 174 | return; 175 | } 176 | var head = request.method === 'HEAD'; 177 | if ((request.method !== 'GET') && (head !== true)) 178 | { 179 | response.statusCode = 501; 180 | response.end(); 181 | return; 182 | } 183 | var pathname = Node.url.parse(request.url).pathname.split('/'); 184 | var path = ''; 185 | if (pathname.length >= 2) 186 | path = pathname[1].toLowerCase(); 187 | var i, text; 188 | if (path.length === 0) 189 | { 190 | if (SV.server.active !== true) 191 | { 192 | response.statusCode = 503; 193 | response.end(); 194 | return; 195 | } 196 | response.statusCode = 200; 197 | response.setHeader('Content-Type', 'text/html; charset=UTF-8'); 198 | if (head === true) 199 | { 200 | response.end(); 201 | return; 202 | } 203 | var hostname = WEBS.HTMLSpecialChars(NET.hostname.string); 204 | response.write(''); 205 | response.write(hostname); 206 | response.write(''); 207 | if (Host.rcon_password.string.length !== 0) 208 | { 209 | response.write(''); 215 | } 216 | response.write('

'); 217 | response.write(hostname); 218 | response.write(' - '); 219 | response.write(WEBS.HTMLSpecialChars(PR.GetString(PR.globals_int[PR.globalvars.mapname]))); 220 | response.write(' ('); 221 | response.write(NET.activeconnections.toString()); 222 | response.write('/'); 223 | response.write(SV.svs.maxclients.toString()); 224 | response.write(')

'); 225 | var client, time = Sys.FloatTime(), seconds; 226 | for (i = 0; i < SV.svs.maxclients; ++i) 227 | { 228 | client = SV.svs.clients[i]; 229 | if (client.active !== true) 230 | continue; 231 | response.write(''); 252 | } 253 | response.write('
NameShirtPantsFragsTime
'); 232 | response.write(WEBS.HTMLSpecialChars(SV.GetClientName(client))) 233 | response.write(''); 236 | response.write((client.colors >> 4).toString()); 237 | response.write(''); 240 | response.write((client.colors & 15).toString()); 241 | response.write(''); 242 | response.write(client.edict.v_float[PR.entvars.frags].toFixed(0)); 243 | response.write(''); 244 | seconds = Math.floor(time - client.netconnection.connecttime); 245 | response.write(Math.floor(seconds / 60.0).toString()); 246 | response.write(':'); 247 | seconds = Math.floor(seconds % 60.0).toString(); 248 | if (seconds.length === 1) 249 | response.write('0'); 250 | response.write(seconds); 251 | response.write('
'); 254 | if (Host.rcon_password.string.length !== 0) 255 | response.write('

Rcon:

'); 256 | response.end(''); 257 | return; 258 | } 259 | if (path === 'server_info') 260 | { 261 | if (SV.server.active !== true) 262 | { 263 | response.statusCode = 503; 264 | response.end(); 265 | return; 266 | } 267 | response.statusCode = 200; 268 | response.setHeader('Content-Type', 'application/json; charset=UTF-8'); 269 | if (head === true) 270 | response.end(); 271 | else 272 | { 273 | response.end(JSON.stringify({ 274 | hostName: NET.hostname.string, 275 | levelName: PR.GetString(PR.globals_int[PR.globalvars.mapname]), 276 | currentPlayers: NET.activeconnections, 277 | maxPlayers: SV.svs.maxclients, 278 | protocolVersion: 2 279 | })); 280 | } 281 | return; 282 | } 283 | if (path === 'player_info') 284 | { 285 | if (SV.server.active !== true) 286 | { 287 | response.statusCode = 503; 288 | response.end(); 289 | return; 290 | } 291 | var client; 292 | if ((pathname.length <= 2) || (pathname[2] === '')) 293 | { 294 | response.statusCode = 200; 295 | response.setHeader('Content-Type', 'application/json; charset=UTF-8'); 296 | response.write('['); 297 | text = []; 298 | for (i = 0; i < SV.svs.maxclients; ++i) 299 | { 300 | client = SV.svs.clients[i]; 301 | if (client.active !== true) 302 | continue; 303 | text[text.length] = JSON.stringify({ 304 | name: SV.GetClientName(client), 305 | colors: client.colors, 306 | frags: (client.edict.v_float[PR.entvars.frags]) >> 0, 307 | connectTime: Sys.FloatTime() - client.netconnection.connecttime, 308 | address: client.netconnection.address 309 | }); 310 | } 311 | response.write(text.join(',')); 312 | response.end(']'); 313 | return; 314 | } 315 | var playerNumber = Q.atoi(pathname[2]); 316 | var activeNumber = -1; 317 | for (i = 0; i < SV.svs.maxclients; ++i) 318 | { 319 | client = SV.svs.clients[i]; 320 | if (client.active !== true) 321 | continue; 322 | if (++activeNumber === playerNumber) 323 | break; 324 | } 325 | if (i === SV.svs.maxclients) 326 | { 327 | response.statusCode = 404; 328 | response.end(); 329 | return; 330 | } 331 | response.statusCode = 200; 332 | response.setHeader('Content-Type', 'application/json; charset=UTF-8'); 333 | if (head === true) 334 | { 335 | response.end(); 336 | return; 337 | } 338 | response.end(JSON.stringify({ 339 | name: SV.GetClientName(client), 340 | colors: client.colors, 341 | frags: (client.edict.v_float[PR.entvars.frags]) >> 0, 342 | connectTime: Sys.FloatTime() - client.netconnection.connecttime, 343 | address: client.netconnection.address 344 | })); 345 | return; 346 | } 347 | if (path === 'rule_info') 348 | { 349 | var name, v; 350 | if (pathname.length >= 3) 351 | { 352 | name = pathname[2].toLowerCase(); 353 | if (name.length !== 0) 354 | { 355 | for (i = 0; i < Cvar.vars.length; ++i) 356 | { 357 | v = Cvar.vars[i]; 358 | if (v.server !== true) 359 | continue; 360 | if (v.name !== name) 361 | continue; 362 | response.statusCode = 200; 363 | response.setHeader('Content-Type', 'application/json; charset=UTF-8'); 364 | if (head === true) 365 | response.end(); 366 | else 367 | response.end(JSON.stringify({rule: v.name, value: v.string})); 368 | return; 369 | } 370 | response.statusCode = 404; 371 | response.end(); 372 | return; 373 | } 374 | } 375 | response.statusCode = 200; 376 | response.setHeader('Content-Type', 'application/json; charset=UTF-8'); 377 | if (head === true) 378 | { 379 | response.end(); 380 | return; 381 | } 382 | response.write('['); 383 | text = []; 384 | for (i = 0; i < Cvar.vars.length; ++i) 385 | { 386 | v = Cvar.vars[i]; 387 | if (v.server === true) 388 | text[text.length] = JSON.stringify({rule: v.name, value: v.string}); 389 | } 390 | response.write(text.join(',')); 391 | response.end(']'); 392 | return; 393 | } 394 | if (path === 'rcon') 395 | { 396 | var data; 397 | try 398 | { 399 | data = decodeURIComponent(pathname.slice(2).join('/')).split('\n')[0]; 400 | } 401 | catch (e) 402 | { 403 | response.statusCode = 400; 404 | response.end(); 405 | return; 406 | } 407 | if (data.length === 0) 408 | { 409 | response.statusCode = 400; 410 | response.end(); 411 | return; 412 | } 413 | if (request.headers.authorization == null) 414 | { 415 | response.statusCode = 401; 416 | response.setHeader('WWW-Authenticate', 'Basic realm="Quake"'); 417 | response.end(); 418 | return; 419 | } 420 | var password = request.headers.authorization; 421 | if (password.substring(0, 6) !== 'Basic ') 422 | { 423 | response.statusCode = 403; 424 | response.end(); 425 | return; 426 | } 427 | try 428 | { 429 | password = (new Buffer(password.substring(6), 'base64')).toString('ascii'); 430 | } 431 | catch (e) 432 | { 433 | response.statusCode = 403; 434 | response.end(); 435 | return; 436 | } 437 | if (password.substring(0, 6) !== 'quake:') 438 | { 439 | response.statusCode = 403; 440 | response.end(); 441 | return; 442 | } 443 | response.statusCode = (Host.RemoteCommand(request.connection.remoteAddress, data, password.substring(6)) === true) ? 200 : 403; 444 | response.end(); 445 | return; 446 | }; 447 | response.statusCode = 404; 448 | response.end(); 449 | }; 450 | 451 | WEBS.ServerOnRequest = function(request) 452 | { 453 | if (SV.server.active !== true) 454 | { 455 | request.reject(); 456 | return; 457 | } 458 | if (request.requestedProtocols[0] !== 'quake') 459 | { 460 | request.reject(); 461 | return; 462 | } 463 | if ((NET.activeconnections + WEBS.acceptsockets.length) >= SV.svs.maxclients) 464 | { 465 | request.reject(); 466 | return; 467 | } 468 | var i, s; 469 | for (i = 0; i < NET.activeSockets.length; ++i) 470 | { 471 | s = NET.activeSockets[i]; 472 | if (s.disconnected === true) 473 | continue; 474 | if (NET.drivers[s.driver] !== WEBS) 475 | continue; 476 | if (request.remoteAddress !== s.address) 477 | continue; 478 | NET.Close(s); 479 | break; 480 | } 481 | WEBS.acceptsockets.push(request.accept('quake', request.origin)); 482 | }; 483 | -------------------------------------------------------------------------------- /server/js/PF.js: -------------------------------------------------------------------------------- 1 | PF = {}; 2 | 3 | PF.VarString = function(first) 4 | { 5 | var i, out = ''; 6 | for (i = first; i < PR.argc; ++i) 7 | out += PR.GetString(PR.globals_int[4 + i * 3]); 8 | return out; 9 | }; 10 | 11 | PF.error = function() 12 | { 13 | Con.Print('======SERVER ERROR in ' + PR.GetString(PR.xfunction.name) + '\n' + PF.VarString(0) + '\n'); 14 | ED.Print(SV.server.edicts[PR.globals_int[PR.globalvars.self]]); 15 | Host.Error('Program error'); 16 | }; 17 | 18 | PF.objerror = function() 19 | { 20 | Con.Print('======OBJECT ERROR in ' + PR.GetString(PR.xfunction.name) + '\n' + PF.VarString(0) + '\n'); 21 | ED.Print(SV.server.edicts[PR.globals_int[PR.globalvars.self]]); 22 | Host.Error('Program error'); 23 | }; 24 | 25 | PF.makevectors = function() 26 | { 27 | var forward = [], right = [], up = []; 28 | Vec.AngleVectors([PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]], forward, right, up); 29 | var i; 30 | for (i = 0; i <= 2; ++i) 31 | { 32 | PR.globals_float[PR.globalvars.v_forward + i] = forward[i]; 33 | PR.globals_float[PR.globalvars.v_right + i] = right[i]; 34 | PR.globals_float[PR.globalvars.v_up + i] = up[i]; 35 | } 36 | }; 37 | 38 | PF.setorigin = function() 39 | { 40 | var e = SV.server.edicts[PR.globals_int[4]]; 41 | e.v_float[PR.entvars.origin] = PR.globals_float[7]; 42 | e.v_float[PR.entvars.origin1] = PR.globals_float[8]; 43 | e.v_float[PR.entvars.origin2] = PR.globals_float[9]; 44 | SV.LinkEdict(e); 45 | }; 46 | 47 | PF.SetMinMaxSize = function(e, min, max) 48 | { 49 | if ((min[0] > max[0]) || (min[1] > max[1]) || (min[2] > max[2])) 50 | PR.RunError('backwards mins/maxs'); 51 | ED.SetVector(e, PR.entvars.mins, min); 52 | ED.SetVector(e, PR.entvars.maxs, max); 53 | e.v_float[PR.entvars.size] = max[0] - min[0]; 54 | e.v_float[PR.entvars.size1] = max[1] - min[1]; 55 | e.v_float[PR.entvars.size2] = max[2] - min[2]; 56 | SV.LinkEdict(e); 57 | }; 58 | 59 | PF.setsize = function() 60 | { 61 | PF.SetMinMaxSize(SV.server.edicts[PR.globals_int[4]], 62 | [PR.globals_float[7], PR.globals_float[8], PR.globals_float[9]], 63 | [PR.globals_float[10], PR.globals_float[11], PR.globals_float[12]]); 64 | }; 65 | 66 | PF.setmodel = function() 67 | { 68 | var e = SV.server.edicts[PR.globals_int[4]]; 69 | var m = PR.GetString(PR.globals_int[7]); 70 | var i; 71 | for (i = 0; i < SV.server.model_precache.length; ++i) 72 | { 73 | if (SV.server.model_precache[i] === m) 74 | break; 75 | } 76 | if (i === SV.server.model_precache.length) 77 | PR.RunError('no precache: ' + m + '\n'); 78 | 79 | e.v_int[PR.entvars.model] = PR.globals_int[7]; 80 | e.v_float[PR.entvars.modelindex] = i; 81 | var mod = SV.server.models[i]; 82 | if (mod != null) 83 | PF.SetMinMaxSize(e, mod.mins, mod.maxs); 84 | else 85 | PF.SetMinMaxSize(e, Vec.origin, Vec.origin); 86 | }; 87 | 88 | PF.bprint = function() 89 | { 90 | Host.BroadcastPrint(PF.VarString(0)); 91 | }; 92 | 93 | PF.sprint = function() 94 | { 95 | var entnum = PR.globals_int[4]; 96 | if ((entnum <= 0) || (entnum > SV.svs.maxclients)) 97 | { 98 | Con.Print('tried to sprint to a non-client\n'); 99 | return; 100 | } 101 | var client = SV.svs.clients[entnum - 1]; 102 | MSG.WriteByte(client.message, Protocol.svc.print); 103 | MSG.WriteString(client.message, PF.VarString(1)); 104 | }; 105 | 106 | PF.centerprint = function() 107 | { 108 | var entnum = PR.globals_int[4]; 109 | if ((entnum <= 0) || (entnum > SV.svs.maxclients)) 110 | { 111 | Con.Print('tried to sprint to a non-client\n'); 112 | return; 113 | } 114 | var client = SV.svs.clients[entnum - 1]; 115 | MSG.WriteByte(client.message, Protocol.svc.centerprint); 116 | MSG.WriteString(client.message, PF.VarString(1)); 117 | }; 118 | 119 | PF.normalize = function() 120 | { 121 | var newvalue = [PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]]; 122 | Vec.Normalize(newvalue); 123 | PR.globals_float[1] = newvalue[0]; 124 | PR.globals_float[2] = newvalue[1]; 125 | PR.globals_float[3] = newvalue[2]; 126 | }; 127 | 128 | PF.vlen = function() 129 | { 130 | PR.globals_float[1] = Math.sqrt(PR.globals_float[4] * PR.globals_float[4] + PR.globals_float[5] * PR.globals_float[5] + PR.globals_float[6] * PR.globals_float[6]); 131 | }; 132 | 133 | PF.vectoyaw = function() 134 | { 135 | var value1 = PR.globals_float[4], value2 = PR.globals_float[5]; 136 | if ((value1 === 0.0) && (value2 === 0.0)) 137 | { 138 | PR.globals_float[1] = 0.0; 139 | return; 140 | } 141 | var yaw = (Math.atan2(value2, value1) * 180.0 / Math.PI) >> 0; 142 | if (yaw < 0) 143 | yaw += 360; 144 | PR.globals_float[1] = yaw; 145 | }; 146 | 147 | PF.vectoangles = function() 148 | { 149 | PR.globals_float[3] = 0.0; 150 | var value1 = [PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]]; 151 | if ((value1[0] === 0.0) && (value1[1] === 0.0)) 152 | { 153 | if (value1[2] > 0.0) 154 | PR.globals_float[1] = 90.0; 155 | else 156 | PR.globals_float[1] = 270.0; 157 | PR.globals_float[2] = 0.0; 158 | return; 159 | } 160 | 161 | var yaw = (Math.atan2(value1[1], value1[0]) * 180.0 / Math.PI) >> 0; 162 | if (yaw < 0) 163 | yaw += 360; 164 | var pitch = (Math.atan2(value1[2], Math.sqrt(value1[0] * value1[0] + value1[1] * value1[1])) * 180.0 / Math.PI) >> 0; 165 | if (pitch < 0) 166 | pitch += 360; 167 | PR.globals_float[1] = pitch; 168 | PR.globals_float[2] = yaw; 169 | }; 170 | 171 | PF.random = function() 172 | { 173 | PR.globals_float[1] = Math.random(); 174 | }; 175 | 176 | PF.particle = function() 177 | { 178 | SV.StartParticle([PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]], 179 | [PR.globals_float[7], PR.globals_float[8], PR.globals_float[9]], 180 | PR.globals_float[10] >> 0, PR.globals_float[13] >> 0); 181 | }; 182 | 183 | PF.ambientsound = function() 184 | { 185 | var samp = PR.GetString(PR.globals_int[7]), i; 186 | for (i = 0; i < SV.server.sound_precache.length; ++i) 187 | { 188 | if (SV.server.sound_precache[i] === samp) 189 | break; 190 | } 191 | if (i === SV.server.sound_precache.length) 192 | { 193 | Con.Print('no precache: ' + samp + '\n'); 194 | return; 195 | } 196 | var signon = SV.server.signon; 197 | MSG.WriteByte(signon, Protocol.svc.spawnstaticsound); 198 | MSG.WriteCoord(signon, PR.globals_float[4]); 199 | MSG.WriteCoord(signon, PR.globals_float[5]); 200 | MSG.WriteCoord(signon, PR.globals_float[6]); 201 | MSG.WriteByte(signon, i); 202 | MSG.WriteByte(signon, PR.globals_float[10] * 255.0); 203 | MSG.WriteByte(signon, PR.globals_float[13] * 64.0); 204 | }; 205 | 206 | PF.sound = function() 207 | { 208 | SV.StartSound(SV.server.edicts[PR.globals_int[4]], 209 | PR.globals_float[7] >> 0, 210 | PR.GetString(PR.globals_int[10]), 211 | (PR.globals_float[13] * 255.0) >> 0, 212 | PR.globals_float[16]); 213 | }; 214 | 215 | PF.breakstatement = function() 216 | { 217 | Con.Print('break statement\n'); 218 | }; 219 | 220 | PF.traceline = function() 221 | { 222 | var trace = SV.Move([PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]], 223 | Vec.origin, Vec.origin, [PR.globals_float[7], PR.globals_float[8], PR.globals_float[9]], 224 | PR.globals_float[10] >> 0, SV.server.edicts[PR.globals_int[13]]); 225 | PR.globals_float[PR.globalvars.trace_allsolid] = (trace.allsolid === true) ? 1.0 : 0.0; 226 | PR.globals_float[PR.globalvars.trace_startsolid] = (trace.startsolid === true) ? 1.0 : 0.0; 227 | PR.globals_float[PR.globalvars.trace_fraction] = trace.fraction; 228 | PR.globals_float[PR.globalvars.trace_inwater] = (trace.inwater === true) ? 1.0 : 0.0; 229 | PR.globals_float[PR.globalvars.trace_inopen] = (trace.inopen === true) ? 1.0 : 0.0; 230 | PR.globals_float[PR.globalvars.trace_endpos] = trace.endpos[0]; 231 | PR.globals_float[PR.globalvars.trace_endpos1] = trace.endpos[1]; 232 | PR.globals_float[PR.globalvars.trace_endpos2] = trace.endpos[2]; 233 | var plane = trace.plane; 234 | PR.globals_float[PR.globalvars.trace_plane_normal] = plane.normal[0]; 235 | PR.globals_float[PR.globalvars.trace_plane_normal1] = plane.normal[1]; 236 | PR.globals_float[PR.globalvars.trace_plane_normal2] = plane.normal[2]; 237 | PR.globals_float[PR.globalvars.trace_plane_dist] = plane.dist; 238 | PR.globals_int[PR.globalvars.trace_ent] = (trace.ent != null) ? trace.ent.num : 0; 239 | }; 240 | 241 | PF.newcheckclient = function(check) 242 | { 243 | if (check <= 0) 244 | check = 1; 245 | else if (check > SV.svs.maxclients) 246 | check = SV.svs.maxclients; 247 | var i = 1; 248 | if (check !== SV.svs.maxclients) 249 | i += check; 250 | var ent; 251 | for (; ; ++i) 252 | { 253 | if (i === SV.svs.maxclients + 1) 254 | i = 1; 255 | ent = SV.server.edicts[i]; 256 | if (i === check) 257 | break; 258 | if (ent.free === true) 259 | continue; 260 | if ((ent.v_float[PR.entvars.health] <= 0.0) || ((ent.v_float[PR.entvars.flags] & SV.fl.notarget) !== 0)) 261 | continue; 262 | break; 263 | } 264 | PF.checkpvs = Mod.LeafPVS(Mod.PointInLeaf([ 265 | ent.v_float[PR.entvars.origin] + ent.v_float[PR.entvars.view_ofs], 266 | ent.v_float[PR.entvars.origin1] + ent.v_float[PR.entvars.view_ofs1], 267 | ent.v_float[PR.entvars.origin2] + ent.v_float[PR.entvars.view_ofs2] 268 | ], SV.server.worldmodel), SV.server.worldmodel); 269 | return i; 270 | }; 271 | 272 | PF.checkclient = function() 273 | { 274 | if ((SV.server.time - SV.server.lastchecktime) >= 0.1) 275 | { 276 | SV.server.lastcheck = PF.newcheckclient(SV.server.lastcheck); 277 | SV.server.lastchecktime = SV.server.time; 278 | } 279 | var ent = SV.server.edicts[SV.server.lastcheck]; 280 | if ((ent.free === true) || (ent.v_float[PR.entvars.health] <= 0.0)) 281 | { 282 | PR.globals_int[1] = 0; 283 | return; 284 | } 285 | var self = SV.server.edicts[PR.globals_int[PR.globalvars.self]]; 286 | var l = Mod.PointInLeaf([ 287 | self.v_float[PR.entvars.origin] + self.v_float[PR.entvars.view_ofs], 288 | self.v_float[PR.entvars.origin1] + self.v_float[PR.entvars.view_ofs1], 289 | self.v_float[PR.entvars.origin2] + self.v_float[PR.entvars.view_ofs2] 290 | ], SV.server.worldmodel).num - 1; 291 | if ((l < 0) || ((PF.checkpvs[l >> 3] & (1 << (l & 7))) === 0)) 292 | { 293 | PR.globals_int[1] = 0; 294 | return; 295 | } 296 | PR.globals_int[1] = ent.num; 297 | }; 298 | 299 | PF.stuffcmd = function() 300 | { 301 | var entnum = PR.globals_int[4]; 302 | if ((entnum <= 0) || (entnum > SV.svs.maxclients)) 303 | PR.RunError('Parm 0 not a client'); 304 | var client = SV.svs.clients[entnum - 1]; 305 | MSG.WriteByte(client.message, Protocol.svc.stufftext); 306 | MSG.WriteString(client.message, PR.GetString(PR.globals_int[7])); 307 | }; 308 | 309 | PF.localcmd = function() 310 | { 311 | Cmd.text += PR.GetString(PR.globals_int[4]); 312 | }; 313 | 314 | PF.cvar = function() 315 | { 316 | var v = Cvar.FindVar(PR.GetString(PR.globals_int[4])); 317 | PR.globals_float[1] = v != null ? v.value : 0.0; 318 | }; 319 | 320 | PF.cvar_set = function() 321 | { 322 | Cvar.Set(PR.GetString(PR.globals_int[4]), PR.GetString(PR.globals_int[7])); 323 | }; 324 | 325 | PF.findradius = function() 326 | { 327 | var chain = 0; 328 | var org = [PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]], eorg = []; 329 | var rad = PR.globals_float[7]; 330 | var i, ent; 331 | for (i = 1; i < SV.server.num_edicts; ++i) 332 | { 333 | ent = SV.server.edicts[i]; 334 | if (ent.free === true) 335 | continue; 336 | if (ent.v_float[PR.entvars.solid] === SV.solid.not) 337 | continue; 338 | eorg[0] = org[0] - (ent.v_float[PR.entvars.origin] + (ent.v_float[PR.entvars.mins] + ent.v_float[PR.entvars.maxs]) * 0.5); 339 | eorg[1] = org[1] - (ent.v_float[PR.entvars.origin1] + (ent.v_float[PR.entvars.mins1] + ent.v_float[PR.entvars.maxs1]) * 0.5); 340 | eorg[2] = org[2] - (ent.v_float[PR.entvars.origin2] + (ent.v_float[PR.entvars.mins2] + ent.v_float[PR.entvars.maxs2]) * 0.5); 341 | if (Math.sqrt(eorg[0] * eorg[0] + eorg[1] * eorg[1] + eorg[2] * eorg[2]) > rad) 342 | continue; 343 | ent.v_int[PR.entvars.chain] = chain; 344 | chain = i; 345 | } 346 | PR.globals_int[1] = chain; 347 | }; 348 | 349 | PF.dprint = function() 350 | { 351 | Con.DPrint(PF.VarString(0)); 352 | }; 353 | 354 | PF.ftos = function() 355 | { 356 | var v = PR.globals_float[4]; 357 | if (v === Math.floor(v)) 358 | PR.TempString(v.toString()); 359 | else 360 | PR.TempString(v.toFixed(1)); 361 | PR.globals_int[1] = PR.string_temp; 362 | }; 363 | 364 | PF.fabs = function() 365 | { 366 | PR.globals_float[1] = Math.abs(PR.globals_float[4]); 367 | }; 368 | 369 | PF.vtos = function() 370 | { 371 | PR.TempString(PR.globals_float[4].toFixed(1) 372 | + ' ' + PR.globals_float[5].toFixed(1) 373 | + ' ' + PR.globals_float[6].toFixed(1)); 374 | PR.globals_int[1] = PR.string_temp; 375 | }; 376 | 377 | PF.Spawn = function() 378 | { 379 | PR.globals_int[1] = ED.Alloc().num; 380 | }; 381 | 382 | PF.Remove = function() 383 | { 384 | ED.Free(SV.server.edicts[PR.globals_int[4]]); 385 | }; 386 | 387 | PF.Find = function() 388 | { 389 | var e = PR.globals_int[4]; 390 | var f = PR.globals_int[7]; 391 | var s = PR.GetString(PR.globals_int[10]); 392 | var ed; 393 | for (++e; e < SV.server.num_edicts; ++e) 394 | { 395 | ed = SV.server.edicts[e]; 396 | if (ed.free === true) 397 | continue; 398 | if (PR.GetString(ed.v_int[f]) === s) 399 | { 400 | PR.globals_int[1] = ed.num; 401 | return; 402 | } 403 | } 404 | PR.globals_int[1] = 0; 405 | }; 406 | 407 | PF.MoveToGoal = function() 408 | { 409 | var ent = SV.server.edicts[PR.globals_int[PR.globalvars.self]]; 410 | if ((ent.v_float[PR.entvars.flags] & (SV.fl.onground + SV.fl.fly + SV.fl.swim)) === 0) 411 | { 412 | PR.globals_float[1] = 0.0; 413 | return; 414 | } 415 | var goal = SV.server.edicts[ent.v_int[PR.entvars.goalentity]]; 416 | var dist = PR.globals_float[4]; 417 | if ((ent.v_int[PR.entvars.enemy] !== 0) && (SV.CloseEnough(ent, goal, dist) === true)) 418 | return; 419 | if ((Math.random() >= 0.75) || (SV.StepDirection(ent, ent.v_float[PR.entvars.ideal_yaw], dist) !== true)) 420 | SV.NewChaseDir(ent, goal, dist); 421 | }; 422 | 423 | PF.precache_file = function() 424 | { 425 | PR.globals_int[1] = PR.globals_int[4]; 426 | }; 427 | 428 | PF.precache_sound = function() 429 | { 430 | var s = PR.GetString(PR.globals_int[4]); 431 | PR.globals_int[1] = PR.globals_int[4]; 432 | PR.CheckEmptyString(s); 433 | var i; 434 | for (i = 0; i < SV.server.sound_precache.length; ++i) 435 | { 436 | if (SV.server.sound_precache[i] === s) 437 | return; 438 | } 439 | SV.server.sound_precache[i] = s; 440 | }; 441 | 442 | PF.precache_model = function() 443 | { 444 | if (SV.server.loading !== true) 445 | PR.RunError('PF.Precache_*: Precache can only be done in spawn functions'); 446 | var s = PR.GetString(PR.globals_int[4]); 447 | PR.globals_int[1] = PR.globals_int[4]; 448 | PR.CheckEmptyString(s); 449 | var i; 450 | for (i = 0; i < SV.server.model_precache.length; ++i) 451 | { 452 | if (SV.server.model_precache[i] === s) 453 | return; 454 | } 455 | SV.server.model_precache[i] = s; 456 | SV.server.models[i] = Mod.ForName(s, true); 457 | }; 458 | 459 | PF.coredump = function() 460 | { 461 | ED.PrintEdicts(); 462 | }; 463 | 464 | PF.traceon = function() 465 | { 466 | PR.trace = true; 467 | }; 468 | 469 | PF.traceoff = function() 470 | { 471 | PR.trace = false; 472 | }; 473 | 474 | PF.eprint = function() 475 | { 476 | ED.Print(SV.server.edicts[PR.globals_float[4]]); 477 | }; 478 | 479 | PF.walkmove = function() 480 | { 481 | var ent = SV.server.edicts[PR.globals_int[PR.globalvars.self]]; 482 | if ((ent.v_float[PR.entvars.flags] & (SV.fl.onground + SV.fl.fly + SV.fl.swim)) === 0) 483 | { 484 | PR.globals_float[1] = 0.0; 485 | return; 486 | } 487 | var yaw = PR.globals_float[4] * Math.PI / 180.0; 488 | var dist = PR.globals_float[7]; 489 | var oldf = PR.xfunction; 490 | PR.globals_float[1] = SV.movestep(ent, [Math.cos(yaw) * dist, Math.sin(yaw) * dist], true); 491 | PR.xfunction = oldf; 492 | PR.globals_int[PR.globalvars.self] = ent.num; 493 | }; 494 | 495 | PF.droptofloor = function() 496 | { 497 | var ent = SV.server.edicts[PR.globals_int[PR.globalvars.self]]; 498 | var trace = SV.Move(ED.Vector(ent, PR.entvars.origin), 499 | ED.Vector(ent, PR.entvars.mins), ED.Vector(ent, PR.entvars.maxs), 500 | [ent.v_float[PR.entvars.origin], ent.v_float[PR.entvars.origin1], ent.v_float[PR.entvars.origin2] - 256.0], 0, ent); 501 | if ((trace.fraction === 1.0) || (trace.allsolid === true)) 502 | { 503 | PR.globals_float[1] = 0.0; 504 | return; 505 | } 506 | ED.SetVector(ent, PR.entvars.origin, trace.endpos); 507 | SV.LinkEdict(ent); 508 | ent.v_float[PR.entvars.flags] |= SV.fl.onground; 509 | ent.v_int[PR.entvars.groundentity] = trace.ent.num; 510 | PR.globals_float[1] = 1.0; 511 | }; 512 | 513 | PF.lightstyle = function() 514 | { 515 | var style = PR.globals_float[4] >> 0; 516 | var val = PR.GetString(PR.globals_int[7]); 517 | SV.server.lightstyles[style] = val; 518 | if (SV.server.loading === true) 519 | return; 520 | var i, client; 521 | for (i = 0; i < SV.svs.maxclients; ++i) 522 | { 523 | client = SV.svs.clients[i]; 524 | if ((client.active !== true) && (client.spawned !== true)) 525 | continue; 526 | MSG.WriteByte(client.message, Protocol.svc.lightstyle); 527 | MSG.WriteByte(client.message, style); 528 | MSG.WriteString(client.message, val); 529 | } 530 | }; 531 | 532 | PF.rint = function() 533 | { 534 | var f = PR.globals_float[4]; 535 | PR.globals_float[1] = (f >= 0.0 ? f + 0.5 : f - 0.5) >> 0; 536 | }; 537 | 538 | PF.floor = function() 539 | { 540 | PR.globals_float[1] = Math.floor(PR.globals_float[4]); 541 | }; 542 | 543 | PF.ceil = function() 544 | { 545 | PR.globals_float[1] = Math.ceil(PR.globals_float[4]); 546 | }; 547 | 548 | PF.checkbottom = function() 549 | { 550 | PR.globals_float[1] = SV.CheckBottom(SV.server.edicts[PR.globals_int[4]]); 551 | }; 552 | 553 | PF.pointcontents = function() 554 | { 555 | PR.globals_float[1] = SV.PointContents([PR.globals_float[4], PR.globals_float[5], PR.globals_float[6]]); 556 | }; 557 | 558 | PF.nextent = function() 559 | { 560 | var i; 561 | for (i = PR.globals_int[4] + 1; i < SV.server.num_edicts; ++i) 562 | { 563 | if (SV.server.edicts[i].free !== true) 564 | { 565 | PR.globals_int[1] = i; 566 | return; 567 | } 568 | } 569 | PR.globals_int[1] = 0; 570 | }; 571 | 572 | PF.aim = function() 573 | { 574 | var ent = SV.server.edicts[PR.globals_int[4]]; 575 | var start = [ent.v_float[PR.entvars.origin], ent.v_float[PR.entvars.origin1], ent.v_float[PR.entvars.origin2] + 20.0]; 576 | var dir = [PR.globals_float[PR.globalvars.v_forward], PR.globals_float[PR.globalvars.v_forward1], PR.globals_float[PR.globalvars.v_forward2]]; 577 | var end = [start[0] + 2048.0 * dir[0], start[1] + 2048.0 * dir[1], start[2] + 2048.0 * dir[2]]; 578 | var tr = SV.Move(start, Vec.origin, Vec.origin, end, 0, ent); 579 | if (tr.ent != null) 580 | { 581 | if ((tr.ent.v_float[PR.entvars.takedamage] === SV.damage.aim) && 582 | ((Host.teamplay.value === 0) || (ent.v_float[PR.entvars.team] <= 0) || 583 | (ent.v_float[PR.entvars.team] !== tr.ent.v_float[PR.entvars.team]))) 584 | { 585 | PR.globals_float[1] = dir[0]; 586 | PR.globals_float[2] = dir[1]; 587 | PR.globals_float[3] = dir[2]; 588 | return; 589 | } 590 | } 591 | var bestdir = [dir[0], dir[1], dir[2]]; 592 | var bestdist = SV.aim.value; 593 | var bestent, i, check, dist, end = []; 594 | for (i = 1; i < SV.server.num_edicts; ++i) 595 | { 596 | check = SV.server.edicts[i]; 597 | if (check.v_float[PR.entvars.takedamage] !== SV.damage.aim) 598 | continue; 599 | if (check === ent) 600 | continue; 601 | if ((Host.teamplay.value !== 0) && (ent.v_float[PR.entvars.team] > 0) && (ent.v_float[PR.entvars.team] === check.v_float[PR.entvars.team])) 602 | continue; 603 | end[0] = check.v_float[PR.entvars.origin] + 0.5 * (check.v_float[PR.entvars.mins] + check.v_float[PR.entvars.maxs]); 604 | end[1] = check.v_float[PR.entvars.origin1] + 0.5 * (check.v_float[PR.entvars.mins1] + check.v_float[PR.entvars.maxs1]); 605 | end[2] = check.v_float[PR.entvars.origin2] + 0.5 * (check.v_float[PR.entvars.mins2] + check.v_float[PR.entvars.maxs2]); 606 | dir[0] = end[0] - start[0]; 607 | dir[1] = end[1] - start[1]; 608 | dir[2] = end[2] - start[2]; 609 | Vec.Normalize(dir); 610 | dist = dir[0] * bestdir[0] + dir[1] * bestdir[1] + dir[2] * bestdir[2]; 611 | if (dist < bestdist) 612 | continue; 613 | tr = SV.Move(start, Vec.origin, Vec.origin, end, 0, ent); 614 | if (tr.ent === check) 615 | { 616 | bestdist = dist; 617 | bestent = check; 618 | } 619 | } 620 | if (bestent != null) 621 | { 622 | dir[0] = bestent.v_float[PR.entvars.origin] - ent.v_float[PR.entvars.origin]; 623 | dir[1] = bestent.v_float[PR.entvars.origin1] - ent.v_float[PR.entvars.origin1]; 624 | dir[2] = bestent.v_float[PR.entvars.origin2] - ent.v_float[PR.entvars.origin2]; 625 | dist = dir[0] * bestdir[0] + dir[1] * bestdir[1] + dir[2] * bestdir[2]; 626 | end[0] = bestdir[0] * dist; 627 | end[1] = bestdir[1] * dist; 628 | end[2] = dir[2]; 629 | Vec.Normalize(end); 630 | PR.globals_float[1] = end[0]; 631 | PR.globals_float[2] = end[1]; 632 | PR.globals_float[3] = end[2]; 633 | return; 634 | } 635 | PR.globals_float[1] = bestdir[0]; 636 | PR.globals_float[2] = bestdir[1]; 637 | PR.globals_float[3] = bestdir[2]; 638 | }; 639 | 640 | PF.changeyaw = function() 641 | { 642 | var ent = SV.server.edicts[PR.globals_int[PR.globalvars.self]]; 643 | var current = Vec.Anglemod(ent.v_float[PR.entvars.angles1]); 644 | var ideal = ent.v_float[PR.entvars.ideal_yaw]; 645 | if (current === ideal) 646 | return; 647 | var move = ideal - current; 648 | if (ideal > current) 649 | { 650 | if (move >= 180.0) 651 | move -= 360.0; 652 | } 653 | else if (move <= -180.0) 654 | move += 360.0; 655 | var speed = ent.v_float[PR.entvars.yaw_speed]; 656 | if (move > 0.0) 657 | { 658 | if (move > speed) 659 | move = speed; 660 | } 661 | else if (move < -speed) 662 | move = -speed; 663 | ent.v_float[PR.entvars.angles1] = Vec.Anglemod(current + move); 664 | }; 665 | 666 | PF.WriteDest = function() 667 | { 668 | switch (PR.globals_float[4] >> 0) 669 | { 670 | case 0: // broadcast 671 | return SV.server.datagram; 672 | case 1: // one 673 | var entnum = PR.globals_int[PR.globalvars.msg_entity]; 674 | if ((entnum <= 0) || (entnum > SV.svs.maxclients)) 675 | PR.RunError('WriteDest: not a client'); 676 | return SV.svs.clients[entnum - 1].message; 677 | case 2: // all 678 | return SV.server.reliable_datagram; 679 | case 3: // init 680 | return SV.server.signon; 681 | } 682 | PR.RunError('WriteDest: bad destination'); 683 | }; 684 | 685 | PF.WriteByte = function() {MSG.WriteByte(PF.WriteDest(), PR.globals_float[7]);}; 686 | PF.WriteChar = function() {MSG.WriteChar(PF.WriteDest(), PR.globals_float[7]);}; 687 | PF.WriteShort = function() {MSG.WriteShort(PF.WriteDest(), PR.globals_float[7]);}; 688 | PF.WriteLong = function() {MSG.WriteLong(PF.WriteDest(), PR.globals_float[7]);}; 689 | PF.WriteAngle = function() {MSG.WriteAngle(PF.WriteDest(), PR.globals_float[7]);}; 690 | PF.WriteCoord = function() {MSG.WriteCoord(PF.WriteDest(), PR.globals_float[7]);}; 691 | PF.WriteString = function() {MSG.WriteString(PF.WriteDest(), PR.GetString(PR.globals_int[7]));}; 692 | PF.WriteEntity = function() {MSG.WriteShort(PF.WriteDest(), PR.globals_int[7]);}; 693 | 694 | PF.makestatic = function() 695 | { 696 | var ent = SV.server.edicts[PR.globals_int[4]]; 697 | var message = SV.server.signon; 698 | MSG.WriteByte(message, Protocol.svc.spawnstatic); 699 | MSG.WriteByte(message, SV.ModelIndex(PR.GetString(ent.v_int[PR.entvars.model]))); 700 | MSG.WriteByte(message, ent.v_float[PR.entvars.frame]); 701 | MSG.WriteByte(message, ent.v_float[PR.entvars.colormap]); 702 | MSG.WriteByte(message, ent.v_float[PR.entvars.skin]); 703 | MSG.WriteCoord(message, ent.v_float[PR.entvars.origin]); 704 | MSG.WriteAngle(message, ent.v_float[PR.entvars.angles]); 705 | MSG.WriteCoord(message, ent.v_float[PR.entvars.origin1]); 706 | MSG.WriteAngle(message, ent.v_float[PR.entvars.angles1]); 707 | MSG.WriteCoord(message, ent.v_float[PR.entvars.origin2]); 708 | MSG.WriteAngle(message, ent.v_float[PR.entvars.angles2]); 709 | ED.Free(ent); 710 | }; 711 | 712 | PF.setspawnparms = function() 713 | { 714 | var i = PR.globals_int[4]; 715 | if ((i <= 0) || (i > SV.svs.maxclients)) 716 | PR.RunError('Entity is not a client'); 717 | var spawn_parms = SV.svs.clients[i - 1].spawn_parms; 718 | for (i = 0; i <= 15; ++i) 719 | PR.globals_float[PR.globalvars.parms + i] = spawn_parms[i]; 720 | }; 721 | 722 | PF.changelevel = function() 723 | { 724 | if (SV.svs.changelevel_issued === true) 725 | return; 726 | SV.svs.changelevel_issued = true; 727 | Cmd.text += 'changelevel ' + PR.GetString(PR.globals_int[4]) + '\n'; 728 | }; 729 | 730 | PF.Fixme = function() 731 | { 732 | PR.RunError('unimplemented builtin'); 733 | }; 734 | 735 | PF.builtin = [ 736 | PF.Fixme, 737 | PF.makevectors, 738 | PF.setorigin, 739 | PF.setmodel, 740 | PF.setsize, 741 | PF.Fixme, 742 | PF.breakstatement, 743 | PF.random, 744 | PF.sound, 745 | PF.normalize, 746 | PF.error, 747 | PF.objerror, 748 | PF.vlen, 749 | PF.vectoyaw, 750 | PF.Spawn, 751 | PF.Remove, 752 | PF.traceline, 753 | PF.checkclient, 754 | PF.Find, 755 | PF.precache_sound, 756 | PF.precache_model, 757 | PF.stuffcmd, 758 | PF.findradius, 759 | PF.bprint, 760 | PF.sprint, 761 | PF.dprint, 762 | PF.ftos, 763 | PF.vtos, 764 | PF.coredump, 765 | PF.traceon, 766 | PF.traceoff, 767 | PF.eprint, 768 | PF.walkmove, 769 | PF.Fixme, 770 | PF.droptofloor, 771 | PF.lightstyle, 772 | PF.rint, 773 | PF.floor, 774 | PF.ceil, 775 | PF.Fixme, 776 | PF.checkbottom, 777 | PF.pointcontents, 778 | PF.Fixme, 779 | PF.fabs, 780 | PF.aim, 781 | PF.cvar, 782 | PF.localcmd, 783 | PF.nextent, 784 | PF.particle, 785 | PF.changeyaw, 786 | PF.Fixme, 787 | PF.vectoangles, 788 | PF.WriteByte, 789 | PF.WriteChar, 790 | PF.WriteShort, 791 | PF.WriteLong, 792 | PF.WriteCoord, 793 | PF.WriteAngle, 794 | PF.WriteString, 795 | PF.WriteEntity, 796 | PF.Fixme, 797 | PF.Fixme, 798 | PF.Fixme, 799 | PF.Fixme, 800 | PF.Fixme, 801 | PF.Fixme, 802 | PF.Fixme, 803 | PF.MoveToGoal, 804 | PF.precache_file, 805 | PF.makestatic, 806 | PF.changelevel, 807 | PF.Fixme, 808 | PF.cvar_set, 809 | PF.centerprint, 810 | PF.ambientsound, 811 | PF.precache_model, 812 | PF.precache_sound, 813 | PF.precache_file, 814 | PF.setspawnparms 815 | ]; -------------------------------------------------------------------------------- /server/js/PR.js: -------------------------------------------------------------------------------- 1 | PR = {}; 2 | 3 | PR.etype = { 4 | ev_void: 0, 5 | ev_string: 1, 6 | ev_float: 2, 7 | ev_vector: 3, 8 | ev_entity: 4, 9 | ev_field: 5, 10 | ev_function: 6, 11 | ev_pointer: 7 12 | }; 13 | 14 | PR.op = { 15 | done: 0, 16 | mul_f: 1, mul_v: 2, mul_fv: 3, mul_vf: 4, 17 | div_f: 5, 18 | add_f: 6, add_v: 7, 19 | sub_f: 8, sub_v: 9, 20 | eq_f: 10, eq_v: 11, eq_s: 12, eq_e: 13, eq_fnc: 14, 21 | ne_f: 15, ne_v: 16, ne_s: 17, ne_e: 18, ne_fnc: 19, 22 | le: 20, ge: 21, lt: 22, gt: 23, 23 | load_f: 24, load_v: 25, load_s: 26, load_ent: 27, load_fld: 28, load_fnc: 29, 24 | address: 30, 25 | store_f: 31, store_v: 32, store_s: 33, store_ent: 34, store_fld: 35, store_fnc: 36, 26 | storep_f: 37, storep_v: 38, storep_s: 39, storep_ent: 40, storep_fld: 41, storep_fnc: 42, 27 | ret: 43, 28 | not_f: 44, not_v: 45, not_s: 46, not_ent: 47, not_fnc: 48, 29 | jnz: 49, jz: 50, 30 | call0: 51, call1: 52, call2: 53, call3: 54, call4: 55, call5: 56, call6: 57, call7: 58, call8: 59, 31 | state: 60, 32 | jump: 61, 33 | and: 62, or: 63, 34 | bitand: 64, bitor: 65 35 | }; 36 | 37 | PR.version = 6; 38 | 39 | PR.globalvars = { 40 | self: 28, // edict 41 | other: 29, // edict 42 | world: 30, // edict 43 | time: 31, // float 44 | frametime: 32, // float 45 | force_retouch: 33, // float 46 | mapname: 34, // string 47 | deathmatch: 35, // float 48 | coop: 36, // float 49 | teamplay: 37, // float 50 | serverflags: 38, // float 51 | total_secrets: 39, // float 52 | total_monsters: 40, // float 53 | found_secrets: 41, // float 54 | killed_monsters: 42, // float 55 | parms: 43, // float[16] 56 | v_forward: 59, // vec3 57 | v_forward1: 60, 58 | v_forward2: 61, 59 | v_up: 62, // vec3 60 | v_up1: 63, 61 | v_up2: 64, 62 | v_right: 65, // vec3, 63 | v_right1: 66, 64 | v_right2: 67, 65 | trace_allsolid: 68, // float 66 | trace_startsolid: 69, // float 67 | trace_fraction: 70, // float 68 | trace_endpos: 71, // vec3 69 | trace_endpos1: 72, 70 | trace_endpos2: 73, 71 | trace_plane_normal: 74, // vec3 72 | trace_plane_normal1: 75, 73 | trace_plane_normal2: 76, 74 | trace_plane_dist: 77, // float 75 | trace_ent: 78, // edict 76 | trace_inopen: 79, // float 77 | trace_inwater: 80, // float 78 | msg_entity: 81, // edict 79 | main: 82, // func 80 | StartFrame: 83, // func 81 | PlayerPreThink: 84, // func 82 | PlayerPostThink: 85, // func 83 | ClientKill: 86, // func 84 | ClientConnect: 87, // func 85 | PutClientInServer: 88, // func 86 | ClientDisconnect: 89, // func 87 | SetNewParms: 90, // func 88 | SetChangeParms: 91 // func 89 | }; 90 | 91 | PR.entvars = { 92 | modelindex: 0, // float 93 | absmin: 1, // vec3 94 | absmin1: 2, 95 | absmin2: 3, 96 | absmax: 4, // vec3 97 | absmax1: 5, 98 | absmax2: 6, 99 | ltime: 7, // float 100 | movetype: 8, // float 101 | solid: 9, // float 102 | origin: 10, // vec3 103 | origin1: 11, 104 | origin2: 12, 105 | oldorigin: 13, // vec3 106 | oldorigin1: 14, 107 | oldorigin2: 15, 108 | velocity: 16, // vec3 109 | velocity1: 17, 110 | velocity2: 18, 111 | angles: 19, // vec3 112 | angles1: 20, 113 | angles2: 21, 114 | avelocity: 22, // vec3 115 | avelocity1: 23, 116 | avelocity2: 24, 117 | punchangle: 25, // vec3 118 | punchangle1: 26, 119 | punchangle2: 27, 120 | classname: 28, // string 121 | model: 29, // string 122 | frame: 30, // float 123 | skin: 31, // float 124 | effects: 32, // float 125 | mins: 33, // vec3 126 | mins1: 34, 127 | mins2: 35, 128 | maxs: 36, // vec3 129 | maxs1: 37, 130 | maxs2: 38, 131 | size: 39, // vec3 132 | size1: 40, 133 | size2: 41, 134 | touch: 42, // func 135 | use: 43, // func 136 | think: 44, // func 137 | blocked: 45, // func 138 | nextthink: 46, // float 139 | groundentity: 47, // edict 140 | health: 48, // float 141 | frags: 49, // float 142 | weapon: 50, // float 143 | weaponmodel: 51, // string 144 | weaponframe: 52, // float 145 | currentammo: 53, // float 146 | ammo_shells: 54, // float 147 | ammo_nails: 55, // float 148 | ammo_rockets: 56, // float 149 | ammo_cells: 57, // float 150 | items: 58, // float 151 | takedamage: 59, // float 152 | chain: 60, // edict 153 | deadflag: 61, // float 154 | view_ofs: 62, // vec3 155 | view_ofs1: 63, 156 | view_ofs2: 64, 157 | button0: 65, // float 158 | button1: 66, // float 159 | button2: 67, // float 160 | impulse: 68, // float 161 | fixangle: 69, // float 162 | v_angle: 70, // vec3 163 | v_angle1: 71, 164 | v_angle2: 72, 165 | idealpitch: 73, // float 166 | netname: 74, // string 167 | enemy: 75, // edict 168 | flags: 76, // float 169 | colormap: 77, // float 170 | team: 78, // float 171 | max_health: 79, // float 172 | teleport_time: 80, // float 173 | armortype: 81, // float 174 | armorvalue: 82, // float 175 | waterlevel: 83, // float 176 | watertype: 84, // float 177 | ideal_yaw: 85, // float 178 | yaw_speed: 86, // float 179 | aiment: 87, // edict 180 | goalentity: 88, // edict 181 | spawnflags: 89, // float 182 | target: 90, // string 183 | targetname: 91, // string 184 | dmg_take: 92, // float 185 | dmg_save: 93, // float 186 | dmg_inflictor: 94, // edict 187 | owner: 95, // edict 188 | movedir: 96, // vec3 189 | movedir1: 97, 190 | movedir2: 98, 191 | message: 99, // string 192 | sounds: 100, // float 193 | noise: 101, // string 194 | noise1: 102, // string 195 | noise2: 103, // string 196 | noise3: 104 // string 197 | }; 198 | 199 | PR.progheader_crc = 5927; 200 | 201 | // cmds 202 | 203 | PR.CheckEmptyString = function(s) 204 | { 205 | var c = s.charCodeAt(0); 206 | if ((Number.isNaN(c) === true) || (c <= 32)) 207 | PR.RunError('Bad string'); 208 | }; 209 | 210 | // edict 211 | 212 | PR.ValueString = function(type, val, ofs) 213 | { 214 | var val_float = new Float32Array(val); 215 | var val_int = new Int32Array(val); 216 | type &= 0x7fff; 217 | switch (type) 218 | { 219 | case PR.etype.ev_string: 220 | return PR.GetString(val_int[ofs]); 221 | case PR.etype.ev_entity: 222 | return 'entity ' + val_int[ofs]; 223 | case PR.etype.ev_function: 224 | return PR.GetString(PR.functions[val_int[ofs]].name) + '()'; 225 | case PR.etype.ev_field: 226 | var def = ED.FieldAtOfs(val_int[ofs]); 227 | if (def != null) 228 | return '.' + PR.GetString(def.name); 229 | return '.'; 230 | case PR.etype.ev_void: 231 | return 'void'; 232 | case PR.etype.ev_float: 233 | return val_float[ofs].toFixed(1); 234 | case PR.etype.ev_vector: 235 | return '\'' + val_float[ofs].toFixed(1) + 236 | ' ' + val_float[ofs + 1].toFixed(1) + 237 | ' ' + val_float[ofs + 2].toFixed(1) + '\''; 238 | case PR.etype.ev_pointer: 239 | return 'pointer'; 240 | } 241 | return 'bad type ' + type; 242 | }; 243 | 244 | PR.UglyValueString = function(type, val, ofs) 245 | { 246 | var val_float = new Float32Array(val); 247 | var val_int = new Int32Array(val); 248 | type &= 0x7fff; 249 | switch (type) 250 | { 251 | case PR.etype.ev_string: 252 | return PR.GetString(val_int[ofs]); 253 | case PR.etype.ev_entity: 254 | return val_int[ofs].toString(); 255 | case PR.etype.ev_function: 256 | return PR.GetString(PR.functions[val_int[ofs]].name); 257 | case PR.etype.ev_field: 258 | var def = ED.FieldAtOfs(val_int[ofs]); 259 | if (def != null) 260 | return PR.GetString(def.name); 261 | return ''; 262 | case PR.etype.ev_void: 263 | return 'void'; 264 | case PR.etype.ev_float: 265 | return val_float[ofs].toFixed(6); 266 | case PR.etype.ev_vector: 267 | return val_float[ofs].toFixed(6) + 268 | ' ' + val_float[ofs + 1].toFixed(6) + 269 | ' ' + val_float[ofs + 2].toFixed(6); 270 | } 271 | return 'bad type ' + type; 272 | }; 273 | 274 | PR.GlobalString = function(ofs) 275 | { 276 | var def = ED.GlobalAtOfs(ofs), line; 277 | if (def != null) 278 | line = ofs + '(' + PR.GetString(def.name) + ')' + PR.ValueString(def.type, PR.globals, ofs); 279 | else 280 | line = ofs + '(???)'; 281 | for (; line.length <= 20; ) 282 | line += ' '; 283 | return line; 284 | }; 285 | 286 | PR.GlobalStringNoContents = function(ofs) 287 | { 288 | var def = ED.GlobalAtOfs(ofs), line; 289 | if (def != null) 290 | line = ofs + '(' + PR.GetString(def.name) + ')'; 291 | else 292 | line = ofs + '(???)'; 293 | for (; line.length <= 20; ) 294 | line += ' '; 295 | return line; 296 | }; 297 | 298 | PR.LoadProgs = function() 299 | { 300 | var progs = COM.LoadFile('progs.dat'); 301 | if (progs == null) 302 | Sys.Error('PR.LoadProgs: couldn\'t load progs.dat'); 303 | Con.DPrint('Programs occupy ' + (progs.byteLength >> 10) + 'K.\n'); 304 | var view = new DataView(progs); 305 | 306 | var i = view.getUint32(0, true); 307 | if (i !== PR.version) 308 | Sys.Error('progs.dat has wrong version number (' + i + ' should be ' + PR.version + ')'); 309 | if (view.getUint32(4, true) !== PR.progheader_crc) 310 | Sys.Error('progs.dat system vars have been modified, PR.js is out of date'); 311 | 312 | PR.crc = CRC.Block(new Uint8Array(progs)); 313 | 314 | PR.stack = []; 315 | PR.depth = 0; 316 | 317 | PR.localstack = []; 318 | for (i = 0; i < PR.localstack_size; ++i) 319 | PR.localstack[i] = 0; 320 | PR.localstack_used = 0; 321 | 322 | var ofs, num; 323 | 324 | ofs = view.getUint32(8, true); 325 | num = view.getUint32(12, true); 326 | PR.statements = []; 327 | for (i = 0; i < num; ++i) 328 | { 329 | PR.statements[i] = { 330 | op: view.getUint16(ofs, true), 331 | a: view.getInt16(ofs + 2, true), 332 | b: view.getInt16(ofs + 4, true), 333 | c: view.getInt16(ofs + 6, true) 334 | }; 335 | ofs += 8; 336 | } 337 | 338 | ofs = view.getUint32(16, true); 339 | num = view.getUint32(20, true); 340 | PR.globaldefs = []; 341 | for (i = 0; i < num; ++i) 342 | { 343 | PR.globaldefs[i] = { 344 | type: view.getUint16(ofs, true), 345 | ofs: view.getUint16(ofs + 2, true), 346 | name: view.getUint32(ofs + 4, true) 347 | }; 348 | ofs += 8; 349 | } 350 | 351 | ofs = view.getUint32(24, true); 352 | num = view.getUint32(28, true); 353 | PR.fielddefs = []; 354 | for (i = 0; i < num; ++i) 355 | { 356 | PR.fielddefs[i] = { 357 | type: view.getUint16(ofs, true), 358 | ofs: view.getUint16(ofs + 2, true), 359 | name: view.getUint32(ofs + 4, true) 360 | }; 361 | ofs += 8; 362 | } 363 | 364 | ofs = view.getUint32(32, true); 365 | num = view.getUint32(36, true); 366 | PR.functions = []; 367 | for (i = 0; i < num; ++i) 368 | { 369 | PR.functions[i] = { 370 | first_statement: view.getInt32(ofs, true), 371 | parm_start: view.getUint32(ofs + 4, true), 372 | locals: view.getUint32(ofs + 8, true), 373 | profile: view.getUint32(ofs + 12, true), 374 | name: view.getUint32(ofs + 16, true), 375 | file: view.getUint32(ofs + 20, true), 376 | numparms: view.getUint32(ofs + 24, true), 377 | parm_size: [ 378 | view.getUint8(ofs + 28), view.getUint8(ofs + 29), 379 | view.getUint8(ofs + 30), view.getUint8(ofs + 31), 380 | view.getUint8(ofs + 32), view.getUint8(ofs + 33), 381 | view.getUint8(ofs + 34), view.getUint8(ofs + 35) 382 | ] 383 | }; 384 | ofs += 36; 385 | } 386 | 387 | ofs = view.getUint32(40, true); 388 | num = view.getUint32(44, true); 389 | PR.strings = []; 390 | for (i = 0; i < num; ++i) 391 | PR.strings[i] = view.getUint8(ofs + i); 392 | PR.string_temp = PR.NewString('', 128); 393 | PR.netnames = PR.NewString('', SV.svs.maxclients << 5); 394 | 395 | ofs = view.getUint32(48, true); 396 | num = view.getUint32(52, true); 397 | PR.globals = new ArrayBuffer(num << 2); 398 | PR.globals_float = new Float32Array(PR.globals); 399 | PR.globals_int = new Int32Array(PR.globals); 400 | for (i = 0; i < num; ++i) 401 | PR.globals_int[i] = view.getInt32(ofs + (i << 2), true); 402 | 403 | PR.entityfields = view.getUint32(56, true); 404 | PR.edict_size = 96 + (PR.entityfields << 2); 405 | 406 | var fields = [ 407 | 'ammo_shells1', 408 | 'ammo_nails1', 409 | 'ammo_lava_nails', 410 | 'ammo_rockets1', 411 | 'ammo_multi_rockets', 412 | 'ammo_cells1', 413 | 'ammo_plasma', 414 | 'gravity', 415 | 'items2' 416 | ], field, def; 417 | for (i = 0; i < fields.length; ++i) 418 | { 419 | field = fields[i]; 420 | def = ED.FindField(field); 421 | PR.entvars[field] = (def != null) ? def.ofs : null; 422 | } 423 | }; 424 | 425 | PR.Init = function() 426 | { 427 | Cmd.AddCommand('edict', ED.PrintEdict_f); 428 | Cmd.AddCommand('edicts', ED.PrintEdicts); 429 | Cmd.AddCommand('edictcount', ED.Count); 430 | Cmd.AddCommand('profile', PR.Profile_f); 431 | Cvar.RegisterVariable('nomonsters', '0'); 432 | Cvar.RegisterVariable('gamecfg', '0'); 433 | Cvar.RegisterVariable('scratch1', '0'); 434 | Cvar.RegisterVariable('scratch2', '0'); 435 | Cvar.RegisterVariable('scratch3', '0'); 436 | Cvar.RegisterVariable('scratch4', '0'); 437 | Cvar.RegisterVariable('savedgamecfg', '0', true); 438 | Cvar.RegisterVariable('saved1', '0', true); 439 | Cvar.RegisterVariable('saved2', '0', true); 440 | Cvar.RegisterVariable('saved3', '0', true); 441 | Cvar.RegisterVariable('saved4', '0', true); 442 | }; 443 | 444 | // exec 445 | 446 | PR.localstack_size = 2048; 447 | 448 | PR.opnames = [ 449 | 'DONE', 450 | 'MUL_F', 'MUL_V', 'MUL_FV', 'MUL_VF', 451 | 'DIV', 452 | 'ADD_F', 'ADD_V', 453 | 'SUB_F', 'SUB_V', 454 | 'EQ_F', 'EQ_V', 'EQ_S', 'EQ_E', 'EQ_FNC', 455 | 'NE_F', 'NE_V', 'NE_S', 'NE_E', 'NE_FNC', 456 | 'LE', 'GE', 'LT', 'GT', 457 | 'INDIRECT', 'INDIRECT', 'INDIRECT', 'INDIRECT', 'INDIRECT', 'INDIRECT', 458 | 'ADDRESS', 459 | 'STORE_F', 'STORE_V', 'STORE_S', 'STORE_ENT', 'STORE_FLD', 'STORE_FNC', 460 | 'STOREP_F', 'STOREP_V', 'STOREP_S', 'STOREP_ENT', 'STOREP_FLD', 'STOREP_FNC', 461 | 'RETURN', 462 | 'NOT_F', 'NOT_V', 'NOT_S', 'NOT_ENT', 'NOT_FNC', 463 | 'IF', 'IFNOT', 464 | 'CALL0', 'CALL1', 'CALL2', 'CALL3', 'CALL4', 'CALL5', 'CALL6', 'CALL7', 'CALL8', 465 | 'STATE', 466 | 'GOTO', 467 | 'AND', 'OR', 468 | 'BITAND', 'BITOR' 469 | ]; 470 | 471 | PR.PrintStatement = function(s) 472 | { 473 | var text; 474 | if (s.op < PR.opnames.length) 475 | { 476 | text = PR.opnames[s.op] + ' '; 477 | for (; text.length <= 9; ) 478 | text += ' '; 479 | } 480 | else 481 | text = ''; 482 | if ((s.op === PR.op.jnz) || (s.op === PR.op.jz)) 483 | text += PR.GlobalString(s.a) + 'branch ' + s.b; 484 | else if (s.op === PR.op.jump) 485 | text += 'branch ' + s.a; 486 | else if ((s.op >= PR.op.store_f) && (s.op <= PR.op.store_fnc)) 487 | text += PR.GlobalString(s.a) + PR.GlobalStringNoContents(s.b); 488 | else 489 | { 490 | if (s.a !== 0) 491 | text += PR.GlobalString(s.a); 492 | if (s.b !== 0) 493 | text += PR.GlobalString(s.b); 494 | if (s.c !== 0) 495 | text += PR.GlobalStringNoContents(s.c); 496 | } 497 | Con.Print(text + '\n'); 498 | }; 499 | 500 | PR.StackTrace = function() 501 | { 502 | if (PR.depth === 0) 503 | { 504 | Con.Print('\n'); 505 | return; 506 | } 507 | PR.stack[PR.depth] = [PR.xstatement, PR.xfunction]; 508 | var f, file; 509 | for (; PR.depth >= 0; --PR.depth) 510 | { 511 | f = PR.stack[PR.depth][1]; 512 | if (f == null) 513 | { 514 | Con.Print('\n'); 515 | continue; 516 | } 517 | file = PR.GetString(f.file); 518 | for (; file.length <= 11; ) 519 | file += ' '; 520 | Con.Print(file + ' : ' + PR.GetString(f.name) + '\n'); 521 | } 522 | PR.depth = 0; 523 | }; 524 | 525 | PR.Profile_f = function() 526 | { 527 | if (SV.server.active !== true) 528 | return; 529 | var num = 0, max, best, i, f, profile; 530 | for (;;) 531 | { 532 | max = 0; 533 | best = null; 534 | for (i = 0; i < PR.functions.length; ++i) 535 | { 536 | f = PR.functions[i]; 537 | if (f.profile > max) 538 | { 539 | max = f.profile; 540 | best = f; 541 | } 542 | } 543 | if (best == null) 544 | return; 545 | if (num < 10) 546 | { 547 | profile = best.profile.toString(); 548 | for (; profile.length <= 6; ) 549 | profile = ' ' + profile; 550 | Con.Print(profile + ' ' + PR.GetString(best.name) + '\n'); 551 | } 552 | ++num; 553 | best.profile = 0; 554 | } 555 | }; 556 | 557 | PR.RunError = function(error) 558 | { 559 | PR.PrintStatement(PR.statements[PR.xstatement]); 560 | PR.StackTrace(); 561 | Con.Print(error + '\n'); 562 | Host.Error('Program error'); 563 | }; 564 | 565 | PR.EnterFunction = function(f) 566 | { 567 | PR.stack[PR.depth++] = [PR.xstatement, PR.xfunction]; 568 | var c = f.locals; 569 | if ((PR.localstack_used + c) > PR.localstack_size) 570 | PR.RunError('PR.EnterFunction: locals stack overflow\n'); 571 | var i; 572 | for (i = 0; i < c; ++i) 573 | PR.localstack[PR.localstack_used + i] = PR.globals_int[f.parm_start + i]; 574 | PR.localstack_used += c; 575 | var o = f.parm_start, j; 576 | for (i = 0; i < f.numparms; ++i) 577 | { 578 | for (j = 0; j < f.parm_size[i]; ++j) 579 | PR.globals_int[o++] = PR.globals_int[4 + i * 3 + j]; 580 | } 581 | PR.xfunction = f; 582 | return f.first_statement - 1; 583 | }; 584 | 585 | PR.LeaveFunction = function() 586 | { 587 | if (PR.depth <= 0) 588 | Sys.Error('prog stack underflow'); 589 | var c = PR.xfunction.locals; 590 | PR.localstack_used -= c; 591 | if (PR.localstack_used < 0) 592 | PR.RunError('PR.LeaveFunction: locals stack underflow\n'); 593 | for (--c; c >= 0; --c) 594 | PR.globals_int[PR.xfunction.parm_start + c] = PR.localstack[PR.localstack_used + c]; 595 | PR.xfunction = PR.stack[--PR.depth][1]; 596 | return PR.stack[PR.depth][0]; 597 | }; 598 | 599 | PR.ExecuteProgram = function(fnum) 600 | { 601 | if ((fnum === 0) || (fnum >= PR.functions.length)) 602 | { 603 | if (PR.globals_int[PR.globalvars.self] !== 0) 604 | ED.Print(SV.server.edicts[PR.globals_int[PR.globalvars.self]]); 605 | Host.Error('PR.ExecuteProgram: NULL function'); 606 | } 607 | var runaway = 100000; 608 | PR.trace = false; 609 | var exitdepth = PR.depth; 610 | var s = PR.EnterFunction(PR.functions[fnum]); 611 | var st, ed, ptr, newf; 612 | 613 | for (;;) 614 | { 615 | ++s; 616 | st = PR.statements[s]; 617 | if (--runaway === 0) 618 | PR.RunError('runaway loop error'); 619 | ++PR.xfunction.profile; 620 | PR.xstatement = s; 621 | if (PR.trace === true) 622 | PR.PrintStatement(st); 623 | switch (st.op) 624 | { 625 | case PR.op.add_f: 626 | PR.globals_float[st.c] = PR.globals_float[st.a] + PR.globals_float[st.b]; 627 | continue; 628 | case PR.op.add_v: 629 | PR.globals_float[st.c] = PR.globals_float[st.a] + PR.globals_float[st.b]; 630 | PR.globals_float[st.c + 1] = PR.globals_float[st.a + 1] + PR.globals_float[st.b + 1]; 631 | PR.globals_float[st.c + 2] = PR.globals_float[st.a + 2] + PR.globals_float[st.b + 2]; 632 | continue; 633 | case PR.op.sub_f: 634 | PR.globals_float[st.c] = PR.globals_float[st.a] - PR.globals_float[st.b]; 635 | continue; 636 | case PR.op.sub_v: 637 | PR.globals_float[st.c] = PR.globals_float[st.a] - PR.globals_float[st.b]; 638 | PR.globals_float[st.c + 1] = PR.globals_float[st.a + 1] - PR.globals_float[st.b + 1]; 639 | PR.globals_float[st.c + 2] = PR.globals_float[st.a + 2] - PR.globals_float[st.b + 2]; 640 | continue; 641 | case PR.op.mul_f: 642 | PR.globals_float[st.c] = PR.globals_float[st.a] * PR.globals_float[st.b]; 643 | continue; 644 | case PR.op.mul_v: 645 | PR.globals_float[st.c] = PR.globals_float[st.a] * PR.globals_float[st.b] + 646 | PR.globals_float[st.a + 1] * PR.globals_float[st.b + 1] + 647 | PR.globals_float[st.a + 2] * PR.globals_float[st.b + 2]; 648 | continue; 649 | case PR.op.mul_fv: 650 | PR.globals_float[st.c] = PR.globals_float[st.a] * PR.globals_float[st.b]; 651 | PR.globals_float[st.c + 1] = PR.globals_float[st.a] * PR.globals_float[st.b + 1]; 652 | PR.globals_float[st.c + 2] = PR.globals_float[st.a] * PR.globals_float[st.b + 2]; 653 | continue; 654 | case PR.op.mul_vf: 655 | PR.globals_float[st.c] = PR.globals_float[st.b] * PR.globals_float[st.a]; 656 | PR.globals_float[st.c + 1] = PR.globals_float[st.b] * PR.globals_float[st.a + 1]; 657 | PR.globals_float[st.c + 2] = PR.globals_float[st.b] * PR.globals_float[st.a + 2]; 658 | continue; 659 | case PR.op.div_f: 660 | PR.globals_float[st.c] = PR.globals_float[st.a] / PR.globals_float[st.b]; 661 | continue; 662 | case PR.op.bitand: 663 | PR.globals_float[st.c] = PR.globals_float[st.a] & PR.globals_float[st.b]; 664 | continue; 665 | case PR.op.bitor: 666 | PR.globals_float[st.c] = PR.globals_float[st.a] | PR.globals_float[st.b]; 667 | continue; 668 | case PR.op.ge: 669 | PR.globals_float[st.c] = (PR.globals_float[st.a] >= PR.globals_float[st.b]) ? 1.0 : 0.0; 670 | continue; 671 | case PR.op.le: 672 | PR.globals_float[st.c] = (PR.globals_float[st.a] <= PR.globals_float[st.b]) ? 1.0 : 0.0; 673 | continue; 674 | case PR.op.gt: 675 | PR.globals_float[st.c] = (PR.globals_float[st.a] > PR.globals_float[st.b]) ? 1.0 : 0.0; 676 | continue; 677 | case PR.op.lt: 678 | PR.globals_float[st.c] = (PR.globals_float[st.a] < PR.globals_float[st.b]) ? 1.0 : 0.0; 679 | continue; 680 | case PR.op.and: 681 | PR.globals_float[st.c] = ((PR.globals_float[st.a] !== 0.0) && (PR.globals_float[st.b] !== 0.0)) ? 1.0 : 0.0; 682 | continue; 683 | case PR.op.or: 684 | PR.globals_float[st.c] = ((PR.globals_float[st.a] !== 0.0) || (PR.globals_float[st.b] !== 0.0)) ? 1.0 : 0.0; 685 | continue; 686 | case PR.op.not_f: 687 | PR.globals_float[st.c] = (PR.globals_float[st.a] === 0.0) ? 1.0 : 0.0; 688 | continue; 689 | case PR.op.not_v: 690 | PR.globals_float[st.c] = ((PR.globals_float[st.a] === 0.0) && 691 | (PR.globals_float[st.a + 1] === 0.0) && 692 | (PR.globals_float[st.a + 2] === 0.0)) ? 1.0 : 0.0; 693 | continue; 694 | case PR.op.not_s: 695 | if (PR.globals_int[st.a] !== 0) 696 | PR.globals_float[st.c] = (PR.strings[PR.globals_int[st.a]] === 0) ? 1.0 : 0.0; 697 | else 698 | PR.globals_float[st.c] = 1.0; 699 | continue; 700 | case PR.op.not_fnc: 701 | case PR.op.not_ent: 702 | PR.globals_float[st.c] = (PR.globals_int[st.a] === 0) ? 1.0 : 0.0; 703 | continue; 704 | case PR.op.eq_f: 705 | PR.globals_float[st.c] = (PR.globals_float[st.a] === PR.globals_float[st.b]) ? 1.0 : 0.0; 706 | continue; 707 | case PR.op.eq_v: 708 | PR.globals_float[st.c] = ((PR.globals_float[st.a] === PR.globals_float[st.b]) 709 | && (PR.globals_float[st.a + 1] === PR.globals_float[st.b + 1]) 710 | && (PR.globals_float[st.a + 2] === PR.globals_float[st.b + 2])) ? 1.0 : 0.0; 711 | continue; 712 | case PR.op.eq_s: 713 | PR.globals_float[st.c] = (PR.GetString(PR.globals_int[st.a]) === PR.GetString(PR.globals_int[st.b])) ? 1.0 : 0.0; 714 | continue; 715 | case PR.op.eq_e: 716 | case PR.op.eq_fnc: 717 | PR.globals_float[st.c] = (PR.globals_int[st.a] === PR.globals_int[st.b]) ? 1.0 : 0.0; 718 | continue; 719 | case PR.op.ne_f: 720 | PR.globals_float[st.c] = (PR.globals_float[st.a] !== PR.globals_float[st.b]) ? 1.0 : 0.0; 721 | continue; 722 | case PR.op.ne_v: 723 | PR.globals_float[st.c] = ((PR.globals_float[st.a] !== PR.globals_float[st.b]) 724 | || (PR.globals_float[st.a + 1] !== PR.globals_float[st.b + 1]) 725 | || (PR.globals_float[st.a + 2] !== PR.globals_float[st.b + 2])) ? 1.0 : 0.0; 726 | continue; 727 | case PR.op.ne_s: 728 | PR.globals_float[st.c] = (PR.GetString(PR.globals_int[st.a]) !== PR.GetString(PR.globals_int[st.b])) ? 1.0 : 0.0; 729 | continue; 730 | case PR.op.ne_e: 731 | case PR.op.ne_fnc: 732 | PR.globals_float[st.c] = (PR.globals_int[st.a] !== PR.globals_int[st.b]) ? 1.0 : 0.0; 733 | continue; 734 | case PR.op.store_f: 735 | case PR.op.store_ent: 736 | case PR.op.store_fld: 737 | case PR.op.store_s: 738 | case PR.op.store_fnc: 739 | PR.globals_int[st.b] = PR.globals_int[st.a]; 740 | continue; 741 | case PR.op.store_v: 742 | PR.globals_int[st.b] = PR.globals_int[st.a]; 743 | PR.globals_int[st.b + 1] = PR.globals_int[st.a + 1]; 744 | PR.globals_int[st.b + 2] = PR.globals_int[st.a + 2]; 745 | continue; 746 | case PR.op.storep_f: 747 | case PR.op.storep_ent: 748 | case PR.op.storep_fld: 749 | case PR.op.storep_s: 750 | case PR.op.storep_fnc: 751 | ptr = PR.globals_int[st.b]; 752 | SV.server.edicts[Math.floor(ptr / PR.edict_size)].v_int[((ptr % PR.edict_size) - 96) >> 2] = PR.globals_int[st.a]; 753 | continue; 754 | case PR.op.storep_v: 755 | ed = SV.server.edicts[Math.floor(PR.globals_int[st.b] / PR.edict_size)]; 756 | ptr = ((PR.globals_int[st.b] % PR.edict_size) - 96) >> 2; 757 | ed.v_int[ptr] = PR.globals_int[st.a]; 758 | ed.v_int[ptr + 1] = PR.globals_int[st.a + 1]; 759 | ed.v_int[ptr + 2] = PR.globals_int[st.a + 2]; 760 | continue; 761 | case PR.op.address: 762 | ed = PR.globals_int[st.a]; 763 | if ((ed === 0) && (SV.server.loading !== true)) 764 | PR.RunError('assignment to world entity'); 765 | PR.globals_int[st.c] = ed * PR.edict_size + 96 + (PR.globals_int[st.b] << 2); 766 | continue; 767 | case PR.op.load_f: 768 | case PR.op.load_fld: 769 | case PR.op.load_ent: 770 | case PR.op.load_s: 771 | case PR.op.load_fnc: 772 | PR.globals_int[st.c] = SV.server.edicts[PR.globals_int[st.a]].v_int[PR.globals_int[st.b]]; 773 | continue; 774 | case PR.op.load_v: 775 | ed = SV.server.edicts[PR.globals_int[st.a]]; 776 | ptr = PR.globals_int[st.b]; 777 | PR.globals_int[st.c] = ed.v_int[ptr]; 778 | PR.globals_int[st.c + 1] = ed.v_int[ptr + 1]; 779 | PR.globals_int[st.c + 2] = ed.v_int[ptr + 2]; 780 | continue; 781 | case PR.op.jz: 782 | if (PR.globals_int[st.a] === 0) 783 | s += st.b - 1; 784 | continue; 785 | case PR.op.jnz: 786 | if (PR.globals_int[st.a] !== 0) 787 | s += st.b - 1; 788 | continue; 789 | case PR.op.jump: 790 | s += st.a - 1; 791 | continue; 792 | case PR.op.call0: 793 | case PR.op.call1: 794 | case PR.op.call2: 795 | case PR.op.call3: 796 | case PR.op.call4: 797 | case PR.op.call5: 798 | case PR.op.call6: 799 | case PR.op.call7: 800 | case PR.op.call8: 801 | PR.argc = st.op - PR.op.call0; 802 | if (PR.globals_int[st.a] === 0) 803 | PR.RunError('NULL function'); 804 | newf = PR.functions[PR.globals_int[st.a]]; 805 | if (newf.first_statement < 0) 806 | { 807 | ptr = -newf.first_statement; 808 | if (ptr >= PF.builtin.length) 809 | PR.RunError('Bad builtin call number'); 810 | PF.builtin[ptr](); 811 | continue; 812 | } 813 | s = PR.EnterFunction(newf); 814 | continue; 815 | case PR.op.done: 816 | case PR.op.ret: 817 | PR.globals_int[1] = PR.globals_int[st.a]; 818 | PR.globals_int[2] = PR.globals_int[st.a + 1]; 819 | PR.globals_int[3] = PR.globals_int[st.a + 2]; 820 | s = PR.LeaveFunction(); 821 | if (PR.depth === exitdepth) 822 | return; 823 | continue; 824 | case PR.op.state: 825 | ed = SV.server.edicts[PR.globals_int[PR.globalvars.self]]; 826 | ed.v_float[PR.entvars.nextthink] = PR.globals_float[PR.globalvars.time] + 0.1; 827 | ed.v_float[PR.entvars.frame] = PR.globals_float[st.a]; 828 | ed.v_int[PR.entvars.think] = PR.globals_int[st.b]; 829 | continue; 830 | } 831 | PR.RunError('Bad opcode ' + st.op); 832 | } 833 | }; 834 | 835 | PR.GetString = function(num) 836 | { 837 | var string = [], c; 838 | for (; num < PR.strings.length; ++num) 839 | { 840 | if (PR.strings[num] === 0) 841 | break; 842 | string[string.length] = String.fromCharCode(PR.strings[num]); 843 | } 844 | return string.join(''); 845 | }; 846 | 847 | PR.NewString = function(s, length) 848 | { 849 | var ofs = PR.strings.length; 850 | var i; 851 | if (s.length >= length) 852 | { 853 | for (i = 0; i < (length - 1); ++i) 854 | PR.strings[PR.strings.length] = s.charCodeAt(i); 855 | PR.strings[PR.strings.length] = 0; 856 | return ofs; 857 | } 858 | for (i = 0; i < s.length; ++i) 859 | PR.strings[PR.strings.length] = s.charCodeAt(i); 860 | length -= s.length; 861 | for (i = 0; i < length; ++i) 862 | PR.strings[PR.strings.length] = 0; 863 | return ofs; 864 | }; 865 | 866 | PR.TempString = function(string) 867 | { 868 | var i; 869 | if (string.length > 127) 870 | string = string.substring(0, 127); 871 | for (i = 0; i < string.length; ++i) 872 | PR.strings[PR.string_temp + i] = string.charCodeAt(i); 873 | PR.strings[PR.string_temp + string.length] = 0; 874 | }; -------------------------------------------------------------------------------- /server/js/Host.js: -------------------------------------------------------------------------------- 1 | Host = {}; 2 | 3 | Host.framecount = 0; 4 | 5 | Host.Error = function(error) 6 | { 7 | if (Host.inerror === true) 8 | Sys.Error('Host.Error: recursively entered'); 9 | Host.inerror = true; 10 | error = 'Host.Error: ' + error + '\n'; 11 | Con.Print(error); 12 | Sys.Error(error); 13 | }; 14 | 15 | Host.FindMaxClients = function() 16 | { 17 | var i = COM.CheckParm('-maxplayers'); 18 | SV.svs.maxclients = 8; 19 | if (i != null) 20 | { 21 | ++i; 22 | if (i < COM.argv.length) 23 | { 24 | SV.svs.maxclients = Q.atoi(COM.argv[i]); 25 | if (SV.svs.maxclients <= 0) 26 | SV.svs.maxclients = 8; 27 | else if (SV.svs.maxclients > 16) 28 | SV.svs.maxclients = 16; 29 | } 30 | } 31 | SV.svs.maxclientslimit = SV.svs.maxclients; 32 | SV.svs.clients = []; 33 | for (i = 0; i < SV.svs.maxclientslimit; ++i) 34 | { 35 | SV.svs.clients[i] = { 36 | num: i, 37 | message: {data: new ArrayBuffer(8000), cursize: 0, allowoverflow: true}, 38 | colors: 0, 39 | old_frags: 0 40 | }; 41 | } 42 | if (SV.svs.maxclients > 1) 43 | Cvar.SetValue('deathmatch', 1); 44 | else 45 | Cvar.SetValue('deathmatch', 0); 46 | }; 47 | 48 | Host.InitLocal = function() 49 | { 50 | Host.InitCommands(); 51 | Host.framerate = Cvar.RegisterVariable('host_framerate', '0'); 52 | Host.speeds = Cvar.RegisterVariable('host_speeds', '0'); 53 | Host.rcon_password = Cvar.RegisterVariable('rcon_password', ''); 54 | Host.ticrate = Cvar.RegisterVariable('sys_ticrate', '0.05'); 55 | //Host.ticrate = Cvar.RegisterVariable('sys_ticrate', '0.5'); 56 | Host.serverprofile = Cvar.RegisterVariable('serverprofile', '0'); 57 | Host.fraglimit = Cvar.RegisterVariable('fraglimit', '0', false, true); 58 | Host.timelimit = Cvar.RegisterVariable('timelimit', '0', false, true); 59 | Host.teamplay = Cvar.RegisterVariable('teamplay', '0', false, true); 60 | Host.samelevel = Cvar.RegisterVariable('samelevel', '0'); 61 | Host.noexit = Cvar.RegisterVariable('noexit', '0', false, true); 62 | Host.skill = Cvar.RegisterVariable('skill', '1'); 63 | Host.developer = Cvar.RegisterVariable('developer', '0'); 64 | Host.deathmatch = Cvar.RegisterVariable('deathmatch', '0'); 65 | Host.coop = Cvar.RegisterVariable('coop', '0'); 66 | Host.pausable = Cvar.RegisterVariable('pausable', '1'); 67 | Host.temp1 = Cvar.RegisterVariable('temp1', '0'); 68 | Host.FindMaxClients(); 69 | }; 70 | 71 | Host.GetConsoleCommands = function() 72 | { 73 | var cmd; 74 | for (;;) 75 | { 76 | cmd = Sys.ConsoleInput(); 77 | if (cmd == null) 78 | return; 79 | Cmd.text += cmd; 80 | } 81 | }; 82 | 83 | Host.ClientPrint = function(string) 84 | { 85 | MSG.WriteByte(Host.client.message, Protocol.svc.print); 86 | MSG.WriteString(Host.client.message, string); 87 | }; 88 | 89 | Host.BroadcastPrint = function(string) 90 | { 91 | var i, client; 92 | for (i = 0; i < SV.svs.maxclients; ++i) 93 | { 94 | client = SV.svs.clients[i]; 95 | if ((client.active !== true) || (client.spawned !== true)) 96 | continue; 97 | MSG.WriteByte(client.message, Protocol.svc.print); 98 | MSG.WriteString(client.message, string); 99 | } 100 | }; 101 | 102 | Host.DropClient = function(crash) 103 | { 104 | var client = Host.client; 105 | if (crash !== true) 106 | { 107 | if (NET.CanSendMessage(client.netconnection) === true) 108 | { 109 | MSG.WriteByte(client.message, Protocol.svc.disconnect); 110 | NET.SendMessage(client.netconnection, client.message); 111 | } 112 | if ((client.edict != null) && (client.spawned === true)) 113 | { 114 | var saveSelf = PR.globals_int[PR.globalvars.self]; 115 | PR.globals_int[PR.globalvars.self] = client.edict.num; 116 | PR.ExecuteProgram(PR.globals_int[PR.globalvars.ClientDisconnect]); 117 | PR.globals_int[PR.globalvars.self] = saveSelf; 118 | } 119 | Sys.Print('Client ' + SV.GetClientName(client) + ' removed\n'); 120 | } 121 | NET.Close(client.netconnection); 122 | client.netconnection = null; 123 | client.active = false; 124 | SV.SetClientName(client, ''); 125 | client.old_frags = -999999; 126 | --NET.activeconnections; 127 | var i, num = client.num; 128 | for (i = 0; i < SV.svs.maxclients; ++i) 129 | { 130 | client = SV.svs.clients[i]; 131 | if (client.active !== true) 132 | continue; 133 | MSG.WriteByte(client.message, Protocol.svc.updatename); 134 | MSG.WriteByte(client.message, num); 135 | MSG.WriteByte(client.message, 0); 136 | MSG.WriteByte(client.message, Protocol.svc.updatefrags); 137 | MSG.WriteByte(client.message, num); 138 | MSG.WriteShort(client.message, 0); 139 | MSG.WriteByte(client.message, Protocol.svc.updatecolors); 140 | MSG.WriteByte(client.message, num); 141 | MSG.WriteByte(client.message, 0); 142 | } 143 | }; 144 | 145 | Host.ShutdownServer = function(crash) 146 | { 147 | if (SV.server.active !== true) 148 | return; 149 | SV.server.active = false; 150 | var start = Sys.FloatTime(), count, i; 151 | do 152 | { 153 | count = 0; 154 | for (i = 0; i < SV.svs.maxclients; ++i) 155 | { 156 | Host.client = SV.svs.clients[i]; 157 | if ((Host.client.active !== true) || (Host.client.message.cursize === 0)) 158 | continue; 159 | if (NET.CanSendMessage(Host.client.netconnection) === true) 160 | { 161 | NET.SendMessage(Host.client.netconnection, Host.client.message); 162 | Host.client.message.cursize = 0; 163 | continue; 164 | } 165 | NET.GetMessage(Host.client.netconnection); 166 | ++count; 167 | } 168 | if ((Sys.FloatTime() - start) > 3.0) 169 | break; 170 | } while (count !== 0); 171 | var buf = {data: new ArrayBuffer(4), cursize: 1}; 172 | (new Uint8Array(buf.data))[0] = Protocol.svc.disconnect; 173 | count = NET.SendToAll(buf); 174 | if (count !== 0) 175 | Con.Print('Host.ShutdownServer: NET.SendToAll failed for ' + count + ' clients\n'); 176 | for (i = 0; i < SV.svs.maxclients; ++i) 177 | { 178 | Host.client = SV.svs.clients[i]; 179 | if (Host.client.active === true) 180 | Host.DropClient(crash); 181 | } 182 | }; 183 | 184 | Host.RemoteCommand = function(from, data, password) 185 | { 186 | if ((Host.rcon_password.string.length === 0) || (password !== Host.rcon_password.string)) 187 | { 188 | Con.Print('Bad rcon from ' + from + ':\n' + data + '\n'); 189 | return; 190 | }; 191 | Con.Print('Rcon from ' + from + ':\n' + data + '\n'); 192 | Cmd.ExecuteString(data); 193 | return true; 194 | }; 195 | 196 | Host.ServerFrame = function() 197 | { 198 | PR.globals_float[PR.globalvars.frametime] = Host.frametime; 199 | SV.server.datagram.cursize = 0; 200 | SV.CheckForNewClients(); 201 | SV.RunClients(); 202 | if (SV.server.paused !== true) 203 | SV.Physics(); 204 | SV.SendClientMessages(); 205 | }; 206 | 207 | Host.realtime = 0.0; 208 | Host._Frame = function() 209 | { 210 | Math.random(); 211 | 212 | Host.realtime = Sys.FloatTime(); 213 | Host.frametime = Host.realtime - Host.oldrealtime; 214 | Host.oldrealtime = Host.realtime; 215 | if (Host.framerate.value > 0) 216 | Host.frametime = Host.framerate.value; 217 | else 218 | { 219 | if (Host.frametime > 0.1) 220 | Host.frametime = 0.1; 221 | else if (Host.frametime < 0.001) 222 | Host.frametime = 0.001; 223 | } 224 | Cmd.Execute(); 225 | if (SV.server.active === true) 226 | Host.ServerFrame(); 227 | Host.GetConsoleCommands(); 228 | ++Host.framecount; 229 | }; 230 | 231 | Host.timetotal = 0.0; 232 | Host.timecount = 0; 233 | Host.Frame = function() 234 | { 235 | setTimeout(Host.Frame, Host.ticrate.value * 1000.0); 236 | if (Host.serverprofile.value === 0) 237 | { 238 | Host._Frame(); 239 | return; 240 | } 241 | var time1 = Sys.FloatTime(); 242 | Host._Frame(); 243 | Host.timetotal += Sys.FloatTime() - time1; 244 | if (++Host.timecount <= 999) 245 | return; 246 | var m = (Host.timetotal * 1000.0 / Host.timecount) >> 0; 247 | Host.timecount = 0; 248 | Host.timetotal = 0.0; 249 | var i, c = 0; 250 | for (i = 0; i < SV.svs.maxclients; ++i) 251 | { 252 | if (SV.svs.clients[i].active === true) 253 | ++c; 254 | } 255 | Con.Print('serverprofile: ' + (c <= 9 ? ' ' : '') + c + ' clients ' + (m <= 9 ? ' ' : '') + m + ' msec\n'); 256 | }; 257 | 258 | Host.Init = function() 259 | { 260 | Host.oldrealtime = Sys.FloatTime(); 261 | Cmd.Init(); 262 | V.Init(); 263 | COM.Init(); 264 | Host.InitLocal(); 265 | PR.Init(); 266 | Mod.Init(); 267 | NET.Init(); 268 | SV.Init(); 269 | Cmd.text = 'exec quake.rc\n' + Cmd.text; 270 | Sys.Print('========Quake Initialized=========\n'); 271 | }; 272 | 273 | // Commands 274 | 275 | Host.Quit_f = function() 276 | { 277 | Sys.Quit(); 278 | }; 279 | 280 | Host.Status_f = function() 281 | { 282 | var print; 283 | if (Cmd.client !== true) 284 | { 285 | if (SV.server.active !== true) 286 | return; 287 | print = Con.Print; 288 | } 289 | else 290 | print = Host.ClientPrint; 291 | print('host: ' + NET.hostname.string + '\n'); 292 | print('version: 1.09\n'); 293 | print('map: ' + PR.GetString(PR.globals_int[PR.globalvars.mapname]) + '\n'); 294 | print('players: ' + NET.activeconnections + ' active (' + SV.svs.maxclients + ' max)\n\n'); 295 | var i, client, str, frags, hours, minutes, seconds; 296 | for (i = 0; i < SV.svs.maxclients; ++i) 297 | { 298 | client = SV.svs.clients[i]; 299 | if (client.active !== true) 300 | continue; 301 | frags = client.edict.v_float[PR.entvars.frags].toFixed(0); 302 | if (frags.length === 1) 303 | frags = ' ' + frags; 304 | else if (frags.length === 2) 305 | frags = ' ' + frags; 306 | seconds = (NET.time - client.netconnection.connecttime) >> 0; 307 | minutes = (seconds / 60) >> 0; 308 | if (minutes !== 0) 309 | { 310 | seconds -= minutes * 60; 311 | hours = (minutes / 60) >> 0; 312 | if (hours !== 0) 313 | minutes -= hours * 60; 314 | } 315 | else 316 | hours = 0; 317 | str = '#' + (i + 1) + ' '; 318 | if (i <= 8) 319 | str += ' '; 320 | str += SV.GetClientName(client); 321 | for (; str.length <= 21; ) 322 | str += ' '; 323 | str += frags + ' '; 324 | if (hours <= 9) 325 | str += ' '; 326 | str += hours + ':'; 327 | if (minutes <= 9) 328 | str += '0'; 329 | str += minutes + ':'; 330 | if (seconds <= 9) 331 | str += '0'; 332 | print(str + seconds + '\n'); 333 | print(' ' + client.netconnection.address + '\n'); 334 | } 335 | }; 336 | 337 | Host.God_f = function() 338 | { 339 | if (Cmd.client !== true) 340 | return; 341 | if (PR.globals_float[PR.globalvars.deathmatch] !== 0) 342 | return; 343 | SV.player.v_float[PR.entvars.flags] ^= SV.fl.godmode; 344 | if ((SV.player.v_float[PR.entvars.flags] & SV.fl.godmode) === 0) 345 | Host.ClientPrint('godmode OFF\n'); 346 | else 347 | Host.ClientPrint('godmode ON\n'); 348 | }; 349 | 350 | Host.Notarget_f = function() 351 | { 352 | if (Cmd.client !== true) 353 | return; 354 | if (PR.globals_float[PR.globalvars.deathmatch] !== 0) 355 | return; 356 | SV.player.v_float[PR.entvars.flags] ^= SV.fl.notarget; 357 | if ((SV.player.v_float[PR.entvars.flags] & SV.fl.notarget) === 0) 358 | Host.ClientPrint('notarget OFF\n'); 359 | else 360 | Host.ClientPrint('notarget ON\n'); 361 | }; 362 | 363 | Host.Noclip_f = function() 364 | { 365 | if (Cmd.client !== true) 366 | return; 367 | if (PR.globals_float[PR.globalvars.deathmatch] !== 0) 368 | return; 369 | if (SV.player.v_float[PR.entvars.movetype] !== SV.movetype.noclip) 370 | { 371 | Host.noclip_anglehack = true; 372 | SV.player.v_float[PR.entvars.movetype] = SV.movetype.noclip; 373 | Host.ClientPrint('noclip ON\n'); 374 | return; 375 | } 376 | Host.noclip_anglehack = false; 377 | SV.player.v_float[PR.entvars.movetype] = SV.movetype.walk; 378 | Host.ClientPrint('noclip OFF\n'); 379 | }; 380 | 381 | Host.Fly_f = function() 382 | { 383 | if (Cmd.client !== true) 384 | return; 385 | if (PR.globals_float[PR.globalvars.deathmatch] !== 0) 386 | return; 387 | if (SV.player.v_float[PR.entvars.movetype] !== SV.movetype.fly) 388 | { 389 | SV.player.v_float[PR.entvars.movetype] = SV.movetype.fly; 390 | Host.ClientPrint('flymode ON\n'); 391 | return; 392 | } 393 | SV.player.v_float[PR.entvars.movetype] = SV.movetype.walk; 394 | Host.ClientPrint('flymode OFF\n'); 395 | }; 396 | 397 | Host.Ping_f = function() 398 | { 399 | if (Cmd.client !== true) 400 | return; 401 | Host.ClientPrint('Client ping times:\n'); 402 | var i, client, total, j; 403 | for (i = 0; i < SV.svs.maxclients; ++i) 404 | { 405 | client = SV.svs.clients[i]; 406 | if (client.active !== true) 407 | continue; 408 | total = 0; 409 | for (j = 0; j <= 15; ++j) 410 | total += client.ping_times[j]; 411 | total = (total * 62.5).toFixed(0); 412 | if (total.length === 1) 413 | total = ' ' + total; 414 | else if (total.length === 2) 415 | total = ' ' + total; 416 | else if (total.length === 3) 417 | total = ' ' + total; 418 | Host.ClientPrint(total + ' ' + SV.GetClientName(client) + '\n'); 419 | } 420 | }; 421 | 422 | Host.Map_f = function() 423 | { 424 | if (Cmd.argv.length <= 1) 425 | { 426 | Con.Print('USAGE: map \n'); 427 | return; 428 | } 429 | if (Cmd.client === true) 430 | return; 431 | Host.ShutdownServer(); 432 | SV.svs.serverflags = 0; 433 | SV.SpawnServer(Cmd.argv[1]); 434 | }; 435 | 436 | Host.Changelevel_f = function() 437 | { 438 | if (Cmd.argv.length !== 2) 439 | { 440 | Con.Print('changelevel : continue game on a new level\n'); 441 | return; 442 | } 443 | if (SV.server.active !== true) 444 | { 445 | Con.Print('Only the server may changelevel\n'); 446 | return; 447 | } 448 | SV.SaveSpawnparms(); 449 | SV.SpawnServer(Cmd.argv[1]); 450 | }; 451 | 452 | Host.Restart_f = function() 453 | { 454 | if ((SV.server.active === true) && (Cmd.client !== true)) 455 | SV.SpawnServer(PR.GetString(PR.globals_int[PR.globalvars.mapname])); 456 | }; 457 | 458 | Host.Name_f = function() 459 | { 460 | if ((Cmd.argv.length <= 1) || (Cmd.client !== true)) 461 | return; 462 | 463 | var newName; 464 | if (Cmd.argv.length === 2) 465 | newName = Cmd.argv[1].substring(0, 15); 466 | else 467 | newName = Cmd.args.substring(0, 15); 468 | 469 | var name = SV.GetClientName(Host.client); 470 | SV.SetClientName(Host.client, newName); 471 | var msg = SV.server.reliable_datagram; 472 | MSG.WriteByte(msg, Protocol.svc.updatename); 473 | MSG.WriteByte(msg, Host.client.num); 474 | MSG.WriteString(msg, newName); 475 | }; 476 | 477 | Host.Version_f = function() 478 | { 479 | Con.Print('Version 1.09\n'); 480 | Con.Print(Def.timedate); 481 | }; 482 | 483 | Host.Say = function(teamonly) 484 | { 485 | if (SV.server.active !== true) 486 | return; 487 | if (Cmd.argv.length <= 1) 488 | return; 489 | var save = Host.client; 490 | var p = Cmd.args; 491 | if (p.charCodeAt(0) === 34) 492 | p = p.substring(1, p.length - 1); 493 | if (Cmd.client === true) 494 | text = '\1' + SV.GetClientName(save) + ': '; 495 | else 496 | { 497 | text = '\1<' + NET.hostname.string + '> '; 498 | teamonly = false; 499 | } 500 | var i = 62 - text.length; 501 | if (p.length > i) 502 | p = p.substring(0, i); 503 | text += p + '\n'; 504 | var client; 505 | for (i = 0; i < SV.svs.maxclients; ++i) 506 | { 507 | client = SV.svs.clients[i]; 508 | if ((client.active !== true) || (client.spawned !== true)) 509 | continue; 510 | if ((Host.teamplay.value !== 0) && (teamonly === true) && (client.v_float[PR.entvars.team] !== save.v_float[PR.entvars.team])) 511 | continue; 512 | Host.client = client; 513 | Host.ClientPrint(text); 514 | } 515 | Host.client = save; 516 | Sys.Print(text.substring(1)); 517 | }; 518 | 519 | Host.Say_Team_f = function() 520 | { 521 | Host.Say(true); 522 | }; 523 | 524 | Host.Tell_f = function() 525 | { 526 | if (Cmd.client !== true) 527 | return; 528 | if (Cmd.argv.length <= 2) 529 | return; 530 | var text = SV.GetClientName(Host.client) + ': '; 531 | var p = Cmd.args; 532 | if (p.charCodeAt(0) === 34) 533 | p = p.substring(1, p.length - 1); 534 | var i = 62 - text.length; 535 | if (p.length > i) 536 | p = p.substring(0, i); 537 | text += p + '\n'; 538 | var save = Host.client, client; 539 | for (i = 0; i < SV.svs.maxclients; ++i) 540 | { 541 | client = SV.svs.clients[i]; 542 | if ((client.active !== true) || (client.spawned !== true)) 543 | continue; 544 | if (SV.GetClientName(client).toLowerCase() !== Cmd.argv[1].toLowerCase()) 545 | continue; 546 | Host.client = client; 547 | Host.ClientPrint(text); 548 | break; 549 | } 550 | Host.client = save; 551 | }; 552 | 553 | Host.Color_f = function() 554 | { 555 | if ((Cmd.argv.length <= 1) || (Cmd.client !== true)) 556 | return; 557 | 558 | var top, bottom; 559 | if (Cmd.argv.length === 2) 560 | top = bottom = (Q.atoi(Cmd.argv[1]) & 15) >>> 0; 561 | else 562 | { 563 | top = (Q.atoi(Cmd.argv[1]) & 15) >>> 0; 564 | bottom = (Q.atoi(Cmd.argv[2]) & 15) >>> 0; 565 | } 566 | if (top >= 14) 567 | top = 13; 568 | if (bottom >= 14) 569 | bottom = 13; 570 | var playercolor = (top << 4) + bottom; 571 | 572 | Host.client.colors = playercolor; 573 | Host.client.edict.v_float[PR.entvars.team] = bottom + 1; 574 | var msg = SV.server.reliable_datagram; 575 | MSG.WriteByte(msg, Protocol.svc.updatecolors); 576 | MSG.WriteByte(msg, Host.client.num); 577 | MSG.WriteByte(msg, playercolor); 578 | }; 579 | 580 | Host.Kill_f = function() 581 | { 582 | if (Cmd.client !== true) 583 | return; 584 | if (SV.player.v_float[PR.entvars.health] <= 0.0) 585 | { 586 | Host.ClientPrint('Can\'t suicide -- allready dead!\n'); 587 | return; 588 | } 589 | PR.globals_float[PR.globalvars.time] = SV.server.time; 590 | PR.globals_int[PR.globalvars.self] = SV.player.num; 591 | PR.ExecuteProgram(PR.globals_int[PR.globalvars.ClientKill]); 592 | }; 593 | 594 | Host.Pause_f = function() 595 | { 596 | if (Cmd.client !== true) 597 | return; 598 | if (Host.pausable.value === 0) 599 | { 600 | Host.ClientPrint('Pause not allowed.\n'); 601 | return; 602 | } 603 | SV.server.paused = !SV.server.paused; 604 | Host.BroadcastPrint(SV.GetClientName(Host.client) + (SV.server.paused === true ? ' paused the game\n' : ' unpaused the game\n')); 605 | MSG.WriteByte(SV.server.reliable_datagram, Protocol.svc.setpause); 606 | MSG.WriteByte(SV.server.reliable_datagram, SV.server.paused === true ? 1 : 0); 607 | }; 608 | 609 | Host.PreSpawn_f = function() 610 | { 611 | if (Cmd.client !== true) 612 | { 613 | Con.Print('prespawn is not valid from the console\n'); 614 | return; 615 | } 616 | var client = Host.client; 617 | if (client.spawned === true) 618 | { 619 | Con.Print('prespawn not valid -- allready spawned\n'); 620 | return; 621 | } 622 | SZ.Write(client.message, new Uint8Array(SV.server.signon.data), SV.server.signon.cursize); 623 | MSG.WriteByte(client.message, Protocol.svc.signonnum); 624 | MSG.WriteByte(client.message, 2); 625 | client.sendsignon = true; 626 | }; 627 | 628 | Host.Spawn_f = function() 629 | { 630 | if (Cmd.client !== true) 631 | { 632 | Con.Print('spawn is not valid from the console\n'); 633 | return; 634 | } 635 | var client = Host.client; 636 | if (client.spawned === true) 637 | { 638 | Con.Print('Spawn not valid -- allready spawned\n'); 639 | return; 640 | } 641 | 642 | var i; 643 | 644 | var ent = client.edict; 645 | for (i = 0; i < PR.entityfields; ++i) 646 | ent.v_int[i] = 0; 647 | ent.v_float[PR.entvars.colormap] = ent.num; 648 | ent.v_float[PR.entvars.team] = (client.colors & 15) + 1; 649 | ent.v_int[PR.entvars.netname] = PR.netnames + (client.num << 5); 650 | for (i = 0; i <= 15; ++i) 651 | PR.globals_float[PR.globalvars.parms + i] = client.spawn_parms[i]; 652 | PR.globals_float[PR.globalvars.time] = SV.server.time; 653 | PR.globals_int[PR.globalvars.self] = ent.num; 654 | PR.ExecuteProgram(PR.globals_int[PR.globalvars.ClientConnect]); 655 | if ((Sys.FloatTime() - client.netconnection.connecttime) <= SV.server.time) 656 | Sys.Print(SV.GetClientName(client) + ' entered the game\n'); 657 | PR.ExecuteProgram(PR.globals_int[PR.globalvars.PutClientInServer]); 658 | 659 | var message = client.message; 660 | message.cursize = 0; 661 | MSG.WriteByte(message, Protocol.svc.time); 662 | MSG.WriteFloat(message, SV.server.time); 663 | for (i = 0; i < SV.svs.maxclients; ++i) 664 | { 665 | client = SV.svs.clients[i]; 666 | MSG.WriteByte(message, Protocol.svc.updatename); 667 | MSG.WriteByte(message, i); 668 | MSG.WriteString(message, SV.GetClientName(client)); 669 | MSG.WriteByte(message, Protocol.svc.updatefrags); 670 | MSG.WriteByte(message, i); 671 | MSG.WriteShort(message, client.old_frags); 672 | MSG.WriteByte(message, Protocol.svc.updatecolors); 673 | MSG.WriteByte(message, i); 674 | MSG.WriteByte(message, client.colors); 675 | } 676 | for (i = 0; i <= 63; ++i) 677 | { 678 | MSG.WriteByte(message, Protocol.svc.lightstyle); 679 | MSG.WriteByte(message, i); 680 | MSG.WriteString(message, SV.server.lightstyles[i]); 681 | } 682 | MSG.WriteByte(message, Protocol.svc.updatestat); 683 | MSG.WriteByte(message, Def.stat.totalsecrets); 684 | MSG.WriteLong(message, PR.globals_float[PR.globalvars.total_secrets]); 685 | MSG.WriteByte(message, Protocol.svc.updatestat); 686 | MSG.WriteByte(message, Def.stat.totalmonsters); 687 | MSG.WriteLong(message, PR.globals_float[PR.globalvars.total_monsters]); 688 | MSG.WriteByte(message, Protocol.svc.updatestat); 689 | MSG.WriteByte(message, Def.stat.secrets); 690 | MSG.WriteLong(message, PR.globals_float[PR.globalvars.found_secrets]); 691 | MSG.WriteByte(message, Protocol.svc.updatestat); 692 | MSG.WriteByte(message, Def.stat.monsters); 693 | MSG.WriteLong(message, PR.globals_float[PR.globalvars.killed_monsters]); 694 | MSG.WriteByte(message, Protocol.svc.setangle); 695 | ent = SV.server.edicts[1 + Host.client.num]; 696 | MSG.WriteAngle(message, ent.v_float[PR.entvars.angles]); 697 | MSG.WriteAngle(message, ent.v_float[PR.entvars.angles1]); 698 | MSG.WriteAngle(message, 0.0); 699 | SV.WriteClientdataToMessage(ent, message); 700 | MSG.WriteByte(message, Protocol.svc.signonnum); 701 | MSG.WriteByte(message, 3); 702 | Host.client.sendsignon = true; 703 | }; 704 | 705 | Host.Begin_f = function() 706 | { 707 | if (Cmd.client !== true) 708 | { 709 | Con.Print('begin is not valid from the console\n'); 710 | return; 711 | } 712 | Host.client.spawned = true; 713 | }; 714 | 715 | Host.Kick_f = function() 716 | { 717 | if (SV.server.active !== true) 718 | return; 719 | if ((Cmd.client === true) && (PR.globals_float[PR.globalvars.deathmatch] !== 0.0)) 720 | return; 721 | var save = Host.client; 722 | var i, byNumber; 723 | if ((Cmd.argv.length >= 3) && (Cmd.argv[1] === '#')) 724 | { 725 | i = Q.atoi(Cmd.argv[2]) - 1; 726 | if ((i < 0) || (i >= SV.svs.maxclients)) 727 | return; 728 | if (SV.svs.clients[i].active !== true) 729 | return; 730 | Host.client = SV.svs.clients[i]; 731 | byNumber = true; 732 | } 733 | else 734 | { 735 | for (i = 0; i < SV.svs.maxclients; ++i) 736 | { 737 | Host.client = SV.svs.clients[i]; 738 | if (Host.client.active !== true) 739 | continue; 740 | if (SV.GetClientName(Host.client).toLowerCase() === Cmd.argv[1].toLowerCase()) 741 | break; 742 | } 743 | } 744 | if (i >= SV.svs.maxclients) 745 | { 746 | Host.client = save; 747 | return; 748 | } 749 | var who; 750 | if (Cmd.client !== true) 751 | who = 'Console'; 752 | else 753 | { 754 | if (Host.client === save) 755 | return; 756 | who = SV.GetClientName(save); 757 | } 758 | var message; 759 | if (Cmd.argv.length >= 3) 760 | message = COM.Parse(Cmd.args); 761 | if (message != null) 762 | { 763 | var p = 0; 764 | if (byNumber === true) 765 | { 766 | ++p; 767 | for (; p < message.length; ++p) 768 | { 769 | if (message.charCodeAt(p) !== 32) 770 | break; 771 | } 772 | p += Cmd.argv[2].length; 773 | } 774 | for (; p < message.length; ++p) 775 | { 776 | if (message.charCodeAt(p) !== 32) 777 | break; 778 | } 779 | Host.ClientPrint('Kicked by ' + who + ': ' + message.substring(p) + '\n'); 780 | } 781 | else 782 | Host.ClientPrint('Kicked by ' + who + '\n'); 783 | Host.DropClient(); 784 | Host.client = save; 785 | }; 786 | 787 | Host.Give_f = function() 788 | { 789 | if (Cmd.client !== true) 790 | return; 791 | if (PR.globals_float[PR.globalvars.deathmatch] !== 0) 792 | return; 793 | if (Cmd.argv.length <= 1) 794 | return; 795 | var t = Cmd.argv[1].charCodeAt(0); 796 | var ent = SV.player; 797 | 798 | if ((t >= 48) && (t <= 57)) 799 | { 800 | if (COM.hipnotic !== true) 801 | { 802 | if (t >= 50) 803 | ent.v_float[PR.entvars.items] |= Def.it.shotgun << (t - 50); 804 | return; 805 | } 806 | if (t === 54) 807 | { 808 | if (Cmd.argv[1].charCodeAt(1) === 97) 809 | ent.v_float[PR.entvars.items] |= Def.hit.proximity_gun; 810 | else 811 | ent.v_float[PR.entvars.items] |= Def.it.grenade_launcher; 812 | return; 813 | } 814 | if (t === 57) 815 | ent.v_float[PR.entvars.items] |= Def.hit.laser_cannon; 816 | else if (t === 48) 817 | ent.v_float[PR.entvars.items] |= Def.hit.mjolnir; 818 | else if (t >= 50) 819 | ent.v_float[PR.entvars.items] |= Def.it.shotgun << (t - 50); 820 | return; 821 | } 822 | var v = Q.atoi(Cmd.argv[2]); 823 | if (t === 104) 824 | { 825 | ent.v_float[PR.entvars.health] = v; 826 | return; 827 | } 828 | if (COM.rogue !== true) 829 | { 830 | switch (t) 831 | { 832 | case 115: 833 | ent.v_float[PR.entvars.ammo_shells] = v; 834 | return; 835 | case 110: 836 | ent.v_float[PR.entvars.ammo_nails] = v; 837 | return; 838 | case 114: 839 | ent.v_float[PR.entvars.ammo_rockets] = v; 840 | return; 841 | case 99: 842 | ent.v_float[PR.entvars.ammo_cells] = v; 843 | } 844 | return; 845 | } 846 | switch (t) 847 | { 848 | case 115: 849 | if (PR.entvars.ammo_shells1 != null) 850 | ent.v_float[PR.entvars.ammo_shells1] = v; 851 | ent.v_float[PR.entvars.ammo_shells] = v; 852 | return; 853 | case 110: 854 | if (PR.entvars.ammo_nails1 != null) 855 | { 856 | ent.v_float[PR.entvars.ammo_nails1] = v; 857 | if (ent.v_float[PR.entvars.weapon] <= Def.it.lightning) 858 | ent.v_float[PR.entvars.ammo_nails] = v; 859 | } 860 | return; 861 | case 108: 862 | if (PR.entvars.ammo_lava_nails != null) 863 | { 864 | ent.v_float[PR.entvars.ammo_lava_nails] = v; 865 | if (ent.v_float[PR.entvars.weapon] > Def.it.lightning) 866 | ent.v_float[PR.entvars.ammo_nails] = v; 867 | } 868 | return; 869 | case 114: 870 | if (PR.entvars.ammo_rockets1 != null) 871 | { 872 | ent.v_float[PR.entvars.ammo_rockets1] = v; 873 | if (ent.v_float[PR.entvars.weapon] <= Def.it.lightning) 874 | ent.v_float[PR.entvars.ammo_rockets] = v; 875 | } 876 | return; 877 | case 109: 878 | if (PR.entvars.ammo_multi_rockets != null) 879 | { 880 | ent.v_float[PR.entvars.ammo_multi_rockets] = v; 881 | if (ent.v_float[PR.entvars.weapon] > Def.it.lightning) 882 | ent.v_float[PR.entvars.ammo_rockets] = v; 883 | } 884 | return; 885 | case 99: 886 | if (PR.entvars.ammo_cells1 != null) 887 | { 888 | ent.v_float[PR.entvars.ammo_cells1] = v; 889 | if (ent.v_float[PR.entvars.weapon] <= Def.it.lightning) 890 | ent.v_float[PR.entvars.ammo_cells] = v; 891 | } 892 | return; 893 | case 112: 894 | if (PR.entvars.ammo_plasma != null) 895 | { 896 | ent.v_float[PR.entvars.ammo_plasma] = v; 897 | if (ent.v_float[PR.entvars.weapon] > Def.it.lightning) 898 | ent.v_float[PR.entvars.ammo_cells] = v; 899 | } 900 | } 901 | }; 902 | 903 | Host.Startdemos_f = function() 904 | { 905 | if (SV.server.active !== true) 906 | Cmd.text += 'map start\n'; 907 | }; 908 | 909 | Host.InitCommands = function() 910 | { 911 | Cmd.AddCommand('status', Host.Status_f); 912 | Cmd.AddCommand('quit', Host.Quit_f); 913 | Cmd.AddCommand('god', Host.God_f); 914 | Cmd.AddCommand('notarget', Host.Notarget_f); 915 | Cmd.AddCommand('fly', Host.Fly_f); 916 | Cmd.AddCommand('map', Host.Map_f); 917 | Cmd.AddCommand('restart', Host.Restart_f); 918 | Cmd.AddCommand('changelevel', Host.Changelevel_f); 919 | Cmd.AddCommand('name', Host.Name_f); 920 | Cmd.AddCommand('noclip', Host.Noclip_f); 921 | Cmd.AddCommand('version', Host.Version_f); 922 | Cmd.AddCommand('say', Host.Say); 923 | Cmd.AddCommand('say_team', Host.Say_Team_f); 924 | Cmd.AddCommand('tell', Host.Tell_f); 925 | Cmd.AddCommand('color', Host.Color_f); 926 | Cmd.AddCommand('kill', Host.Kill_f); 927 | Cmd.AddCommand('pause', Host.Pause_f); 928 | Cmd.AddCommand('spawn', Host.Spawn_f); 929 | Cmd.AddCommand('begin', Host.Begin_f); 930 | Cmd.AddCommand('prespawn', Host.PreSpawn_f); 931 | Cmd.AddCommand('kick', Host.Kick_f); 932 | Cmd.AddCommand('ping', Host.Ping_f); 933 | Cmd.AddCommand('give', Host.Give_f); 934 | Cmd.AddCommand('startdemos', Host.Startdemos_f); 935 | Cmd.AddCommand('mcache', Mod.Print); 936 | }; 937 | --------------------------------------------------------------------------------