├── mod ├── preql │ ├── client │ │ └── gfx_preql.coffee │ ├── server │ │ └── game.coffee │ ├── sprites │ │ ├── suit │ │ │ ├── suit.png │ │ │ ├── suit_walk.png │ │ │ └── suit_engine.png │ │ ├── sprites_nuu.json │ │ └── objects_nuu.json │ ├── build.coffee │ ├── build.json │ └── common │ │ ├── lib.coffee │ │ ├── map.coffee │ │ └── unit.coffee ├── nuu-mbt │ ├── star.png │ ├── star_spectrum.png │ ├── build.coffee │ ├── shader │ │ ├── planet.vert │ │ ├── atmosphere.frag │ │ ├── sun_corona.frag │ │ ├── asteroid.frag │ │ ├── asteroid.vert │ │ ├── earth.frag │ │ ├── mars.frag │ │ ├── sun.frag │ │ └── gas_giant.frag │ ├── render.html │ └── sysgen.coffee ├── nuu │ ├── artwork │ │ ├── nodejs.png │ │ ├── screw.png │ │ ├── loading.png │ │ ├── nuulogo.png │ │ ├── nuuseal.png │ │ ├── threejs.png │ │ ├── icon_2018.png │ │ ├── noscanimg.png │ │ ├── vendor_logos1.png │ │ ├── logo_2018_2.svg │ │ ├── nginx.svg │ │ ├── noscanimg.svg │ │ ├── logo_2018.svg │ │ └── icon_2018.svg │ ├── sprites │ │ ├── com │ │ │ ├── tau.png │ │ │ ├── faypoe.png │ │ │ ├── gforce.png │ │ │ ├── jetson.png │ │ │ ├── russels.png │ │ │ ├── greywash.png │ │ │ ├── valkyrie.png │ │ │ ├── ganymede_gas.png │ │ │ ├── solarsuits.png │ │ │ ├── taikuipment.png │ │ │ ├── siriusrobotics.png │ │ │ ├── admiralassembly.png │ │ │ ├── tepeshkovalaser.png │ │ │ └── ponomarevagaussgun.png │ │ ├── gov │ │ │ ├── chs.png │ │ │ ├── hks.png │ │ │ └── hks.svg │ │ ├── suit │ │ │ ├── suit.png │ │ │ ├── st_suit.png │ │ │ ├── suit_engine.png │ │ │ ├── suit_walk.png │ │ │ ├── st_suit_engine.png │ │ │ └── rotateStitch.sh │ │ ├── sprites_nuu.json │ │ └── objects_nuu.json │ ├── soundtrack │ │ ├── nuutheme_mk1.ogg │ │ ├── nuutheme_mk2.ogg │ │ ├── nuutheme_mk3.ogg │ │ ├── nuutheme_mk4.ogg │ │ ├── nuutheme_mk5.ogg │ │ └── nuutheme_mk5.opus │ ├── build.json │ ├── build.coffee │ ├── client │ │ ├── gui_nuu.coffee │ │ ├── autopilot.coffee │ │ ├── starfield.coffee │ │ ├── render.coffee │ │ └── target.coffee │ ├── server │ │ ├── engine.coffee │ │ └── objects.coffee │ └── common │ │ └── asteroid.coffee ├── nuu-dm │ ├── build.json │ ├── common │ │ └── dm.coffee │ └── client │ │ └── dm.coffee ├── core │ ├── client │ │ ├── tile.coffee │ │ ├── animation.coffee │ │ ├── explosion.coffee │ │ ├── debug.coffee │ │ ├── user.coffee │ │ ├── cache.coffee │ │ ├── client.coffee │ │ ├── vt100.coffee │ │ └── keyboard.coffee │ ├── server │ │ ├── console.coffee │ │ ├── db.coffee │ │ ├── start.coffee │ │ └── ids.coffee │ ├── build.json │ └── common │ │ ├── surface.coffee │ │ ├── error.coffee │ │ ├── item.coffee │ │ ├── buffer.coffee │ │ ├── inventory.coffee │ │ ├── ping.coffee │ │ ├── station.coffee │ │ ├── worker.coffee │ │ └── stellar.coffee └── nuu-naev │ └── build.coffee ├── nuu.json ├── screenshot0.png ├── screenshot1.png ├── screenshot3.png ├── pd ├── index.js ├── package.json ├── sync.js ├── import.js ├── index_map.js ├── schema.js ├── cursor.js ├── record.js └── database.js ├── Makefile ├── .gitignore ├── tools ├── import_npm.coffee ├── import_git.coffee └── dev_autobuild.coffee └── package.json /mod/preql/client/gfx_preql.coffee: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nuu.json: -------------------------------------------------------------------------------- 1 | { "mod":["nuu","nuu-naev","nuu-dm"] } 2 | -------------------------------------------------------------------------------- /screenshot0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/screenshot0.png -------------------------------------------------------------------------------- /screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/screenshot1.png -------------------------------------------------------------------------------- /screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/screenshot3.png -------------------------------------------------------------------------------- /mod/nuu-mbt/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu-mbt/star.png -------------------------------------------------------------------------------- /mod/preql/server/game.coffee: -------------------------------------------------------------------------------- 1 | 2 | do NUU.init -> 3 | NUU.map = new URMap 4 | @start() 5 | -------------------------------------------------------------------------------- /mod/nuu/artwork/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/nodejs.png -------------------------------------------------------------------------------- /mod/nuu/artwork/screw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/screw.png -------------------------------------------------------------------------------- /mod/nuu/artwork/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/loading.png -------------------------------------------------------------------------------- /mod/nuu/artwork/nuulogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/nuulogo.png -------------------------------------------------------------------------------- /mod/nuu/artwork/nuuseal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/nuuseal.png -------------------------------------------------------------------------------- /mod/nuu/artwork/threejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/threejs.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/tau.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/tau.png -------------------------------------------------------------------------------- /mod/nuu/sprites/gov/chs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/gov/chs.png -------------------------------------------------------------------------------- /mod/nuu/sprites/gov/hks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/gov/hks.png -------------------------------------------------------------------------------- /mod/nuu-mbt/star_spectrum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu-mbt/star_spectrum.png -------------------------------------------------------------------------------- /mod/nuu/artwork/icon_2018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/icon_2018.png -------------------------------------------------------------------------------- /mod/nuu/artwork/noscanimg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/noscanimg.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/faypoe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/faypoe.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/gforce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/gforce.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/jetson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/jetson.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/russels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/russels.png -------------------------------------------------------------------------------- /mod/nuu/sprites/suit/suit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/suit/suit.png -------------------------------------------------------------------------------- /mod/preql/sprites/suit/suit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/preql/sprites/suit/suit.png -------------------------------------------------------------------------------- /mod/nuu/artwork/vendor_logos1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/artwork/vendor_logos1.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/greywash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/greywash.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/valkyrie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/valkyrie.png -------------------------------------------------------------------------------- /mod/nuu/sprites/suit/st_suit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/suit/st_suit.png -------------------------------------------------------------------------------- /mod/nuu/soundtrack/nuutheme_mk1.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/soundtrack/nuutheme_mk1.ogg -------------------------------------------------------------------------------- /mod/nuu/soundtrack/nuutheme_mk2.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/soundtrack/nuutheme_mk2.ogg -------------------------------------------------------------------------------- /mod/nuu/soundtrack/nuutheme_mk3.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/soundtrack/nuutheme_mk3.ogg -------------------------------------------------------------------------------- /mod/nuu/soundtrack/nuutheme_mk4.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/soundtrack/nuutheme_mk4.ogg -------------------------------------------------------------------------------- /mod/nuu/soundtrack/nuutheme_mk5.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/soundtrack/nuutheme_mk5.ogg -------------------------------------------------------------------------------- /mod/nuu/soundtrack/nuutheme_mk5.opus: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/soundtrack/nuutheme_mk5.opus -------------------------------------------------------------------------------- /mod/nuu/sprites/com/ganymede_gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/ganymede_gas.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/solarsuits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/solarsuits.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/taikuipment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/taikuipment.png -------------------------------------------------------------------------------- /mod/nuu/sprites/suit/suit_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/suit/suit_engine.png -------------------------------------------------------------------------------- /mod/nuu/sprites/suit/suit_walk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/suit/suit_walk.png -------------------------------------------------------------------------------- /mod/preql/sprites/suit/suit_walk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/preql/sprites/suit/suit_walk.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/siriusrobotics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/siriusrobotics.png -------------------------------------------------------------------------------- /mod/preql/sprites/suit/suit_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/preql/sprites/suit/suit_engine.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/admiralassembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/admiralassembly.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/tepeshkovalaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/tepeshkovalaser.png -------------------------------------------------------------------------------- /mod/nuu/sprites/suit/st_suit_engine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/suit/st_suit_engine.png -------------------------------------------------------------------------------- /mod/nuu/sprites/com/ponomarevagaussgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hakt0r/nuu/HEAD/mod/nuu/sprites/com/ponomarevagaussgun.png -------------------------------------------------------------------------------- /mod/nuu-dm/build.json: -------------------------------------------------------------------------------- 1 | { "client":{"sources":["dm","dm_gui"]}, 2 | "server":{"sources":["dm"]}, 3 | "common":{"sources":["dm"]}} 4 | -------------------------------------------------------------------------------- /mod/preql/build.coffee: -------------------------------------------------------------------------------- 1 | 2 | module.exports.build = (c)-> depend(contrib,sources)( -> 3 | $s [ 4 | mkdir 'build' 5 | ], c ) 6 | -------------------------------------------------------------------------------- /mod/nuu-mbt/build.coffee: -------------------------------------------------------------------------------- 1 | 2 | module.exports.stages = 3 | sysgen: (c)-> depend(assets)(-> exec("coffee mod/nuu-mbt/sysgen.coffee")(c)) 4 | -------------------------------------------------------------------------------- /mod/preql/sprites/sprites_nuu.json: -------------------------------------------------------------------------------- 1 | { 2 | "st_suit": { "size": 24, "cols":6 }, 3 | "st_suit_engine": { "size": 24, "cols":6 } 4 | } 5 | -------------------------------------------------------------------------------- /pd/index.js: -------------------------------------------------------------------------------- 1 | 2 | const Database = require("./database"); 3 | const Schema = require("./schema"); 4 | 5 | Database.Schema = Schema; 6 | module.exports = Database; -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/planet.vert: -------------------------------------------------------------------------------- 1 | 2 | varying vec3 vNormal; 3 | varying vec2 vTex; 4 | 5 | void main() { 6 | vNormal = normal; 7 | vTex = uv; 8 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 9 | } 10 | -------------------------------------------------------------------------------- /pd/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pd", 3 | "version": "1.0.0", 4 | "description": "monogdb drop in", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "anx@hktr.de", 10 | "license": "MIT" 11 | } 12 | -------------------------------------------------------------------------------- /mod/nuu/artwork/logo_2018_2.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /mod/nuu/build.json: -------------------------------------------------------------------------------- 1 | { "client": { 2 | "sources":[ 3 | "starfield", 4 | "controls", 5 | "autopilot", 6 | "gui_nuu", 7 | "gfx_nuu", 8 | "hud", 9 | "scanner", 10 | "target", 11 | "sound"]}, 12 | "common":{ 13 | "sources": [ 14 | "asteroid"]}, 15 | "server":{ 16 | "require":[ 17 | ["NameGen","random-ship-names"]], 18 | "sources": [ 19 | "engine", 20 | "objects"]}} 21 | -------------------------------------------------------------------------------- /mod/preql/build.json: -------------------------------------------------------------------------------- 1 | { "client": { 2 | "contrib": { 3 | "sm2.js": { 4 | "name": "SoundManager 2", 5 | "homepage": "http://www.schillmania.com/projects/soundmanager2/", 6 | "url": "https://raw.github.com/scottschiller/SoundManager2/master/script/soundmanager2-nodebug-jsmin.js"}}, 7 | "sources":[ "gfx_preql", "gui_preql" ], 8 | "scripts":["sm2.js"]}, 9 | "common": { 10 | "sources":[ "lib", "map", "unit" ] 11 | }} 12 | -------------------------------------------------------------------------------- /mod/nuu-mbt/render.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 |
nuu/sysgen.coffee
11 | 
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/atmosphere.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D tex0; 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform float time; 5 | uniform float temperature; 6 | uniform vec3 light; 7 | varying vec3 vNormal; 8 | varying vec2 vTex; 9 | 10 | 11 | void main(void){ 12 | vec3 l = normalize( light - vNormal.xyz ) * .2; 13 | float d = abs(length(vTex-vec2(.5,.5)) * 2.); 14 | d = d > .5 ? 0. : max(0.,d-1.)*100.; 15 | float c = d; 16 | gl_FragColor.rgba = vec4(c,c,c,d); 17 | } 18 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/sun_corona.frag: -------------------------------------------------------------------------------- 1 | 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform vec4 temperature; 5 | uniform float time; 6 | uniform vec3 light; 7 | 8 | varying vec3 vNormal; 9 | varying vec2 vTex; 10 | 11 | void main(void){ 12 | vec3 color = temperature.rgb; 13 | float d = length(vTex-vec2(.5,.5)) * 4.0; 14 | float b = (1.0 / (d * d) - 0.1) * .7; 15 | float c = 1.-min(1.,d); 16 | d = max(.5,d-.3); 17 | gl_FragColor = vec4(color,1.) * vec4(c,c,c,d); 18 | } 19 | -------------------------------------------------------------------------------- /mod/preql/common/lib.coffee: -------------------------------------------------------------------------------- 1 | 2 | $static 'ab2str', (buf) -> 3 | String.fromCharCode.apply null, new Uint16Array(buf) 4 | 5 | $static 'str2ab', (str) -> 6 | buf = new ArrayBuffer(str.length * 2) # 2 bytes for each char 7 | bufView = new Uint16Array(buf) 8 | i = 0 9 | strLen = str.length 10 | 11 | while i < strLen 12 | bufView[i] = str.charCodeAt(i) 13 | i++ 14 | buf 15 | 16 | Array.shuffle = (o) -> 17 | j = undefined 18 | x = undefined 19 | i = o.length 20 | while i 21 | j = Math.floor(Math.random() * i) 22 | x = o[--i] 23 | o[i] = o[j] 24 | o[j] = x 25 | o 26 | -------------------------------------------------------------------------------- /mod/nuu/sprites/suit/rotateStitch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | infile="suit.png" 4 | incr=10 5 | inname=`convert "$infile" -format "%t" info:` 6 | 7 | rm -rf out 8 | mkdir out/ 9 | 10 | 11 | x=1 12 | for ((i=90; i<=460; i=i+incr)); do 13 | convert "$infile" -background transparent -distort ScaleRotateTranslate $i +repage out/${inname}_$x.png 14 | ((x++)); 15 | done 16 | 17 | sync 18 | 19 | montage -tile 6x6 \ 20 | out/${inname}_{1,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2}.png \ 21 | -geometry 24x24+0+0 -background transparent \ 22 | st_${inname}.png -------------------------------------------------------------------------------- /mod/nuu/build.coffee: -------------------------------------------------------------------------------- 1 | 2 | module.exports.build = (c)-> depend(contrib,sources)( -> 3 | $s [ 4 | mkdir 'build/imag' 5 | link 'mod/nuu/sprites/objects_nuu.json', 'build/objects_nuu.json' 6 | link 'mod/nuu/sprites/sprites_nuu.json', 'build/imag/sprites_nuu.json' 7 | link 'mod/nuu/client/gui.css', 'build/gui.css' 8 | linkFilesIn 'mod/nuu/artwork', 'build/imag' 9 | convFilesIn 'mod/nuu/sprites/com', 'build/gfx' 10 | convFilesIn 'mod/nuu/sprites/gov', 'build/gfx' 11 | linkFlatten 'mod/nuu/sprites', 'build/gfx' 12 | (c)-> c null, await iconsFrom 'mod/nuu/artwork/icon_2018.png', 'build/' 13 | ], c ) 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | update-demo: 3 | ssh root@rop.hktr.de '\ 4 | cd /var/www/nuu; \ 5 | killall node; \ 6 | git pull; \ 7 | coffee tools/build.coffee run >/dev/null 2>&1 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | -------------------------------------------------------------------------------- /mod/core/client/animation.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | -------------------------------------------------------------------------------- /mod/core/client/explosion.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | -------------------------------------------------------------------------------- /mod/nuu-dm/common/dm.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | rules.dm = 24 | modeName: 'deathmatch' 25 | modeNameShort: 'dm' 26 | systemName: 'sol' 27 | -------------------------------------------------------------------------------- /mod/core/client/debug.coffee: -------------------------------------------------------------------------------- 1 | 2 | NUU.on 'debug', -> 3 | Kbd.macro 'build', 'KeyB', 'Show debug build menu', -> new Window.dbgStation 4 | Kbd.macro 'ships', 'sKeyB', 'Show debug ship menu', -> new Window.dbgShips 5 | 6 | Window.dbgShips = class DebugShipWindow extends ModalListWindow 7 | name: 'dbg_ship' 8 | title: 'Ships' 9 | subject: Item.byType.ship 10 | closeKey: 'sKeyS' 11 | fetch:(done)-> 12 | NET.json.write unlocks:'' 13 | NET.once 'unlocks', (@filter)=> 14 | window.UNLOCKS = @filter 15 | done @subject 16 | null 17 | render: (key,val)-> 18 | Render.Ship.call @, key, val, @close.bind @ if @filter[val.name] 19 | null 20 | 21 | Window.dbgStation = class DebugBuildWindow extends ModalListWindow 22 | name: 'dbg_build' 23 | title: 'Station' 24 | subject: Item.byType.station 25 | closeKey: 'aKeyS' 26 | render: (key,val)-> 27 | Render.Station.call @,key, val, @close.bind @ 28 | null 29 | -------------------------------------------------------------------------------- /mod/nuu/sprites/sprites_nuu.json: -------------------------------------------------------------------------------- 1 | { 2 | "st_suit": { "size": 24, "width":144, "height":144, "count": 36, "cols":6, "rows": 6 }, 3 | "st_suit_engine": { "size": 24, "width":144, "height":144, "count": 36, "cols":6, "rows": 6 }, 4 | "chs": { "type":"gov" }, 5 | "hks": { "type":"gov" }, 6 | "admiralassembly": { "type":"com" }, 7 | "faypoe": { "type":"com" }, 8 | "ganymede_gas": { "type":"com" }, 9 | "gforce": { "type":"com" }, 10 | "greywash": { "type":"com" }, 11 | "jetson": { "type":"com" }, 12 | "ponomarevagaussgun": { "type":"com" }, 13 | "russels": { "type":"com" }, 14 | "siriusrobotics": { "type":"com" }, 15 | "solarsuits": { "type":"com" }, 16 | "taikuipment": { "type":"com" }, 17 | "tau": { "type":"com" }, 18 | "tepeshkovalaser": { "type":"com" }, 19 | "valkyrie": { "type":"com" } 20 | } 21 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/asteroid.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D tex0; 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform float time; 5 | uniform float temperature; 6 | uniform vec3 light; 7 | 8 | varying vec3 vNormal; 9 | varying vec2 vTex; 10 | varying float vElevator; 11 | varying float vNoiser; 12 | 13 | float shading(vec3 position){ 14 | vec3 l = normalize(light); 15 | return max(0.015, dot(position, l)); } 16 | 17 | void main() { 18 | vec2 p = vTex; 19 | vec4 c = vec4(vElevator,vElevator,vElevator,1.); 20 | if ( vElevator > 0.9 ) { c += vec4(vElevator,vElevator*.3,vElevator+vNoiser,1.);} 21 | else if ( vElevator > 0.3 ) { c += vec4(vElevator*.2+vNoiser,vElevator+vNoiser,vElevator,1.);} 22 | else if ( vElevator > 0.205 ) { c += vec4(1.,vElevator,0.,1.);} 23 | else if ( vElevator > 0.2 ) { c += vec4(.8,vNoiser*.7,vElevator*.3,1.);} 24 | else { c += vec4(.1,vNoiser*.05,vNoiser*.5,1.);} 25 | gl_FragColor = vec4( c.xyz * shading(vNormal.xyz), 1.);} 26 | -------------------------------------------------------------------------------- /mod/nuu-dm/client/dm.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | rules.dm.client = -> 24 | NUU.on 'ship:spawn', (ship) -> 25 | ship.reset() 26 | 27 | NET.on 'stats', (v) -> for id, stat of v 28 | notice 5000, stat.name + " K: #{stat.k} D: #{stat.d}" 29 | 30 | NUU.emit 'rules', rules 31 | -------------------------------------------------------------------------------- /mod/nuu/artwork/nginx.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 11 | 13 | 15 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /mod/core/server/console.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | console.rlog = console.log 24 | console.rerror = console.error 25 | 26 | console.error = (args...)-> 27 | args.unshift '['+'nuu'.red.inverse+']' 28 | @rlog.apply console, args 29 | 30 | console.log = (args...)-> 31 | args.unshift '['+'nuu'.blue.inverse+']' 32 | @rlog.apply console, args 33 | 34 | console.debug = (args...) -> # if argv.debug 35 | args.unshift '['+'nuu'.blue.inverse+']' 36 | @rlog.apply console, args 37 | 38 | console.dump = (msg='Error',error) -> 39 | @rlog.call console, '['+'nuu'.red.inverse+':'+msg.red.inverse+']', error.stack.white.bold 40 | process.exit 42 41 | -------------------------------------------------------------------------------- /pd/sync.js: -------------------------------------------------------------------------------- 1 | 2 | require('colors') 3 | const { join } = require("path"); 4 | const { promises: { writeFile } } = require("fs"); 5 | 6 | module.exports = class Sync { 7 | constructor(db, prev) { 8 | this.db = db; 9 | this.value = {}; 10 | this.promise = new Promise((resolve) => (this.resolve = resolve)); 11 | if (prev) this.prev = prev; 12 | else { 13 | this.prev = { promise: Promise.resolve() }; 14 | db.nextSync = this; 15 | } 16 | } 17 | add(key, value) { 18 | this.value[key] = value; 19 | this.trigger || (this.trigger = setImmediate(this.write)); 20 | return this.promise; 21 | } 22 | write = async () => { 23 | const { db, prev, value } = this; 24 | const { path, stringify = [] } = db; 25 | const time = Date.now(); 26 | const recs = Object.entries(value); 27 | db.nextSync = new Sync(db, this); 28 | this.add = () => console.error("pd writing to a dead sync"); 29 | await prev.promise; 30 | await Promise.all( 31 | recs.map(([key, value]) => { 32 | const file = join(path, key + ".json"); 33 | const json = JSON.stringify(value, ...stringify); 34 | return writeFile(file, json); 35 | }) 36 | ); 37 | console.debug( 38 | `${'pd'.gray} ${this.db.path.white.bold} ${'sync complete:'.gray}`, 39 | Math.round(recs.length / ((Date.now() - time) / 1000)), 40 | "r/s".gray 41 | ); 42 | this.resolve(true); 43 | }; 44 | } -------------------------------------------------------------------------------- /mod/core/build.json: -------------------------------------------------------------------------------- 1 | { "client":{ 2 | "require": [ 3 | ["Crypto","crypto"], 4 | ["EventEmitter","eventemitter3","EventEmitter"], 5 | ["Buffer","buffer","Buffer"], 6 | ["$","jquery"], 7 | ["$v","vectors"]], 8 | "libs": [ 9 | "eventemitter3", 10 | "crypto", 11 | "events", 12 | "jquery", 13 | "buffer", 14 | "vectors"], 15 | "sources": [ 16 | "keyboard", 17 | "cache", 18 | "gfx", 19 | "gui", 20 | "vt100", 21 | "user", 22 | "net", 23 | "sprite", 24 | "tile", 25 | "animation", 26 | "explosion", 27 | "debug", 28 | "client"], 29 | "scripts": [ 30 | "three.js", 31 | "lib.js", 32 | "client.js"]}, 33 | "server":{ 34 | "require": [ 35 | "util", 36 | "colors", 37 | "crypto", 38 | "express", 39 | "ws", 40 | "fs", 41 | "path", 42 | ["Crypto","crypto"], 43 | ["EventEmitter","eventemitter3","EventEmitter"], 44 | ["$v","vectors"], 45 | ["$tag","pd"]], 46 | "sources": [ 47 | "ids", 48 | "server", 49 | "db", 50 | "user", 51 | "console", 52 | "http", 53 | "start"]}, 54 | "common":{ 55 | "sources":[ 56 | "buffer", 57 | "engine", 58 | "error", 59 | "worker", 60 | "objects", 61 | "inventory", 62 | "economy", 63 | "stellar", 64 | "station", 65 | "state", 66 | "net", 67 | "ping", 68 | "elements", 69 | "navcom", 70 | "ship", 71 | "ai", 72 | "item", 73 | "weapon"]}} 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | db 2 | build 3 | node_modules 4 | contrib 5 | TODO 6 | mod/nuu/sprites/suit/out/suit_1.png 7 | mod/nuu/sprites/suit/out/suit_2.png 8 | mod/nuu/sprites/suit/out/suit_3.png 9 | mod/nuu/sprites/suit/out/suit_4.png 10 | mod/nuu/sprites/suit/out/suit_5.png 11 | mod/nuu/sprites/suit/out/suit_6.png 12 | mod/nuu/sprites/suit/out/suit_7.png 13 | mod/nuu/sprites/suit/out/suit_8.png 14 | mod/nuu/sprites/suit/out/suit_9.png 15 | mod/nuu/sprites/suit/out/suit_10.png 16 | mod/nuu/sprites/suit/out/suit_11.png 17 | mod/nuu/sprites/suit/out/suit_12.png 18 | mod/nuu/sprites/suit/out/suit_13.png 19 | mod/nuu/sprites/suit/out/suit_14.png 20 | mod/nuu/sprites/suit/out/suit_15.png 21 | mod/nuu/sprites/suit/out/suit_16.png 22 | mod/nuu/sprites/suit/out/suit_17.png 23 | mod/nuu/sprites/suit/out/suit_18.png 24 | mod/nuu/sprites/suit/out/suit_19.png 25 | mod/nuu/sprites/suit/out/suit_20.png 26 | mod/nuu/sprites/suit/out/suit_21.png 27 | mod/nuu/sprites/suit/out/suit_22.png 28 | mod/nuu/sprites/suit/out/suit_23.png 29 | mod/nuu/sprites/suit/out/suit_24.png 30 | mod/nuu/sprites/suit/out/suit_25.png 31 | mod/nuu/sprites/suit/out/suit_26.png 32 | mod/nuu/sprites/suit/out/suit_27.png 33 | mod/nuu/sprites/suit/out/suit_28.png 34 | mod/nuu/sprites/suit/out/suit_29.png 35 | mod/nuu/sprites/suit/out/suit_30.png 36 | mod/nuu/sprites/suit/out/suit_31.png 37 | mod/nuu/sprites/suit/out/suit_32.png 38 | mod/nuu/sprites/suit/out/suit_33.png 39 | mod/nuu/sprites/suit/out/suit_34.png 40 | mod/nuu/sprites/suit/out/suit_35.png 41 | mod/nuu/sprites/suit/out/suit_36.png 42 | mod/nuu/sprites/suit/out/suit_37.png 43 | mod/nuu/sprites/suit/out/suit_38.png 44 | -------------------------------------------------------------------------------- /pd/import.js: -------------------------------------------------------------------------------- 1 | 2 | const Database = require("./database"); 3 | const Schema = require("./schema"); 4 | 5 | async function monogoImport() { 6 | require("dotenv").config(); 7 | var MongoClient = require("mongodb").MongoClient; 8 | const c = await MongoClient.connect(process.env.DB, { 9 | useNewUrlParser: true, 10 | useUnifiedTopology: true, 11 | }); 12 | const d = await c.db("ax-zone"); 13 | const collections = (await (await d.listCollections()).toArray()).map( 14 | (c) => c.name 15 | ); 16 | const db = {}, all = {}, list = {}; 17 | await Promise.all( collections.map(async (c) => { 18 | const cname = c[0].toUpperCase() + c.replace(/s$/,'').substring(1); 19 | const q = await d.collection(c).find(); 20 | all[c] = await q.toArray(); 21 | db[c] = Database.create({ path: "config/" + c, stringify: [null, 2] }); 22 | await db[c].ready; 23 | all[c].forEach(v=>list[v._id] =v); 24 | console.log( cname.blue.bold ); 25 | })); 26 | const getRefId = o => o?.name || o?.fqdn || o?._id; 27 | const getRefs = o => Object.entries(o).forEach(getRef(o)); 28 | const getRef = o => ([k,v]) => { 29 | if ( v?.toString()?.length == 24 ) o[k] = getRefId(list[v]); 30 | else if ( Array.isArray(v) ) v.forEach((x,k)=>getRef(v)([k,x])); 31 | else if ( typeof v === 'object' ) getRefs(v); 32 | } 33 | await Promise.all( collections.map((c) => all[c].map(({ _id, __v, ...item }) => { 34 | const name = getRefId({_id,...item}); 35 | getRefs(item); 36 | console.log(' -'.bold, c.blue.bold, _id.toString().match(/(.{4})$/)[1], name ); 37 | return db[c].set(name, item); 38 | }))); 39 | } 40 | 41 | 42 | monogoImport(); -------------------------------------------------------------------------------- /mod/core/common/surface.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | Stellar::genMap = -> 24 | vm = require('voronoi-map') 25 | map = vm.map width: 1000.0, height: 1000.0 26 | map.newIsland(vm.islandShape.makeRadial(1), 1) 27 | 28 | map.go0PlacePoints(100) 29 | map.go1ImprovePoints() 30 | map.go2BuildGraph() 31 | map.assignBiomes() 32 | map.go3AssignElevations() 33 | map.go4AssignMoisture() 34 | map.go5DecorateMap() 35 | 36 | lava = vm.lava() 37 | roads = vm.roads() 38 | roads.createRoads(map, [0, 0.05, 0.37, 0.64]) 39 | watersheds = vm.watersheds() 40 | watersheds.createWatersheds(map) 41 | noisyEdges = vm.noisyEdges() 42 | noisyEdges.buildNoisyEdges(map, lava, map.mapRandom.seed) 43 | @map = map 44 | 45 | Stellar::renderMap = (c) -> 46 | vm.canvasRender.graphicsReset(c, map.SIZE.width, map.SIZE.height, vm.style.displayColors) 47 | vm.canvasRender.renderDebugPolygons(c, map, vm.style.displayColors) 48 | -------------------------------------------------------------------------------- /pd/index_map.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = class Index { 3 | 4 | constructor(db, keyPath) { 5 | 6 | this.db = db; 7 | this.keyPath = keyPath; 8 | this.map = new Map(); 9 | const k = keyPath.split("."); 10 | const n = "by" + k.map((v) => v[0].toUpperCase() + v.substring(1)).join(""); 11 | this.readPath = eval(`(k,o) => o?.['${k.join("']?.['")}']`); 12 | 13 | this.consume = ([k, o]) => { 14 | console.log('i+',k); 15 | const v = this.readPath(k, o); 16 | let set = this.map.get(v); 17 | if (set) set.add(k); 18 | else { 19 | set = new Set(); 20 | set.add(k); 21 | this.map.set(v, set); 22 | } 23 | }; 24 | 25 | db[n] = this; 26 | db.indexes.push(this); 27 | 28 | this.initialized = db 29 | .each(this.consume) 30 | .then( 31 | (o) => console.debug("indexed", keyPath, Object.keys(this.map)) || true 32 | ); 33 | } 34 | 35 | delete(k,o) { 36 | const v = this.readPath(k, o); 37 | let set = this.map.get(v); 38 | if (set) set.delete(k); 39 | } 40 | 41 | purge(k,o) { 42 | this.map = new Map(); 43 | } 44 | 45 | all() { 46 | const values = Array.from(this.map.values()); 47 | return Promise.all( 48 | values.map((set) => Array.from(set).map((k) => this.db.get(k))).flat() 49 | ); 50 | } 51 | 52 | keys() { 53 | const values = Array.from(this.map.values()); 54 | return Promise.all( 55 | values.map((set) => Array.from(set)).flat() 56 | ); 57 | } 58 | 59 | each(fn) { 60 | const values = Array.from(this.map.values()); 61 | return Promise.all( 62 | values 63 | .map((set) => 64 | Array.from(set).map(async (k) => await fn(k, await this.db.get(k))) 65 | ) 66 | .flat() 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tools/import_npm.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2020 Sebastian Glaser 4 | * c) 2007-2020 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | module.exports = (destinationFile,callback)-> 24 | fs = require 'fs' 25 | o = '
    ' 26 | d = JSON.parse fs.readFileSync 'package.json', 'utf8' 27 | for lib, data of TARGETS.client.contrib 28 | o += """ 29 |
  • #{data.name} (build/#{lib})master/git
  • 30 | """ 31 | for k in fs.readdirSync 'node_modules' 32 | if fs.existsSync 'node_modules/' + k + '/package.json' 33 | rec = JSON.parse fs.readFileSync 'node_modules/' + k + '/package.json' 34 | v = rec.version 35 | else if d.dependencies[k] then v = d.dependencies[k] 36 | else continue 37 | o += """
  • #{k}""" 38 | o += """#{v}""" 39 | # o += """#{rec.description}""" if rec.description 40 | o += "
  • " 41 | o += '
' 42 | fs.writeFileSync destinationFile, o 43 | callback null 44 | -------------------------------------------------------------------------------- /mod/preql/sprites/objects_nuu.json: -------------------------------------------------------------------------------- 1 | { "ship": [ 2 | 3 | { "name":"Human","sprite":"st_suit", 4 | "slots":{ 5 | "structure":[{"size":"suit","default":"Human Skin"}], 6 | "utility":[{"size":"suit","default":"Human Heart"}], 7 | "weapon":[{"size":"suit","default":"Stock Multitool"}]}, 8 | "stats":{ 9 | "crew":1, 10 | "mass":1, 11 | "fuel_consumption":0} }, 12 | 13 | { "name":"Exosuit","sprite":"st_suit", 14 | "slots":{ 15 | "structure":[ 16 | {"size":"suit","default":"Stock Fabric"}, 17 | {"size":"suit","default":"Stock ExoThrusters"} 18 | ], 19 | "utility":[], 20 | "weapon":[{"size":"suit","default":"StockMultitool"}]}, 21 | "stats":{ 22 | "crew":1, 23 | "mass":1, 24 | "fuel_consumption":0} } 25 | 26 | ], "outf": [ 27 | 28 | { "name" : "Stock ExoThrusters", 29 | "size" : "suit", 30 | "itemId": 500, 31 | "stats" : { 32 | "mass" : 15, 33 | "price" : 0, 34 | "thrust" : 100, 35 | "turn" : 85, 36 | "engine_limit" : 300, 37 | "energy_usage" : 5, 38 | "fuel" : 200, 39 | "speed" : 175 40 | }, 41 | "type" : "modification", 42 | "info" : { 43 | "description" : "Clogged, corroded and cracked in every way possible while still remaining in functional condition, this engine really belongs on the scrap heap.", 44 | "name" : "Stock ExoThrusters", 45 | "gfx_store" : "engine04" 46 | }, 47 | "slot" : { "prop" : "engines", "$t" : "structure" }, 48 | "extends" : "Outfit" }, 49 | 50 | { "name" : "Stock Fabric", 51 | "size" : "suit", 52 | "itemId": 501, 53 | "stats" : { 54 | "armour": 10, 55 | "mass": 1, 56 | "cargo": 0 57 | }, 58 | "type" : "modification", 59 | "info" : { 60 | "description" : "A rag, really.", 61 | "name" : "Stock Fabric", 62 | "gfx_store" : "engine04" 63 | }, 64 | "slot" : { "prop" : "hull", "$t" : "structure" }, 65 | "extends" : "Outfit" } 66 | 67 | ] } 68 | -------------------------------------------------------------------------------- /mod/core/server/db.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | unless fs.existsSync 'db' 24 | fs.mkdirSync 'db' 25 | 26 | $tag.db = (name,obj={}) -> 27 | obj.ready = ( -> ) unless obj.ready 28 | db = new $tag.XScale obj.path = path.join 'db', ( obj.name = name ) + '.db' 29 | meta = db.get '$meta' 30 | console.log '::db$meta', name, meta if debug 31 | Object.assign db, functions, obj, meta 32 | if db.id? 33 | console.log name, ':open'.green, db.id? 34 | throw new Error 'db.id is Nan', db if isNaN db.id 35 | else 36 | console.log name, ':bootstrap'.red, db.id? if debug 37 | db.id = 1 38 | db.create k,v for k,v of db.bootstrap 39 | global[name] = db 40 | do obj.ready 41 | console.log '::db', 'register', name, util.inspect db if debug 42 | db 43 | 44 | functions = 45 | saveMeta:-> 46 | @set '$meta', id: @id 47 | console.log '_save:$meta', id: @id 48 | create: (name,data) -> 49 | if @fields then for k,v of @fields when not data[k] 50 | data[k] = ( 51 | if typeof v is 'function' then v.apply @ 52 | else v ) 53 | data.id = @id++ 54 | @set name, data 55 | do @saveMeta 56 | console.log '_create:', id: @id 57 | 58 | setInterval ( -> 59 | # $tag.flushAll() 60 | ), 1000 61 | 62 | NUU.emit "server:db" 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuu", 3 | "version": "0.4.74", 4 | "description": "escape velocity inspired space sim browser game", 5 | "main": "./build/server.js", 6 | "bin": { 7 | "nuu": "./build/server.js" 8 | }, 9 | "scripts": { 10 | "start": "node .", 11 | "devel": "coffee tools/build.coffee run", 12 | "build": "test -d node_modules/browserify || npm i; coffee tools/build.coffee assets", 13 | "clean": "npm prune --production", 14 | "prepare": "coffee tools/build.coffee assets", 15 | "test": "npm run build; CLIENT=true npm start", 16 | "inspect": "npm run build; CLIENT=true DEBUG=true node --inspect-brk ." 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "anx@ulzq.de:nuu-test" 21 | }, 22 | "author": "anx", 23 | "license": "GPL-3.0", 24 | "dependencies": { 25 | "async": "^0.6.2", 26 | "body-parser": "^1.19.0", 27 | "compression": "^1.7.4", 28 | "cookie-parser": "^1.4.5", 29 | "eventemitter3": "^3.1.2", 30 | "express": "^4.17.1", 31 | "express-json": "^1.0.0", 32 | "express-session": "^1.17.1", 33 | "fast-image-size": "^0.1.2", 34 | "morgan": "^1.10.0", 35 | "multer": "^1.4.2", 36 | "pd": "file:pd", 37 | "random-ship-names": "^1.0.0", 38 | "serve-index": "^1.9.1", 39 | "serve-static": "^1.14.1", 40 | "three": "^0.124.0", 41 | "vectors": "^0.1.0", 42 | "ws": "^5.2.2" 43 | }, 44 | "gitHead": "86252dbc933a7215583393968322ce92c24c903d", 45 | "devDependencies": { 46 | "browserify": "^16.5.2", 47 | "chokidar": "^3.4.2", 48 | "coffeescript": "^2.5.1", 49 | "file-size": "^0.0.5", 50 | "jquery": "^3.5.1", 51 | "marked": "^4.0.10", 52 | "mkdirp": "^0.5.5", 53 | "request": "^2.88.2", 54 | "touch": "^0.0.3", 55 | "uglify-js": "^3.10.2", 56 | "x2js": "^3.4.0" 57 | }, 58 | "keywords": [ 59 | "browsergame", 60 | "game", 61 | "space" 62 | ], 63 | "optionalDependencies": { 64 | "bufferutil": "^3.0.5", 65 | "colors": "^0.6.2", 66 | "node-forge": "^1.2.1" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /mod/core/common/error.coffee: -------------------------------------------------------------------------------- 1 | Error.byKey = {} 2 | Error.byId = {} 3 | Error.i18 = {} 4 | 5 | Error.register = (opts)-> 6 | id = 0 7 | for key, msg of opts 8 | @byKey[key] = id 9 | @byId[id] = msg 10 | @[key] = msg 11 | id++ 12 | null 13 | 14 | Error.register 15 | _invalid_item: "Invalid item id :o" 16 | _no_handle: "I don't have a cookie for you. :<" 17 | _no_fuel: "You don't have enough fuel!" 18 | _no_slot_type: "You made this slot type up!" 19 | _no_slot: "This slot does not exist." 20 | _no_vehicle: "You're naked!" 21 | _not_here: "You can't do this here :(" 22 | _not_in_orbit: "You're not orbiting anything!?" 23 | _not_landed: "You must land at a certified service station." 24 | _not_the_owner: "You don't own this ship." 25 | _nx_jump: "404 - Target not found" 26 | _nx_target: "404 - Target not found" 27 | _invalid_msg: "Invalid message!" 28 | _no_mount: "This is a teapot!" 29 | _no_mounts: "That seat is made up!" 30 | _not_mounted: "Your're not mounted. Don't ask me why..." 31 | _no_steer: "You can't steer this mount." 32 | 33 | Error.i18.de = 34 | _invalid_item: "Gibbet nich!" 35 | _no_handle: "Beweis dich erstmal selbst! :>" 36 | _no_fuel: "Nicht genug Sprit!" 37 | _no_slot_type: "Den Slot-Typ hast du dir doch ausgedacht! :>" 38 | _no_slot: "Den Slot kann ich nicht finden o0" 39 | _no_vehicle: "Du bist Splitterfasernackt, echt jetzt! :D" 40 | _not_here: "Kannst hier so nich machen, tut mir leid!" 41 | _not_in_orbit: "Such dir erstmal ein Orbit..." 42 | _not_landed: "Das muss der Fachmann machen. :<" 43 | _not_the_owner: "Das is' nich' dein Schiff o0" 44 | _nx_jump: "Wohin denn bitte?" 45 | _nx_target: "Wen denn bitte?" 46 | _invalid_msg: "Kannst du kein Deutsch? Deine Zeichenkette ist keine!" 47 | _no_mount: "Der Stuhl ist kaputt... oder ausgedacht :P" 48 | _no_mounts: "Das ist ne Pulle Bier oder so und kein Raumschiff; da kann man jdf. nicht einsteigen!" 49 | _not_mounted: "Da brat' mir einer einen Storch, du stehst zwischen den Welten." 50 | _no_steer: "Das kann man nicht lenken." 51 | -------------------------------------------------------------------------------- /tools/import_git.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2020 Sebastian Glaser 4 | * c) 2007-2020 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | module.exports = (destinationFile,callback)-> 24 | cp = require 'child_process' 25 | ref = cp.execSync('git log --pretty=format:"%H"').toString('utf8').split('\n') 26 | msg = cp.execSync('git log --pretty=format:"%s"').toString('utf8').split('\n') 27 | date = cp.execSync('git log --pretty=format:"%d"').toString('utf8').split('\n') 28 | author = cp.execSync('git log --pretty=format:"%a"').toString('utf8').split('\n') 29 | head = ref[0] 30 | release = {}; current = null 31 | adds = msg 32 | .filter (i,k,s)-> not i.match /^[0-9]+\.[0-9]+\.[0-9]+/ 33 | .filter (i,k,s)-> k is s.indexOf i 34 | msg .map (i,k,s)-> if i.match /^[0-9]+\.[0-9]+\.[0-9]+/ 35 | release[v = i.substr 0,6] = x = v: v 36 | x.m = i.substr(6).replace(/ /g,'\n ') 37 | x.a = author[v] 38 | x.d = date[v] 39 | unless current 40 | current = x 41 | if adds.length > 0 42 | x.v += '+' 43 | x.m += '\n ' + adds.join(' (from master)\n ') + ' (from master)' 44 | x.m = x.m.split('\n').sort( (a,b)-> 45 | a.charCodeAt(5) - b.charCodeAt(5) ).join('\n').substr(6) 46 | current.git = head 47 | fs.writeFileSync path.join(path.dirname(destinationFile),'release.json'), JSON.stringify current 48 | callback null 49 | # console.log head, current.v, current.m 50 | # for k,v of release 51 | # process.exit 1 52 | # callback null 53 | -------------------------------------------------------------------------------- /mod/nuu/client/gui_nuu.coffee: -------------------------------------------------------------------------------- 1 | Window.About = class AboutWindow extends Window 2 | title: 'About NUU / License' 3 | closeKey:'aKeyH' 4 | constructor:-> 5 | super() 6 | @$.addClass 'about full' 7 | @$.append $ """ 8 |
9 | Game 10 | Libraries 11 | Artwork 12 | Sounds 13 | Close 14 |
15 |
16 | 17 |

    18 |
  • c) 2007-2022 Sebastian Glaser
  • 19 |
  • c) 2007-2022 flyc0r
  • 20 |

21 | 22 |

The nuu project intends to use all the asset files 23 | according to their respective licenses.

24 | 25 |

nuu currently uses the graphics and sound assets of 26 | the excellent naev project, which in turn are partly attributable to the 27 | Vega Strike project.

28 | 29 |

All assets are downloaded from their source repo to 30 | the contrib folder during the build process and LICENSE information is 31 | copied to the build directory as well as being made available in the 32 | client's about screen and the server splash.

33 |
34 |
35 |
36 |
37 | """ 38 | @$.find('.close').on 'click', => @close() 39 | @tabs = @$.find '.tab' 40 | @tabs.each (k,i) -> 41 | src = $(i).attr 'data-src' 42 | console.log src 43 | return unless src 44 | $.get src, (data,s,x)-> $(i).html data 45 | btns = @$.find '.tabbtn' 46 | w = @ 47 | btns.on 'click', -> w.activate @href 48 | @activate '#game' 49 | activate: (name) -> 50 | @tabs.css 'display', 'none' 51 | name = name.replace(/.*#/,'') 52 | console.log name 53 | $('#'+name).css 'display', 'block' 54 | 55 | Kbd.macro 'about', 'aKeyH', 'Show about / license', -> new Window.About 56 | -------------------------------------------------------------------------------- /mod/nuu/server/engine.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | $static '$id$', (i)-> i.id 24 | 25 | NUU.fix_sprites = (o)-> 26 | for k,v of o 27 | w = v.size 28 | v.cols = v.cols || 1 29 | v.rows = v.rows || 1 30 | v.width = v.width || w 31 | v.height = v.height || w 32 | v.radius = v.radius || w / 2 33 | o 34 | 35 | $public class Formula 36 | @to: {} 37 | @from: {} 38 | 39 | Formula.define = (k,f)-> 40 | ( Formula.to[k] || Formula.to[k] = [] ).push f 41 | ( Formula.from[c] || Formula.from[c] = [] ).push [k,f] for c in Object.keys f 42 | return 43 | 44 | Formula.init = (k,f)-> 45 | for f in rules.formula 46 | k = Object.keys(f)[0] 47 | Formula.define k, f[k] 48 | console.log Formula.to if debug 49 | console.log Formula.from if debug 50 | return 51 | 52 | NUU.init =-> 53 | NUU.mode = NUU.mode || 'dm' 54 | console.log 'loading game mode', NUU.mode 55 | Object.assign rules, rules[NUU.mode] 56 | # Load objects 57 | fs.writeJSONSync 'build/objects.json', Item.init ( 58 | fs.readJSONSync 'build/objects_naev.json' 59 | .concat fs.readJSONSync 'build/objects_nuu.json' ) 60 | # Load metadata for sprites for each object 61 | fs.writeJSONSync 'build/images.json', meta = NUU.fix_sprites Object.assign( 62 | fs.readJSONSync 'build/imag/sprites_naev.json' 63 | fs.readJSONSync 'build/imag/sprites_nuu.json' ) 64 | $static '$meta', meta 65 | do Formula.init 66 | do Stellar.init 67 | console.log ':nuu', 'init:rules' if debug 68 | rules @ 69 | @thread 'group', 1000, -> 70 | time = NUU.time() 71 | o.update time for o in $obj.list 72 | null 73 | @start() 74 | -------------------------------------------------------------------------------- /pd/schema.js: -------------------------------------------------------------------------------- 1 | const Database = require("./database"); 2 | const SchemaRecord = require('./record'); 3 | 4 | Database.model = ({ db, name, path = name, schema }) => { 5 | db = db ? db : Database.open({ path }); 6 | db.Model = schema; 7 | schema.Record.$ = db; 8 | schema.Record.prototype.$ = db; 9 | schema.indexes.forEach((key) => db.index(key)); 10 | Object.assign(schema.Record.prototype, schema.methods); 11 | Schema.Types[name] = schema.Record; 12 | return schema.Record; 13 | }; 14 | 15 | 16 | 17 | 18 | class Schema { 19 | constructor({ methods = {}, ...fields }) { 20 | Object.entries(fields).map(([k,v]) => fields[k] = typeof v === 'object' && !Array.isArray(v) ? v : {type:v}); 21 | const keys = Object.keys(fields), type = {}, defaults = {}; 22 | keys.forEach((k) => (type[k] = fields[k]?.type || fields[k])); 23 | keys.forEach((k) => (defaults[k] = fields[k]?.default)); 24 | const requireds = keys.filter((k) => fields[k]?.required); 25 | this.indexes = keys.filter((k) => fields[k]?.index); 26 | this.methods = methods; 27 | this.$on = {}; 28 | const Record = SchemaRecord({Schema,$schema:this,keys,requireds,type,defaults}); 29 | this.Record = Record; 30 | Object.assign(this, {fields,requireds,defaults,type,Record}); 31 | keys.forEach( key => { 32 | Object.defineProperty(this.Record.prototype, key, { 33 | get: function(){ return this.data[key]; }, 34 | set: function(v){ this.data[key] = v; this.$changed = true; }, 35 | enumerable: true 36 | }); 37 | }); 38 | } 39 | virtual = (key, fn) => { 40 | setImmediate(()=> Object.defineProperty(this.Record.prototype, key, fns)); 41 | let fns = {}, ctx = { 42 | get: (get) => { fns = {...fns,get}; return ctx; }, 43 | set: (set) => { fns = {...fns,set}; return ctx; }, 44 | virtual: this.virtual 45 | }; 46 | return ctx; 47 | } 48 | pre( event, callback ){ 49 | this.$on[event] ? this.$on[event].push(callback) : ( this.$on[event] = [callback] ); 50 | } 51 | isArray(key){ 52 | const type = this.fields[key]?.type; 53 | return Array === type || Array.isArray(type); 54 | } 55 | } 56 | 57 | const ObjectId = Symbol("PD_OBJREF"); 58 | 59 | Schema.type = [String, Number, Boolean, Object, Array]; 60 | 61 | Schema.Types = { 62 | String, 63 | Number, 64 | Boolean, 65 | Object, 66 | Array, 67 | ObjectId, 68 | }; 69 | 70 | module.exports = Schema; 71 | -------------------------------------------------------------------------------- /mod/preql/common/map.coffee: -------------------------------------------------------------------------------- 1 | $public class URMap 2 | x: 0 3 | y: 0 4 | scale: 8 5 | height: null 6 | mountain: [] 7 | 8 | constructor: (@w,@h,@seed=32) -> 9 | # load Map from cache 10 | if (m = localStorage.getItem("urtc.map."+@seed)) 11 | console.log 'cached' 12 | @height = new Int16Array str2ab m 13 | else # Generate Map 14 | Math.seedrandom(@seed) 15 | @height = new Int16Array @w*@h+@w+1 16 | for x in [0..@w-1] 17 | for y in [0..@h-1] 18 | @height[x+y*@w] = h = Math.round( ( 19 | Math.floor(55.0 + 50 * Math.sin(0.5 * x / 16.0)) + 20 | Math.floor(55.0 + 50 * Math.sin(0.5 * y / 8.0)) + 21 | Math.floor(55.0 + 50 * Math.sin(0.5 * (x + y) / 16.0)) + 22 | Math.floor(55.0 + 50 * Math.sin(0.5 * Math.sqrt(x*x + y*y) / 8.0)) 23 | ) / 4) 24 | @peak(Math.floor(Math.random()*@w),Math.floor(Math.random()*@h),200) for i in [0..10] 25 | localStorage.setItem("urtc.map."+@seed,ab2str(@height.buffer)) 26 | # Initial render() 27 | win.on 'resize', @render 28 | do animate = => do @render; requestAnimationFrame animate 29 | $('body').on 'mousemove', => @hud() 30 | @map on 31 | 32 | peak: (x,y,h) => 33 | @mountain[i] = m = x : x, y : y, h : h = Math.floor(Math.random()*h) 34 | h = @height[idx = x+y*@w] += h 35 | stack = [[x+1,y+1,h],[x-1,y+1,h],[x+1,y-1,h],[x-1,y-1,h],[x,y+1,h],[x,y-1,h],[x+1,y],[x-1,y,h]] 36 | have = new Int16Array(@w*@h+@w+1) 37 | have[idx] = 1 38 | c = 0 39 | while stack.length > 0 40 | stack = Array.shuffle stack if c++ % 10 is 0 41 | [x,y,h] = stack.shift() 42 | if have[idx = x+y*@w] isnt 1 43 | lh = @height[idx] 44 | if h - lh > 10 45 | have[idx] = 1 46 | if lh < 55 47 | @height[idx] = h = lh && h - 1 - Math.floor(Math.random() * 2) 48 | else @height[idx] = h = lh && h - 1 - Math.floor(Math.random() * 8) 49 | for i in [[x-1,y+1,h],[x+1,y-1,h],[x,y+1,h],[x,y-1,h],[x+1,y,h],[x-1,y,h],[x+1,y+1,h],[x-1,y-1,h]] 50 | stack.push i if have[i[0]+i[1]*@w] isnt 1 51 | @peak(Math.floor(Math.random()*50),Math.floor(Math.random()*50),h-Math.floor(10+Math.random()*20)) if h - 55 > 100 52 | 53 | walkmap: -> 54 | grid = [] 55 | for y in [0..@h-1] 56 | grid.push row = [] 57 | for x in [0..@w-1] 58 | row[x] = @height[x+y*@w] 59 | # row[x] = if 49 < (h=@height[x+y*@w]) < 101 then 0 else h 60 | grid 61 | 62 | debug: => console.log @ 63 | -------------------------------------------------------------------------------- /mod/core/server/start.coffee: -------------------------------------------------------------------------------- 1 | 2 | NUU.emit 'extend' 3 | 4 | # ██ ██ ███████ ██████ ███████ ███████ ██████ ██ ██ ███████ ██████ 5 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 6 | # ██ █ ██ █████ ██████ ███████ █████ ██████ ██ ██ █████ ██████ 7 | # ██ ███ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 8 | # ███ ███ ███████ ██████ ███████ ███████ ██ ██ ████ ███████ ██ ██ 9 | 10 | ## Initialize express / setup WebSockets 11 | $websocket NUU.web = express() 12 | ## Setup Webserver 13 | NUU.web.use require('morgan')() if debug 14 | # NUU.web.use require('body-parser') keepExtensions: true, uploadDir: '/tmp/' 15 | NUU.web.use require('compression')() 16 | NUU.web.use require('cookie-parser')() 17 | NUU.web.use require('express-session') secret: 'what-da-nuu', saveUninitialized:no, resave:no 18 | NUU.web.use '/build', require('serve-static')('build',etag:no) 19 | NUU.web.use '/build', require('serve-index' )('build',etag:no) if debug 20 | NUU.web.get '/excuse', NUU.splashPage false, true 21 | NUU.web.get '/', NUU.splashPage false, false 22 | NUU.web.get '/intro', NUU.splashPage true, false 23 | NUU.web.get '/start', NUU.startPage() 24 | 25 | # ███████ ███ ██ ██████ ██ ███ ██ ███████ 26 | # ██ ████ ██ ██ ██ ████ ██ ██ 27 | # █████ ██ ██ ██ ██ ███ ██ ██ ██ ██ █████ 28 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 29 | # ███████ ██ ████ ██████ ██ ██ ████ ███████ 30 | 31 | $static '$release', fs.readJSONSync './build/release.json' 32 | $release.banner = $release.v.green + $release.git.red 33 | 34 | NUU.chgid = process.env.CHGID || false 35 | NUU.port = process.env.PORT || 9999 36 | NUU.addr = process.env.ADDR || '127.0.0.1' 37 | BROWSER = process.env.BROWSER || 'chromium' 38 | 39 | console.log ':nuu', 'initializing'.yellow 40 | NUU.init() 41 | 42 | console.log 'http', 'listen'.yellow, NUU.addr.red + ':' + NUU.port.toString().magenta 43 | NUU.web.listen NUU.port, NUU.addr, -> 44 | console.log 'http', 'online'.green, NUU.addr.red + ':' + NUU.port.toString().magenta 45 | console.log ':nuu', $release.banner 46 | if process.env.CLIENT 47 | if BROWSER.match /^chrom[ei]/ 48 | ARGS = ["-app=http://#{NUU.addr}:#{NUU.port}/start"] 49 | if BROWSER.match /^firefox/ 50 | ARGS = ["http://#{NUU.addr}:#{NUU.port}/start"] 51 | try cp.spawn BROWSER, ARGS 52 | if NUU.chgid 53 | console.log 'http', 'dropping privileges'.green 54 | process.setgid NUU.chgid 55 | process.setuid NUU.chgid 56 | null 57 | -------------------------------------------------------------------------------- /mod/nuu/client/autopilot.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | $public class Autopilot 24 | @active: no 25 | @plan: 'land' 26 | 27 | Autopilot.widget = (v) -> 28 | unless VEHICLE.target 29 | HUD.widget 'autopilot', 'no target', yes 30 | return v 31 | s = '' 32 | s += VEHICLE.target.name + '\n' 33 | s += v.message + '\n' 34 | s += v.recommend + '\n' 35 | s += 'v: ' + parseInt(VEHICLE.target.v[0]) + ':' + parseInt(VEHICLE.target.v[1]) + '\n' 36 | s += 't: ' + parseInt(v.throttle) + '\n' 37 | s += 'e: ' + v.error + '\n' 38 | s += 'z: ' + parseInt(v.target_zone) + '\n' 39 | s += 'dd:' + parseInt(v.maxSpeed) + '\n' 40 | s += '\n⚑[' 41 | s += '▲' if v.recommend is 'boost' 42 | s += '△' if v.recommend is 'burn' 43 | s += '▽' if v.recommend is 'retro' 44 | s += '◉' if v.recommend is 'setdir' 45 | s += '☕' if v.recommend is 'wait' 46 | s += '⌘' if v.recommend is 'execute' 47 | s += ']\nFm:' + hdist v.maxSpeed 48 | HUD.widget 'autopilot', s, yes 49 | return v 50 | 51 | Autopilot.start = -> 52 | Autopilot.stop() if Autopilot.active 53 | HUD.widget 'autopilot', 'ap:booting', yes 54 | VEHICLE.target = TARGET 55 | VEHICLE.changeStrategy null 56 | VEHICLE.changeStrategy 'approach' 57 | Autopilot.active = yes 58 | Mouse.disableTemp() 59 | VEHICLE.onTarget = (v)-> 60 | Autopilot.stop() 61 | Target.orbit() 62 | return 63 | 64 | Autopilot.stop = -> 65 | HUD.widget 'autopilot', 'ap:off', yes 66 | VEHICLE.changeStrategy null 67 | Autopilot.active = no 68 | Mouse.enableIfWasEnabled() 69 | return 70 | 71 | Autopilot.macro = -> 72 | unless VEHICLE.hasAP 73 | VEHICLE.hasAP = yes 74 | VEHICLE.approachTarget = -> @target = TARGET 75 | VEHICLE.changeStrategy = AI.prototype.changeStrategy 76 | VEHICLE.onDecision = Autopilot.widget.bind Autopilot 77 | unless Autopilot.active 78 | do Autopilot.start 79 | else do Autopilot.stop 80 | 81 | Kbd.macro 'autopilot', 'sKeyZ', 'Autopilot', Autopilot.macro 82 | -------------------------------------------------------------------------------- /tools/dev_autobuild.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2020 Sebastian Glaser 4 | * c) 2007-2020 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | fs = require 'fs' 24 | path = require 'path' 25 | cp = require 'child_process' 26 | async = require 'async' 27 | _ = require 'underscore' 28 | 29 | Array.prototype.uniq = -> 30 | b = {}; c = []; for k,v of @ when b[v] isnt true 31 | b[v] = true;c.push v 32 | c 33 | 34 | readDir = (dir,call) -> call f, dir for f in fs.readdirSync dir 35 | 36 | root = path.dirname __dirname 37 | server = null 38 | client = null 39 | watch = {} 40 | rebuildFiles = [] 41 | timeout = null 42 | rebuildLock = no 43 | 44 | addFile = (f,dir) -> 45 | path = dir + f 46 | watch[f+dir] = fs.watch path,{persistent:on}, changeFile(path,f) 47 | 48 | changeFile = (path,name) -> -> 49 | if rebuildLock is on 50 | console.log ':dev', '[locked]', path 51 | return 52 | clearTimeout timeout 53 | rebuildFiles.push path 54 | timeout = setTimeout rebuild, 100 55 | 56 | rebuild = -> 57 | rebuildLock = on 58 | console.log 'coffee',['-co',root+'/build/'].concat rebuildFiles.uniq() 59 | i = cp.spawn 'coffee',['-co',root+'/build/'].concat rebuildFiles.uniq() 60 | i.on 'close', (status) -> 61 | console.log 'done' 62 | rebuildFiles = [] 63 | rebuildLock = off 64 | server.kill('SIGHUP') if server? 65 | client.kill('SIGHUP') if client? 66 | server = cp.spawn 'coffee', ['server/server.coffee'] 67 | server.stdout.setEncoding 'utf8' 68 | server.stderr.setEncoding 'utf8' 69 | server.stdout.on 'data', console.log 70 | server.stderr.on 'data', console.log 71 | setTimeout ( -> 72 | client = cp.spawn 'chromium-browser', ["-app=http://localhost:9999"] 73 | client.stdout.setEncoding 'utf8' 74 | client.stderr.setEncoding 'utf8' 75 | client.stdout.on 'data', console.log 76 | client.stderr.on 'data', console.log 77 | ), 500 78 | 79 | readDir root + '/common/', addFile 80 | readDir root + '/client/', addFile 81 | console.log ':dev', 'watching', Object.keys(watch).length 82 | -------------------------------------------------------------------------------- /mod/core/server/ids.coffee: -------------------------------------------------------------------------------- 1 | 2 | # ██████ ██████ ██████ ██ 3 | # ██ ██ ██ ██ ██ ██ ██ 4 | # ██████ ██ ██ ██ ██ ██ 5 | # ██ ██ ██ ██ ██ ██ 6 | # ██ ██████ ██████ ███████ 7 | 8 | $public class IdPool 9 | empty: 0x00 10 | full: 0xFF 11 | constructor:(opts)-> 12 | Object.assign @,opts 13 | @length = 0 14 | @lastFree = 0 15 | @s = if @s? then @s else $id.getRange @max 16 | @u = new Uint8Array @max/8 17 | # @f = new Set 18 | $id[@name] = @ 19 | $id.pools.push @ 20 | # console.log "pool(#{@name}:#{@s}:#{@max}) get:#{@lastFree}".bold.inverse 21 | take:(obj)-> 22 | obj.pool = @ 23 | id = obj.id - @s 24 | @u[byteNum = floor id/8] = byte = @u[byteNum] + ( 1 << bit = id - byteNum*8 ) 25 | @lastFree = byteNum unless byte is @full 26 | @length++ 27 | # console.log "pool(#{@name}:#{@s}:#{@lastFree}:#{@max}) take(#{byteNum}:#{bit}:#{id}) byte(#{byte.toString 2})" 28 | free:(id)-> 29 | bit = ( id = id - @s ) - 8*byteNum = floor id/8 30 | #console.log "pool(#{@name}:#{@s}:#{@lastFree}:#{@max}) free(#{byteNum}:#{bit}:#{id}) byte(#{@u[byteNum].toString 2})".red 31 | @u[byteNum] = byte = @u[byteNum] ^ ( 1 << bit ) 32 | # @f.add byteNum 33 | @length-- 34 | # console.log "pool(#{@name}:#{@s}:#{@lastFree}:#{@max}) free(#{byteNum}:#{bit}:#{id}) byte(#{byte.toString 2})".yellow 35 | getBlock:-> 36 | c = @max; f = @full; l = @lastFree || 0 37 | return p for i in [0..@max] when f isnt @u[p = l + i % c] 38 | throw new Error 'Pool out of Bocks' 39 | get:(obj)-> 40 | # console.log "pool(#{@name}:#{@s}:#{@max}) get:#{@u[@lastFree].toString 2}".bold.inverse.red 41 | byte = b unless 0xFF is b = @u[byteNum = @lastFree] 42 | byte = b unless 0xFF is b = @u[byteNum = @getBlock()] unless byte? 43 | throw new Error 'Pool out of Ids' unless byte? 44 | for bit in [0..7] when 0 is ( byte & ( 1 << bit ) ) 45 | obj.id = id = @s + byteNum*8 + bit 46 | @take obj 47 | # console.log "pool(#{@name}:#{@s}:#{@lastFree}:#{@max}) get(#{byteNum}:#{bit}:#{id}) byte(#{byte.toString 2})" 48 | return 49 | throw new Error 'Pool out of Ideas, also this should not happen... o0' 50 | 51 | new class IdManager 52 | reserved: new Map 53 | lastId: 0 54 | maxId: 0xFFFF 55 | pools: [] 56 | constructor:-> 57 | $static '$id', @ 58 | new IdPool name:'eternal', max:10000 59 | new IdPool name:'dynamic', max:20000 60 | getRange:-> 61 | l = 0 62 | l = max l, pool.s + pool.max for pool in @pools 63 | l 64 | free:(list)-> 65 | list = list.sort (a,b)-> a-b 66 | reserve:(obj,max,key='_'+obj.id)-> 67 | @[key] = new IdPool 68 | id = @lastId + 1 69 | @lastId = @lastId + max 70 | @reserved.set obj, max 71 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/asteroid.vert: -------------------------------------------------------------------------------- 1 | 2 | varying vec3 vNormal; 3 | varying vec2 vTex; 4 | varying float vElevator; 5 | varying float vNoiser; 6 | 7 | uniform float seed; 8 | uniform float time; 9 | uniform float temperature; 10 | uniform vec3 light; 11 | 12 | #define PI 3.1415926535897932384626433832795 13 | 14 | vec3 random3(vec3 c) { 15 | float j = seed + 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0))); 16 | vec3 r; 17 | r.z = fract(512.0*j); 18 | j *= .125; 19 | r.x = fract(512.0*j); 20 | j *= .125; 21 | r.y = fract(512.0*j); 22 | return r-0.5; } 23 | 24 | const float F3 = 0.3333333; 25 | const float G3 = 0.1666667; 26 | float snoise(vec3 p) { 27 | vec3 s = floor(p + dot(p, vec3(F3))); 28 | vec3 x = p - s + dot(s, vec3(G3)); 29 | vec3 e = step(vec3(0.0), x - x.yzx); 30 | vec3 i1 = e*(1.0 - e.zxy); 31 | vec3 i2 = 1.0 - e.zxy*(1.0 - e); 32 | vec3 x1 = x - i1 + G3; 33 | vec3 x2 = x - i2 + 2.0*G3; 34 | vec3 x3 = x - 1.0 + 3.0*G3; 35 | vec4 w, d; 36 | w.x = dot(x, x); 37 | w.y = dot(x1, x1); 38 | w.z = dot(x2, x2); 39 | w.w = dot(x3, x3); 40 | w = max(0.6 - w, 0.0); 41 | d.x = dot(random3(s), x); 42 | d.y = dot(random3(s + i1), x1); 43 | d.z = dot(random3(s + i2), x2); 44 | d.w = dot(random3(s + 1.0), x3); 45 | w *= w; 46 | w *= w; 47 | d *= w; 48 | return dot(d, vec4(52.0)); } 49 | 50 | float shading(vec3 position){ 51 | vec3 l = normalize(light); 52 | return max(0.015, dot(position, l)); } 53 | 54 | float fnoise(vec3 position, const int octaves, float frequency, float persistence) { 55 | float total = 0.0; 56 | float maxAmplitude = 0.0; 57 | float amplitude = 1.0; 58 | total += snoise(position * frequency) * amplitude; 59 | frequency *= 2.0; 60 | maxAmplitude += amplitude; 61 | amplitude *= persistence; 62 | total += snoise(position * frequency) * amplitude; 63 | frequency *= 2.0; 64 | maxAmplitude += amplitude; 65 | amplitude *= persistence; 66 | total += snoise(position * frequency) * amplitude; 67 | frequency *= 2.0; 68 | maxAmplitude += amplitude; 69 | amplitude *= persistence; 70 | total += snoise(position * frequency) * amplitude; 71 | frequency *= 2.0; 72 | maxAmplitude += amplitude; 73 | amplitude *= persistence; 74 | total += snoise(position * frequency) * amplitude; 75 | frequency *= 2.0; 76 | maxAmplitude += amplitude; 77 | amplitude *= persistence; 78 | total += snoise(position * frequency) * amplitude; 79 | frequency *= 2.0; 80 | maxAmplitude += amplitude; 81 | amplitude *= persistence; 82 | return total / maxAmplitude; } 83 | 84 | void main() { 85 | vNormal = normal; 86 | vTex = uv; 87 | vElevator = max( 88 | fnoise(vNormal.xyz, 6, 0.1, 0.8), 89 | fnoise(vNormal.zyx, 5, -0.1, 0.79)); 90 | vNoiser = fnoise(vNormal.xzy, 6, 0.1, 0.66); 91 | gl_Position = projectionMatrix * modelViewMatrix * 92 | vec4(position, 1.0) + 93 | vec4(vElevator*.3,.0,.0,.1); } 94 | -------------------------------------------------------------------------------- /mod/nuu/sprites/objects_nuu.json: -------------------------------------------------------------------------------- 1 | [ 2 | { "class": "ship", 3 | "name": "Human", 4 | "sprite": "st_suit", 5 | "slots":{ 6 | "structure":[{"size":"suit","default":"Human Skin"}], 7 | "utility":[{"size":"suit","default":"Human Heart"}], 8 | "weapon":[{"size":"suit","default":"Stock Multitool"}]}, 9 | "stats":{ 10 | "crew":1, 11 | "mass":1, 12 | "fuel_consumption":0} }, 13 | 14 | { "class": "ship", 15 | "name": "Exosuit", 16 | "sprite": "st_suit", 17 | "slots":{ 18 | "structure":[ 19 | {"size":"suit","default":"Stock Fabric"}, 20 | {"size":"suit","default":"Stock ExoThrusters"} 21 | ], 22 | "utility":[], 23 | "weapon":[{"size":"suit","default":"StockMultitool"}]}, 24 | "stats":{ 25 | "crew":1, 26 | "mass":1, 27 | "fuel_consumption":0} }, 28 | 29 | { "class": "outfit", 30 | "name" : "Stock ExoThrusters", 31 | "size" : "suit", 32 | "itemId": 500, 33 | "stats" : { 34 | "mass" : 15, 35 | "price" : 0, 36 | "thrust" : 100, 37 | "turn" : 85, 38 | "engine_limit" : 300, 39 | "energy_usage" : 5, 40 | "fuel" : 200, 41 | "speed" : 175 42 | }, 43 | "type" : "modification", 44 | "info" : { 45 | "description" : "Clogged, corroded and cracked in every way possible while still remaining in functional condition, this engine really belongs on the scrap heap.", 46 | "name" : "Stock ExoThrusters", 47 | "gfx_store" : "engine04" 48 | }, 49 | "slot" : { "prop" : "engines", "$t" : "structure" }, 50 | "extends" : "Outfit" }, 51 | 52 | { "class": "outfit", 53 | "name" : "Stock Fabric", 54 | "size" : "suit", 55 | "itemId": 501, 56 | "stats" : { 57 | "armour": 10, 58 | "mass": 1, 59 | "cargo": 0 60 | }, 61 | "type" : "modification", 62 | "info" : { 63 | "description" : "A rag, really.", 64 | "name" : "Stock Fabric", 65 | "gfx_store" : "engine04" 66 | }, 67 | "slot" : { "prop" : "hull", "$t" : "structure" }, 68 | "extends" : "Outfit" }, 69 | 70 | { "class": "com", "name":"Admiral Assembly", "logo":"admiralassembly" }, 71 | { "class": "com", "name":"FayPoe", "logo":"faypoe" }, 72 | { "class": "com", "name":"Ganymede Gas", "logo":"ganymede_gas" }, 73 | { "class": "com", "name":"G-Force", "logo":"gforce" }, 74 | { "class": "com", "name":"Greywash", "logo":"greywash" }, 75 | { "class": "com", "name":"Johnson and Jetson", "logo":"jetson" }, 76 | { "class": "com", "name":"Ponomareva GaussGun", "logo":"ponomarevagaussgun" }, 77 | { "class": "com", "name":"Russels", "logo":"russels" }, 78 | { "class": "com", "name":"Sirius Robotics", "logo":"siriusrobotics" }, 79 | { "class": "com", "name":"Solarsuits", "logo":"solarsuits" }, 80 | { "class": "com", "name":"Taikuipment", "logo":"taikuipment" }, 81 | { "class": "com", "name":"Tau", "logo":"tau" }, 82 | { "class": "com", "name":"Tepeshkovalaser", "logo":"tepeshkovalaser" }, 83 | { "class": "com", "name":"Valkyrie", "logo":"valkyrie" } 84 | 85 | ] 86 | -------------------------------------------------------------------------------- /mod/nuu-mbt/sysgen.coffee: -------------------------------------------------------------------------------- 1 | 2 | global.$static = (name,value) -> global[name] = value 3 | $static.list = global 4 | global.$library = (args...) -> for a in args 5 | if Array.isArray a then global[a[0]] = require a[1] else global[a] = require a 6 | global.$public = (args...) -> global[a.name] = a for a in args 7 | global.$cue = (f) -> setImmediate f 8 | 9 | $static 'debug', no 10 | $static 'isClient', no 11 | $static 'isServer', yes 12 | BROWSER = process.env.BROWSER || 'chromium' 13 | 14 | ## Load sources 15 | $cp = require 'child_process' 16 | $fs = require 'fs' 17 | 18 | deps = 19 | common : JSON.parse $fs.readFileSync './common/build.json' 20 | client : JSON.parse $fs.readFileSync './client/build.json' 21 | server : JSON.parse $fs.readFileSync './server/build.json' 22 | 23 | for lib in deps.server.require 24 | if Array.isArray lib 25 | if lib.length is 3 26 | $static lib[0], require(lib[1])[lib[2]] 27 | else $static lib[0], require(lib[1]) 28 | else $static lib, require lib 29 | 30 | ## Initialize express 31 | $static 'app', app = express() 32 | $static 'coffee', coffee = require 'coffeescript' 33 | 34 | ## Setup Webserver 35 | app.use require('morgan')('combined',{}) 36 | app.use require('body-parser').urlencoded keepExtensions: true, uploadDir: '/tmp/', limit: '1mb', extended:true 37 | app.use require('compression')() 38 | app.use require('cookie-parser')() 39 | app.use '/shader', express.static('mod/nuu/shader',etag:yes) 40 | 41 | express.static.mime.define({'text/html': ['frag','vert']}); 42 | 43 | app.post '/upload/:name', (req,res)-> 44 | out = $fs.createWriteStream 'build/imag/' + req.params.name 45 | req.pipe out 46 | req.on 'end', -> 47 | console.log 'upload'.green, req.params.name 48 | # $cp.spawn 'feh', ['build/imag/' + req.params.name] 49 | res.end() 50 | 51 | app.get '/', (req,res) -> 52 | res.set 'Content-Type', 'text/html' 53 | res.send $fs.readFileSync 'mod/nuu/render.html' 54 | 55 | scriptfile = (n)-> app.get '/'+n+'.js', (req,res) -> 56 | res.set 'Content-Type', 'text/javascript' 57 | if $fs.existsSync 'mod/nuu/'+n+'.coffee' 58 | res.send coffee.compile( $fs.readFileSync('mod/nuu/'+n+'.coffee').toString 'utf8' ) 59 | else res.send $fs.readFileSync 'mod/nuu/'+n+'.js' 60 | 61 | pngfile = (n)-> app.get '/'+n+'.png', (req,res) -> 62 | res.set 'Content-Type', 'image/png' 63 | res.send $fs.readFileSync 'mod/nuu/'+n+'.png' 64 | 65 | scriptfile n for n in ['stargen','three','spritegen'] 66 | pngfile n for n in ['star_spectrum'] 67 | 68 | app.get '/quit', (req,res)-> 69 | $cp.spawnSync 'pkill', ['-f','Xephyr'] 70 | res.end() 71 | 72 | app.listen 9998, -> 73 | console.log 'sysgen-server:9998'.yellow, 'ready'.green 74 | return 75 | p = $cp.spawnSync 'rm',['-f','/tmp/.X84-lock'], stdio:'inherit' 76 | p = $cp.spawn 'Xephyr',['-screen','820x820',':84'], stdio:'inherit' 77 | setTimeout ( -> 78 | p = $cp.spawn BROWSER,['--temp-profile','--app=http://localhost:9998/'], stdio:'inherit', env: DISPLAY:':84' 79 | p.on 'close', -> process.exit 0 80 | ), 1000 81 | -------------------------------------------------------------------------------- /pd/cursor.js: -------------------------------------------------------------------------------- 1 | 2 | class Cursor { 3 | constructor({ $schema, $db, query, opts = {} }) { 4 | Object.assign(this, { $schema, $db, ...opts }); 5 | this.limit = this.limit || Infinity; 6 | this._populate = []; 7 | const { $or, $and, ...fields } = query; 8 | if (!$or && !$and) this.query = this.evaluate(fields); 9 | if ($or) this.query = this.$or($or); 10 | if ($and) this.query = this.$and([$and]); 11 | this.query = this.query || "true"; 12 | //console.debug("QUERY:", this.query); 13 | } 14 | exec() { 15 | const test = eval(`([key,json]) => { return ${this.query}; }`); 16 | const done = new Promise(async (resolve) => { 17 | let all = this.$db.forEach(); 18 | let count = 0, 19 | done, 20 | value; 21 | const result = new Map(); 22 | Object.assign(this, { result }); 23 | while (({ done, value } = await all.next())) { 24 | if (done) break; 25 | if (!test(value)) continue; 26 | let [id, record] = value; 27 | this.$post && ( record = await this.$post(id, record, this) ); 28 | result.set(id, record); 29 | if (count++ > this.limit) break; 30 | } 31 | resolve(this.$filter ? this.$filter.call(this, this) : this); 32 | }); 33 | this.done = new Proxy(done, { 34 | get: (_, key) => { 35 | const target = !!done[key] ? done : this; 36 | const value = target[key]; 37 | if (!!value && typeof value === "function") return value.bind(target); 38 | return value; 39 | }, 40 | }); 41 | return this.done; 42 | } 43 | populate(...rules) { 44 | this._populate = [...this._populate, ...rules]; 45 | return this.done; 46 | } 47 | async toArray() { 48 | return Array.from(this.result.values()); 49 | } 50 | $logical(operator, operands, path = "json") { 51 | if (operands.length === 0) return ""; 52 | return `(${operands 53 | .map((rules) => this.evaluate(rules, path)) 54 | .filter((s) => !!s) 55 | .join(`) ${operator} (`)})`; 56 | } 57 | $and = (operands, path) => this.$logical("&&", operands, path); 58 | $or = (operands, path) => this.$logical("||", operands, path); 59 | evaluate(rules, path = "json") { 60 | const accessor = (k) => [path, "[" + JSON.stringify(k) + "]"].join("?."); 61 | const entries = Object.entries(rules); 62 | if (entries.length === 0) return ""; 63 | const match = (path, key, rule) => { 64 | switch (key) { 65 | case "$regex": 66 | return `!! (${rule.toString()}).test(${path})`; 67 | default: 68 | return `${path} === ${JSON.stringify(rule)}`; 69 | } 70 | }; 71 | return `(${entries 72 | .map(([key, rule]) => { 73 | const path = accessor(key); 74 | if (rule instanceof RegExp) return match(path, key, rule); 75 | if (this.$schema.isArray(key)) 76 | return `${path}?.some(value => ${match("value", key, rule)})`; 77 | //else if ( this.schema.isObject(path) ) 78 | return match(path, key, rule); 79 | }) 80 | .join("")})`; 81 | } 82 | } 83 | 84 | module.exports = Cursor; 85 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/earth.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D tex0; 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform float time; 5 | uniform float temperature; 6 | uniform vec3 light; 7 | varying vec3 vNormal; 8 | varying vec2 vTex; 9 | 10 | #define PI 3.1415926535897932384626433832795 11 | 12 | vec3 random3(vec3 c) { 13 | float j = seed + 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0))); 14 | vec3 r; 15 | r.z = fract(512.0*j); 16 | j *= .125; 17 | r.x = fract(512.0*j); 18 | j *= .125; 19 | r.y = fract(512.0*j); 20 | return r-0.5; } 21 | 22 | const float F3 = 0.3333333; 23 | const float G3 = 0.1666667; 24 | float snoise(vec3 p) { 25 | vec3 s = floor(p + dot(p, vec3(F3))); 26 | vec3 x = p - s + dot(s, vec3(G3)); 27 | vec3 e = step(vec3(0.0), x - x.yzx); 28 | vec3 i1 = e*(1.0 - e.zxy); 29 | vec3 i2 = 1.0 - e.zxy*(1.0 - e); 30 | vec3 x1 = x - i1 + G3; 31 | vec3 x2 = x - i2 + 2.0*G3; 32 | vec3 x3 = x - 1.0 + 3.0*G3; 33 | vec4 w, d; 34 | w.x = dot(x, x); 35 | w.y = dot(x1, x1); 36 | w.z = dot(x2, x2); 37 | w.w = dot(x3, x3); 38 | w = max(0.6 - w, 0.0); 39 | d.x = dot(random3(s), x); 40 | d.y = dot(random3(s + i1), x1); 41 | d.z = dot(random3(s + i2), x2); 42 | d.w = dot(random3(s + 1.0), x3); 43 | w *= w; 44 | w *= w; 45 | d *= w; 46 | return dot(d, vec4(52.0)); } 47 | 48 | float shading(vec3 position){ 49 | vec3 l = normalize(light); 50 | return max(0.015, dot(position, l)); } 51 | 52 | float fnoise(vec3 position, const int octaves, float frequency, float persistence) { 53 | float total = 0.0; 54 | float maxAmplitude = 0.0; 55 | float amplitude = 1.0; 56 | total += snoise(position * frequency) * amplitude; 57 | frequency *= 2.0; 58 | maxAmplitude += amplitude; 59 | amplitude *= persistence; 60 | total += snoise(position * frequency) * amplitude; 61 | frequency *= 2.0; 62 | maxAmplitude += amplitude; 63 | amplitude *= persistence; 64 | total += snoise(position * frequency) * amplitude; 65 | frequency *= 2.0; 66 | maxAmplitude += amplitude; 67 | amplitude *= persistence; 68 | total += snoise(position * frequency) * amplitude; 69 | frequency *= 2.0; 70 | maxAmplitude += amplitude; 71 | amplitude *= persistence; 72 | total += snoise(position * frequency) * amplitude; 73 | frequency *= 2.0; 74 | maxAmplitude += amplitude; 75 | amplitude *= persistence; 76 | total += snoise(position * frequency) * amplitude; 77 | frequency *= 2.0; 78 | maxAmplitude += amplitude; 79 | amplitude *= persistence; 80 | return total / maxAmplitude; } 81 | 82 | float computeDiffuse(vec3 normal) { 83 | return dot( normal, vec3(1.) ); } 84 | 85 | void main() { 86 | vec2 p = vTex; 87 | float n1 = max( 88 | fnoise(vNormal.xyz, 6, 0.1, 0.8), 89 | fnoise(vNormal.zyx, 6, -0.1, 0.79) 90 | ); 91 | float n2 = fnoise(vNormal.xzy, 6, 0.1, 0.66); 92 | vec4 c = vec4(n1,n1,n1,1.); 93 | if ( n1 > 0.9 ) { c += vec4(n1,n1,n1,1.);} 94 | if ( n1 > 0.3 ) { c += vec4(n1,n2,n1,1.);} 95 | if ( n1 > 0.205 ) { c += vec4(0.,1.,0.,1.);} 96 | else if ( n1 > 0.2 ) { c += vec4(1.,1.,0.,1.);} 97 | else { c += vec4(n2*.05,n2*.05,1.,1.);} 98 | gl_FragColor = vec4( c.xyz * shading(vNormal.xyz), 1.);} 99 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/mars.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D tex0; 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform float time; 5 | uniform float temperature; 6 | uniform vec3 light; 7 | varying vec3 vNormal; 8 | varying vec2 vTex; 9 | 10 | #define PI 3.1415926535897932384626433832795 11 | 12 | vec3 random3(vec3 c) { 13 | float j = seed + 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0))); 14 | vec3 r; 15 | r.z = fract(512.0*j); 16 | j *= .125; 17 | r.x = fract(512.0*j); 18 | j *= .125; 19 | r.y = fract(512.0*j); 20 | return r-0.5; } 21 | 22 | const float F3 = 0.3333333; 23 | const float G3 = 0.1666667; 24 | float snoise(vec3 p) { 25 | vec3 s = floor(p + dot(p, vec3(F3))); 26 | vec3 x = p - s + dot(s, vec3(G3)); 27 | vec3 e = step(vec3(0.0), x - x.yzx); 28 | vec3 i1 = e*(1.0 - e.zxy); 29 | vec3 i2 = 1.0 - e.zxy*(1.0 - e); 30 | vec3 x1 = x - i1 + G3; 31 | vec3 x2 = x - i2 + 2.0*G3; 32 | vec3 x3 = x - 1.0 + 3.0*G3; 33 | vec4 w, d; 34 | w.x = dot(x, x); 35 | w.y = dot(x1, x1); 36 | w.z = dot(x2, x2); 37 | w.w = dot(x3, x3); 38 | w = max(0.6 - w, 0.0); 39 | d.x = dot(random3(s), x); 40 | d.y = dot(random3(s + i1), x1); 41 | d.z = dot(random3(s + i2), x2); 42 | d.w = dot(random3(s + 1.0), x3); 43 | w *= w; 44 | w *= w; 45 | d *= w; 46 | return dot(d, vec4(52.0)); } 47 | 48 | float shading(vec3 position){ 49 | vec3 l = normalize(light); 50 | return max(0.015, dot(position, l)); } 51 | 52 | float fnoise(vec3 position, const int octaves, float frequency, float persistence) { 53 | float total = 0.0; 54 | float maxAmplitude = 0.0; 55 | float amplitude = 1.0; 56 | total += snoise(position * frequency) * amplitude; 57 | frequency *= 2.0; 58 | maxAmplitude += amplitude; 59 | amplitude *= persistence; 60 | total += snoise(position * frequency) * amplitude; 61 | frequency *= 2.0; 62 | maxAmplitude += amplitude; 63 | amplitude *= persistence; 64 | total += snoise(position * frequency) * amplitude; 65 | frequency *= 2.0; 66 | maxAmplitude += amplitude; 67 | amplitude *= persistence; 68 | total += snoise(position * frequency) * amplitude; 69 | frequency *= 2.0; 70 | maxAmplitude += amplitude; 71 | amplitude *= persistence; 72 | total += snoise(position * frequency) * amplitude; 73 | frequency *= 2.0; 74 | maxAmplitude += amplitude; 75 | amplitude *= persistence; 76 | total += snoise(position * frequency) * amplitude; 77 | frequency *= 2.0; 78 | maxAmplitude += amplitude; 79 | amplitude *= persistence; 80 | return total / maxAmplitude; } 81 | 82 | float computeDiffuse(vec3 normal) { 83 | return dot( normal, vec3(1.) ); } 84 | 85 | void main() { 86 | vec2 p = vTex; 87 | float n1 = max( 88 | fnoise(vNormal.xyz, 6, 0.1, 0.8), 89 | fnoise(vNormal.zyx, 5, -0.1, 0.79) 90 | ); 91 | float n2 = fnoise(vNormal.xzy, 6, 0.1, 0.66); 92 | vec4 c = vec4(n1,n1,n1,1.); 93 | if ( n1 > 0.9 ) { c += vec4(n1,n1,n1,1.);} 94 | if ( n1 > 0.3 ) { c += vec4(n1,n2,n1,1.);} 95 | if ( n1 > 0.205 ) { c += vec4(1.,0.,0.,1.);} 96 | else if ( n1 > 0.2 ) { c += vec4(.8,.2,0.,1.);} 97 | else { c += vec4(.1,n2*.05,n2*.05,1.);} 98 | gl_FragColor = vec4( c.xyz * shading(vNormal.xyz), 1.);} 99 | -------------------------------------------------------------------------------- /mod/nuu-naev/build.coffee: -------------------------------------------------------------------------------- 1 | global.marked = require 'marked' 2 | 3 | markdown = (src,tgt)-> (c)-> 4 | fs.readFile src, (error,data)-> 5 | return c error if error 6 | txt = do data.toString 7 | txt = txt.replace ' , ', ', ' 8 | txt = txt.replace ' ,', ', ' 9 | while m = txt.match /Author:([^,]+), / 10 | txt = txt.replace m[0], "**" + m[1].trim() + "**" 11 | while m = txt.match /License:([^\n]+)\n/ 12 | txt = txt.replace m[0], " (***" + m[1].trim() + "***)\n" 13 | txt = txt.replace /\ \ \ \ \ \ \ \*\ \*\n/g, '' 14 | txt = txt.replace /,\ \ \(\*\*\*PD\)\*\*\*\)/g, ' (PD)' 15 | txt = txt.replace /\ \*\ \*\*/g, '## **' 16 | txt = txt.replace '## **Bobbens', '\n## **Bobbens' 17 | blurb = """ 18 | ## Licenses 19 | These refer to the contributors of the [NAEV](http://blog.naev.org/) project. 20 | 21 | """ 22 | o = [] 23 | authorP = author = mode1 = mode2 = null 24 | lines = txt.split('\n') 25 | txt = n while txt isnt n = txt.replace '\n\n','\n' 26 | for line,i in lines 27 | if line.match /\#/ 28 | authorP = author = mode1 = mode2 = null 29 | author = line 30 | if line is ' * outfit' 31 | mode1 = 'outfit' 32 | else if line is ' * planet' 33 | mode1 = 'planet' 34 | else if line is ' * commodity' 35 | mode1 = 'commodity' 36 | else if line is ' * space' 37 | mode2 = 'space' 38 | else if line is ' * store' 39 | mode2 = 'store' 40 | else if line is ' * exterior' 41 | mode2 = 'exterior' 42 | else if line.match /png$/ 43 | n = line.replace /.* /, '' 44 | p = ['build',mode1,mode2,n].join '/' 45 | continue unless fs.existsSync p 46 | o.push authorP = author unless authorP 47 | o.push '![' + n + '](' + p + ')' 48 | 49 | txt = o.join '\n' 50 | fs.writeFile tgt.replace('html','txt'), blurb + txt, -> 51 | fs.writeFile tgt, marked.marked(blurb + txt), c 52 | null 53 | null 54 | 55 | module.exports.build = (c) -> 56 | depend(dirs)( -> 57 | $s [ 58 | fetch 'contrib/naev.zip', 'https://github.com/bobbens/naev/archive/master.zip' 59 | unzip 'contrib/naev.zip', 'contrib/naev-master' 60 | mkdir 'build/gfx' 61 | markdown 'contrib/naev-master/dat/gfx/ARTWORK_LICENSE', 'build/ARTWORK_LICENSE.html' 62 | markdown 'contrib/naev-master/dat/snd/SOUND_LICENSE', 'build/SOUND_LICENSE.html' 63 | link 'contrib/naev-master/dat/snd/sounds', 'build/sounds' 64 | linkFilesIn 'contrib/naev-master/dat/gfx/spfx', 'build/gfx' 65 | linkFlatten 'contrib/naev-master/dat/gfx/ship', 'build/gfx' 66 | linkFilesIn 'contrib/naev-master/dat/gfx/bkg', 'build/gfx' 67 | linkFilesIn 'contrib/naev-master/dat/gfx/bkg/star', 'build/gfx' 68 | linkFilesIn 'contrib/naev-master/dat/gfx/planet/space', 'build/gfx' 69 | linkFilesIn 'contrib/naev-master/dat/gfx/outfit/space', 'build/gfx' 70 | link 'contrib/naev-master/dat/gfx/outfit/store', 'build/gfx/store' 71 | generate 'build/objects_naev.json', path.join __dirname, 'import.coffee' 72 | ], c ) 73 | -------------------------------------------------------------------------------- /mod/nuu/server/objects.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | Ship::dropLoot = -> 24 | do @update 25 | newRandom = (classObj) => new classObj state: 26 | S: $moving 27 | x: @x + -@size/2 + Math.random()*@size 28 | y: @y + -@size/2 + Math.random()*@size 29 | v: [ @v[0] + Math.random() * .2 - .1, @v[1] + Math.random()* .2 - .1 ] 30 | newRandom Cargo for i in [0...10] 31 | newRandom Debris for i in [0...10] 32 | return 33 | 34 | Ship::resetHostiles = -> 35 | h = @hostile; @hostile = [] 36 | return unless h 37 | Array.remove s.hostile, @ for s in h when s.hostile? 38 | NUU.jsoncastTo @, hostile:@hostile if @inhabited 39 | 40 | Ship::respawn = -> 41 | @locked = true 42 | @respawning = yes 43 | @resetHostiles() 44 | setTimeout ( => 45 | @dropLoot() 46 | ), 4000 47 | setTimeout ( => 48 | do @reset 49 | if @user 50 | opts = @user.spawnState() 51 | @setState opts.state; delete opts.state 52 | Object.assign @, opts 53 | else 54 | @x = Math.random()*100 55 | @y = Math.random()*100 56 | @setState S:$moving, x:@x, y:@y, v:[0,0] 57 | if @state.S is $moving 58 | @locked = true 59 | setTimeout ( => @locked = false ), 3000 60 | if @landedAt 61 | NUU.jsoncastTo @, landed: @landedAt.id 62 | do @update 63 | NET.mods.write @, 'spawn' 64 | ), 5000 65 | 66 | Ship::hit = (src,wp) -> 67 | return if @destructing 68 | switch Weapon.impactLogic.call @, wp 69 | when Weapon.impactType.hit 70 | NUU.emit 'ship:hit', @, src, @shield, @armour 71 | NET.mods.write @, 'hit', @shield, @armour 72 | when Weapon.impactType.shieldsDown 73 | NUU.emit 'ship:shieldsDown', @, src 74 | NET.mods.write @, 'shield', @shield, @armour 75 | when Weapon.impactType.disabled 76 | NUU.emit 'ship:disabled', @, src 77 | NET.mods.write @, 'disabled', @shield, @armour 78 | when Weapon.impactType.destroyed 79 | NUU.emit 'ship:destroyed', @, src 80 | NET.mods.write @, 'destroyed', 0, 0 81 | return 82 | 83 | Station::hit = (src,wp) -> 84 | return if @destructing 85 | switch Weapon.impactLogic.call @, wp 86 | when Weapon.impactType.hit 87 | NUU.emit 'station:hit', @, src, @shield, @armour 88 | NET.mods.write @, 'hit', @shield, @armour 89 | when Weapon.impactType.shieldsDown 90 | NUU.emit 'station:shieldsDown', @, src 91 | when Weapon.impactType.disabled 92 | NUU.emit 'station:disabled', @, src 93 | when Weapon.impactType.destroyed 94 | NUU.emit 'station:destroyed', @, src 95 | NET.mods.write @, 'destroyed', 0, 0 96 | return 97 | -------------------------------------------------------------------------------- /mod/core/common/item.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | ### 24 | this creates the game model, not an instance of a shot 25 | think of it as a factory 26 | ### 27 | 28 | $public class Outfit 29 | constructor: (name) -> 30 | @tpl = Item.byName[name] 31 | Object.assign @, @tpl 32 | 33 | $public class Item 34 | @byId: {} 35 | @byName: {} 36 | @byType: ship:{}, station:{} 37 | @byProp: {} 38 | @byClass: ship:[],outfit:[],gov:[],skill:[],com:[],stellar:[],station:[] 39 | 40 | Item.random = (opts={})-> 41 | item = Array.random Object.values Item.byId 42 | return item unless opts.not 43 | while opts.not.includes item.type 44 | item = Array.random Object.values Item.byId 45 | return item 46 | 47 | Item.init = (seed) -> 48 | items = seed 49 | console.log ':nuu', 'init:items' if debug 50 | Item.db = items 51 | NUU.emit 'init:items:pre', items 52 | id = 0 53 | for k,o of Station.template 54 | o.class = "station" 55 | o.name = o.name || k 56 | Item.byClass.station.push Item.byType.station[o.name] = Item.byId[o.itemId = id] = Item.byName[o.name] = o 57 | console.log 'item', 'Station', id, o.name if debug 58 | id++ 59 | NUU.emit 'init:items', items 60 | for o in items 61 | Item.byClass[o.class].push o 62 | if o.class is 'ship' 63 | Item.byType['ship'][o.name] = Item.byId[o.itemId = id] = Item.byName[o.name] = o 64 | Ship.byTpl[id] = o.name 65 | Ship.byName[o.name] = id 66 | id++ 67 | else if o.class is 'outfit' 68 | Item.byId[o.itemId = id] = Item.byName[o.name] = o 69 | size = o.size || 'small' 70 | t = ( 71 | if (s = o.slot) then (if s.$t then s.$t else s) 72 | else if o.extends is 'Ammo' then 'ammo' 73 | else 'cargo' ) 74 | Item.byType[t] = {} unless Item.byType[t] 75 | Item.byType[t][size] = {} unless Item.byType[t][size] 76 | Item.byType[t][size][o.name] = o 77 | if o.type 78 | t = o.type.split(' ').pop() 79 | Item.byType[t] = {} unless Item.byType[t] 80 | Item.byType[t][o.name] = o 81 | if s and (t = s.prop) 82 | Item.byProp[t] = {} unless Item.byProp[t] 83 | Item.byProp[t][o.name] = o 84 | id++ 85 | else if o.class is 'com' 86 | else if o.class is 'gov' 87 | else console.log 'x', o 88 | 89 | for type, items of Item.byType when items.medium? 90 | if Object.keys(items.medium).length is 0 and Object.keys(items.large).length is 0 91 | Item.byType[type] = items.small 92 | Item.byName.CheatersRagnarokBeam.turret = yes 93 | Item.byName.CheatersRagnarokBeam.stats.track = 1.6 94 | NUU.emit 'init:items:done', items 95 | return seed 96 | -------------------------------------------------------------------------------- /mod/core/client/user.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | NUU.on 'login:test', -> 24 | Scanner.scale = 500000 25 | # Scanner.toggleFullscreen() 26 | # Target.set $obj.byName.Venus 27 | return 28 | 29 | $public class User 30 | _vehicle: null 31 | primary: id: 0 32 | secondary: id: 0 33 | constructor: (opts)-> 34 | Object.assign @, opts 35 | console.log 'user', @ if debug 36 | if @user.nick.match /^test[0-9]+$/ 37 | NET.once 'sync', -> NUU.emit 'login:test' 38 | return 39 | 40 | Object.defineProperty User::, 'vehicle', 41 | set: (v) -> 42 | return unless v 43 | window.VEHICLE = @_vehicle = v 44 | v.hide() 45 | v.layer = GFX.PLAYER 46 | v.show() 47 | GFX.repositionPlayer() 48 | @vehicleId = v.id 49 | NUU.emit 'enterVehicle', v 50 | switchWeap(-1) NUU.player, 'primary' 51 | switchWeap(-1) NUU.player, 'secondary' 52 | console.log 'user', 'enterVehicle', v.id if debug 53 | $obj.select yes 54 | get: -> @_vehicle 55 | 56 | switchWeap = (mutate)-> (player,trigger='primary') -> 57 | primary = trigger is 'primary' 58 | ws = player.vehicle.slots.weapon 59 | ct = ws.length 60 | tg = player[trigger] 61 | unless mutate is -1 62 | id = 0 if isNaN id = parseInt tg.id 63 | id = max 0, min ct, id 64 | tg.id = id = mutate id, ct 65 | if ct is id 66 | tg.slot = weap = null 67 | tg.trigger = tg.release = -> 68 | else 69 | tg.slot = weap = ws[id].equip 70 | tg.trigger = -> NET.weap.write 'trigger', primary, id, if TARGET then TARGET.id else undefined 71 | tg.release = -> NET.weap.write 'release', primary, id, if TARGET then TARGET.id else undefined 72 | NUU.emit 'switchWeapon', trigger, weap 73 | Ship::setWeap = (idx,trigger='primary')-> switchWeap( -> idx )(NUU.player,'primary') 74 | Ship::nextWeap = switchWeap (id,ct)-> if ct < 1 then 0 else ++id % (ct + 1 ) 75 | Ship::prevWeap = switchWeap (id,ct)-> if ct < 1 then 0 else ( --id + ct ) % (ct + 1 ) 76 | 77 | NET.on 'switchShip', (opts) -> 78 | console.log 'user', 'switchShip', opts if debug 79 | NUU.player.vehicle = Ship.byId[opts.i] 80 | NET.emit 'setMount', opts.mount 81 | $obj.select yes 82 | return 83 | 84 | NET.on 'setMount', (list) -> 85 | VEHICLE.mount = list 86 | NUU.player.mountId = id = list.indexOf NUU.player.user.nick 87 | console.log 'user', 'setMount', id # if debug 88 | NUU.player.mount = VEHICLE.mountSlot[id] 89 | NUU.player.equip = VEHICLE.mountSlot[id].equip if NUU.player.mount 90 | VEHICLE.name + '['+ id + ':' + VEHICLE.mountType[id] + ']\n' + VEHICLE.mount 91 | .map (i,k)-> if i then "[#{k}]i" else false 92 | .filter (i)-> i 93 | .join ' ' 94 | 95 | NUU.frame = 0 96 | -------------------------------------------------------------------------------- /mod/core/common/buffer.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | readFLoatLE = (mLen, nBytes) -> (offset)-> 24 | e = m = null; nBits = -7 25 | eLen = nBytes * 8 - mLen - 1 26 | eBias = ( eMax = (1 << eLen) - 1 ) >> 1 27 | i = nBytes + d = -1 28 | s = @[offset + i] 29 | i += d 30 | e = s & (1 << -nBits) - 1 31 | s >>= -nBits 32 | nBits += eLen 33 | while nBits > 0 34 | e = e * 256 + @[offset + i] 35 | i += d 36 | nBits -= 8 37 | m = e & (1 << -nBits) - 1 38 | e >>= -nBits 39 | nBits += mLen 40 | while nBits > 0 41 | m = m * 256 + @[offset + i] 42 | i += d 43 | nBits -= 8 44 | if e == 0 then e = 1 - eBias 45 | else if e == eMax 46 | return if m then NaN else ( if s then -1 else 1 ) * Infinity 47 | else 48 | m = m + 2 ** mLen 49 | e = e - eBias 50 | return ( if s then -1 else 1 ) * m * 2 ** ( e - mLen ) 51 | 52 | writeFloatLE = (mLen, nBytes)-> (value, offset)-> 53 | e = m = c = null; i = 0; d = 1 54 | eLen = nBytes * 8 - mLen - 1 55 | eBias = ( eMax = (1 << eLen) - 1 ) >> 1 56 | rt = if mLen == 23 then 2 ** (-24) - 2 ** (-77) else 0 57 | s = if value < 0 or value == 0 and 1 / value < 0 then 1 else 0 58 | value = Math.abs value 59 | if isNaN(value) or value == Infinity 60 | m = if isNaN(value) then 1 else 0 61 | e = eMax 62 | else 63 | e = Math.floor Math.log(value) / Math.LN2 64 | ( e--; c *= 2 ) if value * (c = 2 ** (-e)) < 1 65 | value += if e + eBias >= 1 then rt / c else rt * 2 ** ( 1 - eBias ) 66 | ( e++; c /= 2 ) if value * c >= 2 67 | if e + eBias >= eMax 68 | ( m = 0; e = eMax ) 69 | else if e + eBias >= 1 70 | m = (value * c - 1) * 2 ** mLen 71 | e = e + eBias 72 | else 73 | m = value * 2 ** (eBias - 1) * 2 ** mLen 74 | e = 0 75 | while mLen >= 8 76 | @[offset + i] = m & 0xff 77 | i += d; m /= 256; mLen -= 8 78 | e = e << mLen | m 79 | eLen += mLen 80 | while eLen > 0 81 | @[offset + i] = e & 0xff 82 | i += d; e /= 256; eLen -= 8 83 | @[offset + i - d] |= s * 128 84 | return 85 | 86 | Uint8Array::readUInt16LE = (offset)-> @[offset] | ( @[offset + 1] << 8 ) 87 | Uint8Array::writeUInt16LE = (value,offset)-> @[offset] = (value & 0xff); @[offset + 1] = (value >>> 8) 88 | Uint8Array::readUInt32LE = (offset)-> ( (@[offset]) | (@[offset + 1] << 8) | (@[offset + 2] << 16) ) + ( @[offset + 3] * 0x1000000 ) 89 | Uint8Array::writeUInt32LE = (value,offset)-> @[offset + 3] = (value >>> 24); @[offset + 2] = (value >>> 16); @[offset + 1] = (value >>> 8); @[offset] = (value & 0xff) 90 | Uint8Array::readFloatLE = readFLoatLE 23,4 91 | Uint8Array::writeFloatLE = writeFloatLE 23,4 92 | Uint8Array::readDoubleLE = readFLoatLE 52,8 93 | Uint8Array::writeDoubleLE = writeFloatLE 52,8 94 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/sun.frag: -------------------------------------------------------------------------------- 1 | 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform vec4 temperature; 5 | uniform float time; 6 | uniform vec3 light; 7 | 8 | varying vec3 vNormal; 9 | varying vec2 vTex; 10 | 11 | #define PI 3.1415926535897932384626433832795 12 | 13 | vec3 random3(vec3 c) { 14 | float j = seed + 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0))); 15 | vec3 r; 16 | r.z = fract(512.0*j); 17 | j *= .125; 18 | r.x = fract(512.0*j); 19 | j *= .125; 20 | r.y = fract(512.0*j); 21 | return r-0.5; 22 | } 23 | 24 | const float F3 = 0.3333333; 25 | const float G3 = 0.1666667; 26 | float snoise(vec3 p) { 27 | vec3 s = floor(p + dot(p, vec3(F3))); 28 | vec3 x = p - s + dot(s, vec3(G3)); 29 | vec3 e = step(vec3(0.0), x - x.yzx); 30 | vec3 i1 = e*(1.0 - e.zxy); 31 | vec3 i2 = 1.0 - e.zxy*(1.0 - e); 32 | vec3 x1 = x - i1 + G3; 33 | vec3 x2 = x - i2 + 2.0*G3; 34 | vec3 x3 = x - 1.0 + 3.0*G3; 35 | vec4 w, d; 36 | w.x = dot(x, x); 37 | w.y = dot(x1, x1); 38 | w.z = dot(x2, x2); 39 | w.w = dot(x3, x3); 40 | w = max(0.6 - w, 0.0); 41 | d.x = dot(random3(s), x); 42 | d.y = dot(random3(s + i1), x1); 43 | d.z = dot(random3(s + i2), x2); 44 | d.w = dot(random3(s + 1.0), x3); 45 | w *= w; 46 | w *= w; 47 | d *= w; 48 | return dot(d, vec4(52.0)); } 49 | 50 | float snoise(vec3 uv, float res){ 51 | const vec3 s = vec3(1e0, 1e2, 1e4); 52 | uv *= res; 53 | vec3 uv0 = floor(mod(uv, res))*s; 54 | vec3 uv1 = floor(mod(uv+vec3(1.), res))*s; 55 | vec3 f = fract(uv); f = f*f*(3.0-2.0*f); 56 | vec4 v = vec4(uv0.x+uv0.y+uv0.z, uv1.x+uv0.y+uv0.z, uv0.x+uv1.y+uv0.z, uv1.x+uv1.y+uv0.z); 57 | vec4 r = fract(sin(v*1e-3)*1e5); 58 | float r0 = mix(mix(r.x, r.y, f.x), mix(r.z, r.w, f.x), f.y); 59 | r = fract(sin((v + uv1.z - uv0.z)*1e-3)*1e5); 60 | float r1 = mix(mix(r.x, r.y, f.x), mix(r.z, r.w, f.x), f.y); 61 | return mix(r0, r1, f.z)*2.-1.; } 62 | 63 | float snoiseFractal(vec3 m) { 64 | return 0.5333333 * 65 | snoise(m,2.) + 66 | 0.2666667 * snoise(2.0*m,2.) + 67 | 0.1333333 * snoise(4.0*m,2.) + 68 | 0.0666667 * snoise(8.0*m,2.); } 69 | 70 | float freqs[4]; 71 | 72 | float shading(vec4 position){ 73 | vec3 l = normalize(light); 74 | return max(0.08, dot(vNormal, l)); } 75 | 76 | vec3 fineNoise(vec2 p){ 77 | float xx = snoise(vec3(p*4.,0.), 100.); 78 | float yy = snoise(vec3(p*4.,0.), 100.); 79 | float zz = snoise(vec3(p*4.,0.), 100.); 80 | float x = xx + snoise(vec3(p*20.,10.), 64.); 81 | float y = yy + snoise(vec3(p*20.,10.), 64.); 82 | float z = zz + snoise(vec3(p*20.,10.), 64.); 83 | return vec3(x,x,x); } 84 | 85 | float u_k = .1; 86 | vec3 plasma(vec2 p){ 87 | float v = 0.0; 88 | vec2 c = p * u_k - u_k/2.0; 89 | v += sin((c.x+time)); 90 | v += sin((c.y+time)/2.0); 91 | v += sin((c.x+c.y+time)/2.0); 92 | c += u_k/2.0 * vec2(sin(time/3.0), cos(time/2.0)); 93 | v += sin(sqrt(c.x*c.x+c.y*c.y+1.0)+time); 94 | v = v/2.0; 95 | vec3 col = vec3(sin(PI*v)); 96 | return col; } 97 | 98 | void main() { 99 | vec2 p = vTex; 100 | vec3 color; 101 | float unExposure = 3.0; 102 | float unGamma = 1.0 / 0.7; 103 | // base + noise 104 | color.rgb = temperature.rgb + temperature.rgb * plasma(p * 2000.) * fineNoise(p); 105 | // float theta = 1.0 - dot(0.5, p); 106 | // color = color + total - theta; 107 | color = 1.0 - exp(color * -unExposure); // HDR exposure 108 | color = pow(color, vec3(unGamma)); // Gamma correction 109 | gl_FragColor = vec4(color, 1.0); 110 | } 111 | -------------------------------------------------------------------------------- /mod/nuu/artwork/noscanimg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 24 | 43 | 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 65 | ERR 76 | 77 | 78 | -------------------------------------------------------------------------------- /mod/core/common/inventory.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | if isServer 24 | { Database, Schema } = $tag 25 | 26 | NUU.on "server:db", ( -> 27 | # $tag.db 'InventoryDB' 28 | InventorySchema = new Schema 29 | id: { type: Number, default: 1 } 30 | name: { type: String, required: true } 31 | description: { type: String, default: '' } 32 | type: { type: String, required: true } 33 | amount: { type: Number, default: 0 } 34 | price: { type: Number, default: 0 } 35 | weight: { type: Number, default: 0 } 36 | image: { type: String, default: '' } 37 | created: { type: Date, default: Date.now } 38 | updated: { type: Date, default: Date.now } 39 | deleted: { type: Date, default: null } 40 | global.InventoryDB = $tag.model 41 | name: 'InventoryDB' 42 | path: 'db/InventoryDB' 43 | schema: InventorySchema 44 | console.log Object.keys global.InventoryDB 45 | return 46 | ) if isServer 47 | 48 | $public class Inventory 49 | @byKey: {} 50 | create: yes 51 | constructor: (opts)-> 52 | { @key, @create, @data } = opts 53 | return existing if existing = Inventory.byKey[@key] 54 | ( @[k] = v for k,v of EventEmitter::; EventEmitter.call @ ) if isClient 55 | Inventory.byKey[@key] = @ 56 | do @read if @key 57 | do @tally if @data 58 | 59 | Inventory::close = -> delete Inventory.byKey[@key] 60 | 61 | Inventory::tally = -> 62 | @types = Object.keys(@data).length 63 | @total = Object.values(@data).reduce ( (v,i)-> v += i ), 0 64 | return 65 | 66 | Inventory::read = NUU.$target 67 | server: -> 68 | @exists = false isnt @data = InventoryDB.$.getSync(@key) || {} 69 | return if @data or not @create 70 | @write @data = {} 71 | return 72 | client: -> 73 | NET.json inventory_read: @key 74 | return 75 | 76 | Inventory::write = NUU.$target 77 | server: -> 78 | do @tally 79 | InventoryDB.$.set @key, @data if @key 80 | return 81 | client: -> 82 | 83 | Inventory::has = (item,count=1)-> 84 | return false unless d = @data[item] 85 | return false unless d >= count 86 | return d 87 | 88 | Inventory::add = (item,count=1)-> 89 | @data[item] = ( @data[item] || 0 ) + count 90 | do @write 91 | return 92 | 93 | Inventory::give = (other,item,count=1)-> 94 | return false unless @get item, count 95 | other.add item, count 96 | do @write 97 | true 98 | 99 | Inventory::get = (item,count=1)-> 100 | return false unless @data[item]? and @data[item] >= count 101 | @data[item] -= count 102 | do @write 103 | true 104 | 105 | NET.on "inventory_read", (msg,src)-> 106 | return src.error '_no_handle' unless u = src.handle 107 | i = new Inventory Object.assign msg, create:no 108 | src.json inventory_write: key:msg.key, data: i.data 109 | i.close() 110 | return 111 | 112 | NET.register "inventory_write", 113 | server: (msg,src)-> 114 | i = new Inventory msg 115 | src.json inventory_write: key:msg.key, data: i.data 116 | i.close() 117 | client: (msg)-> 118 | return unless i = Inventory.byKey[msg.key] 119 | i.data = msg.data 120 | i.emit 'read', i 121 | return 122 | -------------------------------------------------------------------------------- /pd/record.js: -------------------------------------------------------------------------------- 1 | const { v4: uuid } = require("uuid"); 2 | const util = require("util"); 3 | 4 | const SchemaRecord = ({ Schema, $schema, keys, requireds, type, defaults }) => { 5 | class Record { 6 | constructor({ id, ...fields }) { 7 | this.data = {}; 8 | for (const k of keys) { 9 | const defaultValue = defaults[k]; 10 | const isFunction = typeof defaultValue === "function"; 11 | fields[k] === undefined && 12 | (defaultValue && isFunction 13 | ? (this.data[k] = defaultValue()) 14 | : defaultValue !== undefined && 15 | (this.data[k] = clone(defaultValue))); 16 | } 17 | this.id = id || uuid(); 18 | Object.assign(this.data, fields); 19 | } 20 | async save() { 21 | await this.$.ready; 22 | const errors = []; 23 | for (const k of requireds) 24 | if (!this.data[k]) errors.push(`required[${k}]`); 25 | if (errors.length > 0) 26 | throw new Error(`save error: ${errors.join(", ")}`); 27 | await this.$.set(this.id, this.data); 28 | return this; 29 | } 30 | 31 | delete() { 32 | return this.$.delete(this.id); 33 | } 34 | toJSON = () => ({ ...this.data, id: this.id }); 35 | inspect() { 36 | return JSON.stringify({ ...this.data, id: this.id }, null, 2); 37 | } 38 | static each = (fn) => 39 | Record.$.each(([k, r]) => fn(new Record({ id: k, ...r }))); 40 | static forEach = (fn) => Record.$.forEach(fn); 41 | static all = () => Record.$.all().then((a) => a.map((r) => new Record(r))); 42 | static find = (query) => { 43 | const { $post, $filter } = Record; 44 | return Record.$.find(query, { $schema, $post, $filter }); 45 | }; 46 | static findOne = async (query) => { 47 | const { $post, $filter } = Record; 48 | const list = await Record.$.find(query, { 49 | limit: 1, 50 | $schema, 51 | $post, 52 | $filter, 53 | }); 54 | return list[0]; 55 | }; 56 | static findById = async (id) => { 57 | const rec = await Record.$.get(id); 58 | return new Record({ ...rec, id }); 59 | }; 60 | static findByIdSync = async (id) => { 61 | const rec = await Record.$.getSync(id); 62 | return new Record({ ...rec, id }); 63 | }; 64 | static $filter = (cursor) => cursor.toArray(); 65 | static $post = async (id, value, cursor) => { 66 | if (cursor._populate) 67 | await Promise.all( 68 | cursor._populate.map(async (field) => { 69 | const descriptor = this.$.Model?.fields?.[field]; 70 | if ( 71 | !descriptor || 72 | descriptor.type !== $schema.constructor.Types.ObjectId 73 | ) 74 | return; 75 | value[field] = await Schema.Types[descriptor.ref].findById( 76 | value[field] 77 | ); 78 | //console.log(field, value[field], descriptor); 79 | return; 80 | }) 81 | ); 82 | return new Record({ id, ...value }); 83 | }; 84 | static delete = (query) => Record.$.delete(query); 85 | static deleteOne = (query) => Record.$.deleteOne(query); 86 | } 87 | Object.assign(Record.prototype, $schema.methods); 88 | 89 | Object.defineProperties(Record.prototype, { 90 | $schema: { enumerable: false, value: $schema }, 91 | toJSON: { enumerable: false, value: Record.prototype.toJSON }, 92 | toString: { enumerable: false, value: Record.prototype.toString }, 93 | [util.inspect.custom]: { 94 | enumerable: false, 95 | value: Record.prototype.inspect, 96 | }, 97 | data: { enumerable: false, writable: true }, 98 | }); 99 | return Record; 100 | }; 101 | 102 | function clone(value) { 103 | if (typeof value === "object") return JSON.parse(JSON.stringify(value)); 104 | return value; 105 | } 106 | 107 | module.exports = SchemaRecord; 108 | -------------------------------------------------------------------------------- /mod/nuu/artwork/logo_2018.svg: -------------------------------------------------------------------------------- 1 | 2 | 114 | -------------------------------------------------------------------------------- /mod/nuu/client/starfield.coffee: -------------------------------------------------------------------------------- 1 | 2 | # ███ ██ ███████ ██████ ██ ██ ██ █████ 3 | # ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ 4 | # ██ ██ ██ █████ ██████ ██ ██ ██ ███████ 5 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 6 | # ██ ████ ███████ ██████ ██████ ███████ ██ ██ 7 | 8 | NUU.on 'rules', -> 9 | # Nebula.deterministic = new Deterministic rules.systemName + "-nebulae" 10 | # Nebula.random() for i in [0..2+max 1, Math.ceil Nebula.deterministic.double()*5] 11 | return 12 | 13 | $public class Nebula 14 | @list: [ "02","16","21","25","29","33","04","17","22","26","30","34","10","19","23","27","31","12","20","24","28","32" ] 15 | @random:-> 16 | idx = round Nebula.deterministic.double() * ( Nebula.list.length - 1 ) 17 | img = Nebula.list[idx] 18 | n = PIXI.Sprite.from "build/gfx/nebula#{img}.png" 19 | n.position.set( 20 | Nebula.deterministic.double() * 4*GFX.width - 2*GFX.width 21 | Nebula.deterministic.double() * 4*GFX.height - 2*GFX.height ) 22 | GFX.nebulae.addChild n 23 | 24 | # ███████ ████████ █████ ██████ ███████ ██ ███████ ██ ██████ 25 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 26 | # ███████ ██ ███████ ██████ █████ ██ █████ ██ ██ ██ 27 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 28 | # ███████ ██ ██ ██ ██ ██ ██ ██ ███████ ███████ ██████ 29 | 30 | $public class GFX.StarfieldLayer 31 | count:1000 32 | constructor:-> 33 | VEHICLE.v = [random(),random()] 34 | @geometry = new THREE.Geometry 35 | i = 0 36 | while i++ < @count 37 | @geometry.vertices.push new THREE.Vector3(0,0,0) 38 | map = GFX.loader.load 'build/gfx/moon-D02.png' 39 | # material = new THREE.PointsMaterial transparent:true, alphaTest:0.1, size:1.5 40 | # GFX.debugShader 'FRAGMENT_SHADER', GFX.StarfieldLayer.fragment 41 | # GFX.debugShader 'VERTEX_SHADER', GFX.StarfieldLayer.vertex 42 | @material = new THREE.ShaderMaterial 43 | precision:'highp' 44 | transparent: true 45 | depthWrite: false 46 | uniforms: 47 | uScreen: value: [GFX.width,GFX.height] 48 | uOffset: value: [0,0] 49 | uMap: value: map 50 | fragmentShader: GFX.StarfieldLayer.fragment 51 | vertexShader: GFX.StarfieldLayer.vertex 52 | blending: THREE.AdditiveBlending 53 | # transformFeedbackVaryings: outPosition: 'position' 54 | @particles = new THREE.Points @geometry, @material 55 | @particles.for = 'starfield' 56 | @randomize() 57 | GFX.scene.add @particles 58 | GFX.children.push @ 59 | GFX.on 'resize', @randomize.bind(@) 60 | @lastUpdate = performance.now() 61 | randomize:-> 62 | { width,height,wdb2,hgb2 } = GFX 63 | return if @lastWidth is width and @lastHeight is height 64 | @lastWidth = width; @lastHeight = height 65 | pos = @geometry.vertices; i = 0 66 | while i < @count 67 | p = pos[i] 68 | p.z = random() 69 | p.x = -wdb2 + width *Math.random() 70 | p.y = -wdb2 + height*Math.random() 71 | i++ 72 | @material.uniforms.uScreen.value = [width,height] 73 | @geometry.verticesNeedUpdate = true 74 | @lastUpdate = performance.now() 75 | return 76 | update:(time=performance.now())-> 77 | [vx,vy] = VEHICLE.v 78 | svx = svy = 0 79 | m = min 0.2, mag = Math.sqrt vx*vx + vy*vy 80 | if m isnt 0 81 | svx = vx / mag * m 82 | svy = vy / mag * m 83 | uniforms = @material.uniforms 84 | dt = time - @lastUpdate 85 | uniforms.uOffset.value[0] += -svx * dt 86 | uniforms.uOffset.value[1] += svy * dt 87 | @material.needsUpdate = true 88 | @lastUpdate = time 89 | return 90 | 91 | GFX.StarfieldLayer.vertex = """ 92 | uniform highp vec2 uScreen; 93 | uniform highp vec2 uOffset; 94 | varying float vAlpha; 95 | void main() { 96 | vAlpha = (position.z + abs(sin(position.x + position.y))) / 4.; 97 | highp vec3 newPosition = vec3( 98 | -uScreen.x/2. + mod(position.x + uOffset.x *vAlpha,uScreen.x), 99 | -uScreen.y/2. + mod(position.y + uOffset.y *vAlpha,uScreen.y), 100 | position.z ); 101 | gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 ); 102 | gl_PointSize = 3.5 + abs(sin(position.x))*position.z; } 103 | """ 104 | 105 | GFX.StarfieldLayer.fragment = """ 106 | uniform sampler2D uMap; 107 | varying float vAlpha; 108 | void main() { 109 | vec4 tex = texture2D( uMap, gl_PointCoord ); 110 | gl_FragColor = vec4( 1., 1., 1., tex.a * vAlpha * .2 ); } 111 | """ 112 | -------------------------------------------------------------------------------- /mod/core/client/cache.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | $public class Bottle 24 | constructor:(@limit)-> @stack = []; @active = 0 25 | next: => 26 | if @stack.length is 0 then @active-- 27 | else @stack.shift() @next 28 | add: (fnc) => 29 | if @active < @limit then fnc @next, @active++ 30 | else @stack.push fnc 31 | 32 | $b = new Bottle(3) 33 | URL = window.URL or window.webkitURL 34 | indexedDB = window.indexedDB or window.webkitIndexedDB or window.mozIndexedDB or window.OIndexedDB or window.msIndexedDB 35 | iDBtx = window.IDBTransaction or window.webkitIDBTransaction or window.OIDBTransaction or window.msIDBTransaction 36 | 37 | $static 'Cache', new class BlobCacheIndexedDB 38 | constructor: -> 39 | dbVersion = 1.0 40 | createObjectStore = (dataBase) -> dataBase.createObjectStore 'nuu' 41 | req = indexedDB.open 'nuucache', dbVersion 42 | req.onerror = (event) -> console.log 'data', 'Error creating/accessing IndexedDB database' 43 | req.onupgradeneeded = (event) -> createObjectStore event.target.result 44 | req.onsuccess = (event) => 45 | console.log 'data', 'Success creating/accessing IndexedDB database' if debug 46 | @db = req.result 47 | @db.onerror = (event) -> console.log 'data','Error creating/accessing IndexedDB database' 48 | if @db.setVersion # Interim solution for Google Chrome to create an objectStore. Will be deprecated 49 | if @db.version isnt dbVersion 50 | setVersion = @db.setVersion dbVersion 51 | setVersion.onsuccess = => ready createObjectStore @db 52 | else do ready 53 | else do ready 54 | null 55 | @get_ = @get; queue = {} 56 | @get = (path,callback) -> 57 | l = queue[path] || queue[path] = [] 58 | l.push callback if -1 is l.indexOf callback 59 | ready = => 60 | @get = @get_ 61 | @get k, c for c in v for k, v of queue 62 | NUU.emit 'cache:ready' 63 | null 64 | 65 | getTexture: (url)-> new Promise (resolve,reject)=> 66 | t = @db.transaction ['nuu'], "readonly" 67 | p = url.replace /^\//,'' 68 | q = t.objectStore('nuu').get p 69 | q.onerror = reject 70 | q.onsuccess = (event)=> 71 | r = new Image 72 | r.onload = (event) -> 73 | t = new THREE.Texture r 74 | t.needsUpdate = yes 75 | resolve t 76 | if blob = event.target.result then r.src = URL.createObjectURL blob 77 | else @fetch p, (blob)-> r.src = URL.createObjectURL blob 78 | return 79 | 80 | get: (path,callback) -> 81 | path = path.replace(/^\//,'') 82 | tx = @db.transaction([ 'nuu' ], "readonly") 83 | q = tx.objectStore('nuu').get(path) 84 | q.onerror = (event) -> console.log event 85 | q.onsuccess = (event) => 86 | if ( imgFile = event.target.result ) 87 | imgURL = URL.createObjectURL imgFile 88 | callback imgURL 89 | # URL.revokeObjectURL imgURL 90 | else @fetch path, (blob)-> 91 | imgURL = URL.createObjectURL blob 92 | callback imgURL 93 | # URL.revokeObjectURL imgURL 94 | null 95 | null 96 | null 97 | 98 | fetch: (path, callback) -> 99 | $b.add (release) => 100 | x = new XMLHttpRequest 101 | x.responseType = 'blob' 102 | x.open 'GET', path, true 103 | x.addEventListener 'error', (e) -> console.log 'data', 'fetch-error', path, e 104 | x.addEventListener 'load', => if x.status == 200 105 | tx = @db.transaction [ 'nuu' ], "readwrite" 106 | put = tx.objectStore('nuu').put x.response, path 107 | callback x.response 108 | release() 109 | null 110 | x.send() 111 | null 112 | null 113 | 114 | drop:-> 115 | indexedDB.deleteDatabase 'nuucache' 116 | window.location.reload() 117 | -------------------------------------------------------------------------------- /mod/nuu/artwork/icon_2018.svg: -------------------------------------------------------------------------------- 1 | 2 | 91 | -------------------------------------------------------------------------------- /mod/core/client/client.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | window.$static = (name,value) -> window[name] = value 24 | $static.list = window 25 | window.$public = (args...) -> window[a.name] = a for a in args 26 | window.$cue = (f) -> setTimeout 0,f 27 | 28 | ### 29 | Client-specific constants / $statics 30 | ### 31 | 32 | $static 'isClient', yes 33 | $static 'isServer', no 34 | $static 'debug', no 35 | 36 | $static 'NET', {} 37 | $static 'NUU', {} 38 | 39 | $static 'DUMMY', dummy:yes, id:0, d:0, x:0, y:0, v: [0,0], update: (->), updateSprite: (->), updateScanner:(->), updateShortrange:(->), state:S:'none' 40 | $static 'VEHICLE', DUMMY 41 | $static 'TARGET', null 42 | $static 'TTL', new Set 43 | 44 | $static 'WIDTH', 640 45 | $static 'HEIGHT', 480 46 | $static 'WDB2', 320 47 | $static 'HGB2', 240 48 | $static 'WDT2', 1280 49 | $static 'HGT2', 960 50 | 51 | NUU.defaults = 52 | mouseturnoff: off 53 | gfx: hud: off, scanner: off, speedScale: off 54 | 55 | NUU.saveSettings = -> 56 | localStorage.setItem 'config', JSON.stringify NUU.settings 57 | NUU.emit 'settings' 58 | NUU.settings 59 | 60 | NUU.loadSettings = -> 61 | try data = NUU.applyDefaults JSON.parse( localStorage.getItem "config" ), NUU.defaults 62 | catch error then data = NUU.defaults 63 | data = new Proxy data, set:(o,k,v)-> NUU.saveSettings o[k] = v 64 | NUU.settings = data 65 | 66 | NUU.applyDefaults = (o={},d={})-> 67 | for k,v of d 68 | if typeof v is 'object' then o[k] = NUU.applyDefaults o[k] || {}, v 69 | else if not o[k]? then o[k] = v 70 | return o 71 | 72 | do NUU.loadSettings 73 | 74 | ### 75 | Load the more strightforward deps 76 | ### 77 | 78 | console.log ':nuu', 'loading deps' 79 | 80 | for lib in deps.client.require 81 | if Array.isArray lib 82 | if lib.length is 3 83 | $static lib[0], require(lib[1])[lib[2]] 84 | else $static lib[0], require(lib[1]) 85 | else $static lib, require(lib) 86 | 87 | # Extend NUU/NET (GLUE OBJECTs:) 88 | NUU[k] = v for k,v of EventEmitter::; EventEmitter.call NUU 89 | NET[k] = v for k,v of EventEmitter::; EventEmitter.call NET 90 | 91 | console.log ':nuu', 'loading libs' 92 | 93 | $ -> 94 | NUU.emit 'runtime:ready' 95 | NUU.emit 'settings:apply' 96 | 97 | NUU.on 'start', -> 98 | Object.assign rules, rules[NUU.mode||'dm'] 99 | rules NUU 100 | NUU.emit 'settings' 101 | 102 | NUU.on 'gfx:ready', -> 103 | VT100.write """\ 104 |
\ 105 | \ 106 |
\ 107 |
108 | 109 | 110 | 111 |
""" 112 | vt.write NUU.intro = """ 113 | --- [ FakeNN ] BREAKING ------------------------------------------------------------------------\ 114 | Earth and Luna have been overrun by the drones our own creation, and now,\ 115 | her Majesty the Kernel is scheming to take Mars and the Jupiter-system!\ 116 | ------------------------------------------------------------------------------------------------ 117 | 118 | ➜ Press alt-R to register (we only store salted hashes) 119 | ➜ Press alt-L to show license screen 120 | ➜ Press alt-C for demo 121 | 122 | """ 123 | NUU.loginPrompt() 124 | Item.init await new Promise (resolve)-> $.ajax '/build/objects.json', success:resolve 125 | vt.hide = -> 126 | $('img.com').remove() 127 | Window::hide.call @ 128 | a = Item.byClass.com.sort -> Math.random() - .5 129 | $('body').append $ """""" 130 | $('body').append $ """""" 131 | return 132 | 133 | NUU.loginComplete = (opts)-> 134 | @player = new User opts 135 | Sound.radio.init() 136 | console.log '' 137 | await GFX.initGame() 138 | await GFX.start() 139 | NUU.emit 'start' 140 | Promise.resolve() 141 | -------------------------------------------------------------------------------- /mod/core/common/ping.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | . .,:cddxddoddxxkO0KKOo,'... 22 | .ll:xxxkKXXXKKKKKXXXXXXXXXNNXKK0Oxc'. 23 | 'OKK0kkOxO0O0K0occdOokxx:dO0KKKKK00Od;, 24 | .cOKKx:..o00x0X0l:;;;lKx,.. .o0KKOkldOOddl, 25 | ,KK0x, .c:xKKKXKdcd0;..'dKk:.;cxXXX0ocox:dkko. 26 | lK0KO' .l0XXXXNNX0Kkc',. ,OKX0KXNNXNNNNXO,.,l00d;. 27 | ;KXKX, 'OXXXOOKkkO,;dOll'.o;lKNXNWWNWNNNNNNk. ;OK0d 28 | .xKXXk.,OXXX0OccdlldKK0Kl'.:loO0OkK0oll,;kXXX0' .ldKo 29 | .ldOXk:.okk0xl,. .cOKXXK0dooc;'. .. .,cOKXXO, ;ol. 30 | :dxkO;.cKl.kk;lc:...cOK0Odcl::cc;::::lllodoclo0X0x'.;kOc 31 | l0K0o..OX0.'dd:oo;;;;:x0kkxodkkkkkxx;;,xl::,,,lKXXx;x0XO; 32 | oXKKd ,0XK; .;;;ooco,...,'.. .,,'. .,'.;:,::.;;:OXX0c.,dd. 33 | oXXKd.,OXKd. .,lx0xoo:;c,.... .'',codk00O00OokdOXKXKcloo. 34 | lKXx. .d00x,. ..cxxk0KXNNNNK0l;;.,0XNNNWWWNK0kxk0kdXOO00: 35 | o0Ko lKXKOoooxxx0XXXXKXXNNXXKx',:lO0kd:;,'. ':dXXKXNo 36 | :0Od. 'KXXKk:dx:'........;cd0KKOd;,dd. .'',,;::. ,0KXKKX; 37 | lXKk..oXX0:... ,;'';::;. .:okoxOx. .,,,c::cc.c0X0lxk. 38 | 'XXX0Olkx,.;;...... ..;. xKXXc .,c:;loxkxx0KKc .'d0K0kOkkdoc'. 39 | .OXXN0. . ,KNNNX0xc'',;:,.'.. ;XWN0kxdc;,,;coKNNXO:. ;NWWWWWWWWWWWNO 40 | .kXXXk. .oKXXKXNWNK0kkOKKKOl kNWO;dO0XNNNNNX0xo. 'NWNNNNNNNNNNKX 41 | :x0Kx. .,cc;:xXNNNWWWNXO' lXWNKl..:x0KKK0doc .ONXXNNNNXKXXk, 42 | ;lxkod: .lOKXXXNXXd .,.:KXXXK0O; .':xxdOo. . 'KNXdKNNNNNNNNd 43 | 'l0XXXK, ,. .. ';. .lO0Oo:. .,. ....'..,ll,. ..'. .. .kXKd '..,xO0Oc 44 | ,ONNNNNNx. ';. ..'. ,;'. 'o:.... .,kKNXNXXkc. ;XNN0..0o ,0XX' 45 | ,kNWNNXXXXOc..ol;'..::,. .lkOKXXKKkd;'dKKXNX0Okdloxc. .ONNNX, kNd cKNO 46 | .kWWWN0l'.:kXXK:'x;..:;,....'xNXKKK0OOoo,;..:,,,. ...cO: cXNWNX' 'XNl 'oX 47 | .dNWWNx; oNWNX:.'. .:,..;:kXd;o:. ',;c;'dOKKdodo:lxO; .OXNWWN, oWX: . 48 | NWWNx: .. dWWWN0'.oc.::::,,l0dd:...:okKXXK0xO0NNXOkKxc' ',OXNNWWk .OW0. 49 | Kx0o 'OXk..xNNXo,xl'l,'lx:,c,OXo;0k0kOO0kcld0x:;:lOO;... .lKx0XXKO0Nc :NNx. . 50 | . .l: ;kKKk0XOc. 'OXo,d:..'.,odxoocxl.OKk. ..ccko,,.o' lKX0KKKK: ,k, xN0, 51 | oc,.'o:. ,0Ko, .xXloXl.dOc. ...:ld;;oxlkckOkkddNKK00ddkKNWK'.:0d ,lKXc '0NO: 52 | XXKK00Kx. ..', .;0X' cXc.xNN0x:. .'',cd0XXNXXXKkd:..oXNWNWWd ;;.cKNWWXl.lXKd. 53 | X0xx0XOd. ,kO0XWWd c0d.cKNNNNKkc;.. .c0x,;,. .oXWWWXl lKo..dXNXkx0Kx. 54 | oNWXKX0:. ckKNWX; .kXl .c0XKKXXXXXX00Xx .kWWXc cXXl .xKXOx0K: 55 | ,l0KOdxOo. . ,0NNO. ,0Kc ,lco0XNNWWWx.ld:... . .'. ...cKk' 'KNNl . .kK0 56 | kxl. .cOXXO..;, .0WNl .00k;'l:oXNKXNNNc,xX00Kl ,:l; '0OOKK: oNNXl ,ldkK 57 | KWW0. .kNNk cO; ;NWN, xWWW00X::NxkXNo.0XNOOXX' ,;dO: OWWWWNd. dKXN0. lk0lo 58 | 59 | David L. Mills * 6/3/1938 60 | designer of NTP, inernet pioneer, hero of man 61 | ### 62 | 63 | $static class SyncPing 64 | constructor:-> 65 | @timer = null 66 | @ringId = -1 67 | @ringBf = [] 68 | @bestPing = [Infinity,Infinity,Infinity] 69 | @bestDelta = [0,0,0] 70 | @avrgDelta = @avrgPing = @pings = 0 71 | 72 | SyncPing::add = (id,remote)-> 73 | local = Date.now() 74 | prediction = local - @avrgDelta 75 | error = remote - prediction 76 | ping = .5 * ( local - @ringBf[id] ) # this assumption is ofc wrong :D 77 | delta = local - ping - remote 78 | return false if @bestPing[0] < ping 79 | @bestPing[2] = @bestPing[1]; @bestPing[1] = @bestPing[0]; @bestPing[0] = ping 80 | @bestDelta[2] = @bestDelta[1]; @bestDelta[1] = @bestDelta[0]; @bestDelta[0] = delta 81 | @avrgPing = @avrgDelta = 0 82 | count = 1 + min 3, @pings 83 | for i in [0...count] 84 | @avrgPing += @bestPing[0] 85 | @avrgDelta += @bestDelta[0] 86 | @avrgPing /= count 87 | @avrgDelta /= count 88 | return true unless 20 < ++@pings and 1.33 > @avrgDelta 89 | # assume that system clocks are sync; TODO: track clock-skew again 90 | console.log 'ASSUMING HOSTS ARE SYNC', @avrgDelta, 'ms delta' 91 | NUU.time = Date.now 92 | SyncPing::add = -> 93 | true 94 | 95 | SyncPing::engage = -> => @timer = $interval 1000, => 96 | @ringBf[id = ++@ringId % 32] = Date.now() 97 | msg = Buffer.from [NET.pingCode,id] 98 | NET.send msg.toString 'binary' 99 | 100 | SyncPing::disengage = -> => clearInterval @timer 101 | 102 | return if isServer 103 | 104 | $static 'Ping', new SyncPing 105 | NUU.time = -> Date.now() - Ping.avrgDelta 106 | NUU.on 'connect', do Ping.engage 107 | NUU.on 'disconnect', do Ping.disengage 108 | -------------------------------------------------------------------------------- /mod/nuu/client/render.coffee: -------------------------------------------------------------------------------- 1 | 2 | $public class SpriteSurface 3 | @renderer: null 4 | @camera3d: null 5 | @scene3d: null 6 | @scene2d: null 7 | @camera2d: null 8 | @spriteTL: null 9 | @spriteTR: null 10 | @spriteBL: null 11 | @spriteBR: null 12 | @spriteC: null 13 | @mapC: null 14 | @group: null 15 | 16 | constructor:-> 17 | @width = window.innerWidth; @height = window.innerHeight; @wdb2 = @width/2; @hgb2 = @height/2 18 | @camera3d = new THREE.PerspectiveCamera 60, @width / @height, 1, 2100 19 | @camera3d.position.z = 1500 20 | @camera2d = new THREE.OrthographicCamera -@wdb2, @wdb2, @hgb2, -@hgb2, 1, 10 21 | @camera2d.position.z = 10 22 | @scene3d = new THREE.Scene 23 | @scene3d.fog = new THREE.Fog 0x000000, 1500, 2100 24 | @scene2d = new THREE.Scene 25 | # create sprites 26 | amount = 200 27 | radius = 500 28 | @loader = new THREE.TextureLoader 29 | @loader.load 'textures/sprite0.png', createHUDSprites 30 | @mapB = @loader.load('textures/sprite1.png') 31 | @mapC = @loader.load('textures/sprite2.png') 32 | @group = new THREE.Group 33 | materialC = new THREE.SpriteMaterial map: @mapC, color: 0xffffff, fog: true 34 | materialB = new THREE.SpriteMaterial map: @mapB, color: 0xffffff, fog: true 35 | a = 0 36 | while a < amount 37 | x = Math.random() - 0.5 38 | y = Math.random() - 0.5 39 | z = Math.random() - 0.5 40 | material = undefined 41 | if z < 0 42 | material = materialB.clone() 43 | else 44 | material = materialC.clone() 45 | material.color.setHSL 0.5 * Math.random(), 0.75, 0.5 46 | material.map.offset.set -0.5, -0.5 47 | material.map.repeat.set 2, 2 48 | sprite = new (THREE.Sprite)(material) 49 | sprite.position.set x, y, z 50 | sprite.position.normalize() 51 | sprite.position.multiplyScalar radius 52 | @group.add sprite 53 | a++ 54 | @scene3d.add @group 55 | @renderer = new THREE.WebGLRenderer 56 | @renderer.setPixelRatio window.devicePixelRatio 57 | @renderer.setSize window.innerWidth, window.innerHeight 58 | @renderer.autoClear = false 59 | # To allow render overlay on top of sprited sphere 60 | document.body.appendChild @renderer.domElement 61 | window.addEventListener 'resize', onWindowResize, false 62 | animate() 63 | return 64 | 65 | createHUDSprites: (texture) -> 66 | material = new (THREE.SpriteMaterial)(map: texture) 67 | @width = material.map.image.@width 68 | @height = material.map.image.@height 69 | @spriteTL = new (THREE.Sprite)(material) 70 | @spriteTL.center.set 0.0, 1.0 71 | @spriteTL.scale.set @width, @height, 1 72 | @scene2d.add @spriteTL 73 | @spriteTR = new (THREE.Sprite)(material) 74 | @spriteTR.center.set 1.0, 1.0 75 | @spriteTR.scale.set @width, @height, 1 76 | @scene2d.add @spriteTR 77 | @spriteBL = new (THREE.Sprite)(material) 78 | @spriteBL.center.set 0.0, 0.0 79 | @spriteBL.scale.set @width, @height, 1 80 | @scene2d.add @spriteBL 81 | @spriteBR = new (THREE.Sprite)(material) 82 | @spriteBR.center.set 1.0, 0.0 83 | @spriteBR.scale.set @width, @height, 1 84 | @scene2d.add @spriteBR 85 | @spriteC = new (THREE.Sprite)(material) 86 | @spriteC.center.set 0.5, 0.5 87 | @spriteC.scale.set @width, @height, 1 88 | @scene2d.add @spriteC 89 | updateHUDSprites() 90 | return 91 | 92 | updateHUDSprites: -> 93 | @width = window.innerWidth / 2 94 | @height = window.innerHeight / 2 95 | @spriteTL.position.set -@width, @height, 1 96 | @spriteTR.position.set @width, @height, 1 97 | @spriteBL.position.set -@width, -@height, 1 98 | @spriteBR.position.set @width, -@height, 1 99 | @spriteC.position.set 0, 0, 1 100 | return 101 | 102 | onWindowResize: -> 103 | @width = window.innerWidth 104 | @height = window.innerHeight 105 | @camera3d.aspect = @width / @height 106 | @camera3d.updateProjectionMatrix() 107 | @camera2d.left = -@wdb2 108 | @camera2d.right = @wdb2 109 | @camera2d.top = @hgb2 110 | @camera2d.bottom = -@hgb2 111 | @camera2d.updateProjectionMatrix() 112 | updateHUDSprites() 113 | @renderer.setSize window.innerWidth, window.innerHeight 114 | return 115 | 116 | animate:-> 117 | requestAnimationFrame animate 118 | render() 119 | return 120 | 121 | render = -> 122 | time = Date.now() / 1000 123 | i = 0 124 | l = @group.children.length 125 | while i < l 126 | sprite = @group.children[i] 127 | material = sprite.material 128 | scale = Math.sin(time + sprite.position.x * 0.01) * 0.3 + 1.0 129 | imageWidth = 1 130 | imageHeight = 1 131 | if material.map and material.map.image and material.map.image.@width 132 | imageWidth = material.map.image.@width 133 | imageHeight = material.map.image.@height 134 | sprite.material.rotation += 0.1 * i / l 135 | sprite.scale.set scale * imageWidth, scale * imageHeight, 1.0 136 | if material.map != @mapC 137 | material.opacity = Math.sin(time + sprite.position.x * 0.01) * 0.4 + 0.6 138 | i++ 139 | @group.rotation.x = time * 0.5 140 | @group.rotation.y = time * 0.75 141 | @group.rotation.z = time * 1.0 142 | @renderer.clear() 143 | @renderer.render @scene3d, @camera3d 144 | @renderer.clearDepth() 145 | @renderer.render @scene2d, @camera2d 146 | return 147 | -------------------------------------------------------------------------------- /pd/database.js: -------------------------------------------------------------------------------- 1 | const { spawnSync } = require("child_process"); 2 | const { yellow } = require("colors"); 3 | const { 4 | readFileSync, 5 | promises: { 6 | stat, 7 | readdir, 8 | mkdir, 9 | rmdir, 10 | readFile, 11 | unlink, 12 | writeFile, 13 | symlink, 14 | readlink, 15 | }, 16 | } = require("fs"); 17 | 18 | const { join } = require("path"); 19 | 20 | const Index = require("./index_map"); 21 | const Sync = require("./sync"); 22 | const Cursor = require("./cursor"); 23 | 24 | const exists = async (p) => 25 | stat(p) 26 | .then((stat) => stat.isDirectory()) 27 | .catch((e) => false); 28 | 29 | class Database { 30 | constructor(opts = {}) { 31 | Object.assign(this, opts); 32 | this.ready = this.init(); 33 | this.cache = new Map(); 34 | this.readPromise = {}; 35 | this.indexes = []; 36 | new Sync(this); 37 | } 38 | 39 | async init() { 40 | if (await this.create()) return this; 41 | if (await this.open()) return this; 42 | throw new Error(`pd could not open: ${this.path}`); 43 | } 44 | 45 | async create() { 46 | let doesExist = await exists(this.path); 47 | if (!this.forceCreate && doesExist) return false; 48 | if (doesExist) await this.purge(); 49 | await mkdir(this.path, { recursive: true }); 50 | if (!(await this.open())) return false; 51 | if (this.onCreate) await this.onCreate(); 52 | } 53 | 54 | async open() { 55 | try { 56 | await readdir(this.path); 57 | return true; 58 | } catch (e) { 59 | console.debug(e); 60 | } 61 | return false; 62 | } 63 | 64 | async set(key, value) { 65 | this.cache.set(key, value); 66 | this.indexes.forEach((i) => i.consume([key, value])); 67 | return this.nextSync.add(key, value); 68 | } 69 | 70 | async all() { 71 | let all = this.forEach(); 72 | let done, value, result = []; 73 | while (({ done, value } = await all.next())) { 74 | if (done) break; 75 | result.push(value[1]); 76 | } 77 | return result; 78 | } 79 | 80 | async each(fn) { 81 | let all = this.forEach(); 82 | let done, 83 | value, 84 | result = []; 85 | Object.assign(this, { result }); 86 | while (({ done, value } = await all.next())) { 87 | if (done) break; 88 | result.push(fn([value[0], value[1]])); 89 | } 90 | return Promise.all(result); 91 | } 92 | 93 | async *forEach() { 94 | const files = await readdir(this.path).then((files) => 95 | files.map((f) => f.replace(/.json$/, "")) 96 | ); 97 | const cached = Array.from(this.cache.entries()); 98 | const uncached = files.filter((f) => !this.cache.has(f)); 99 | for (const entry of cached) yield entry; 100 | for (const key of uncached) yield [key, await this.get(key)]; 101 | } 102 | 103 | async get(key) { 104 | const cachedValue = this.cache.get(key); 105 | if (cachedValue !== undefined) return cachedValue; 106 | const beingRead = this.readPromise[key]; 107 | if (beingRead) return beingRead; 108 | return (this.readPromise[key] = new Promise(async (resolve) => { 109 | try { 110 | const file = join(this.path, key + ".json"); 111 | const data = await readFile(file, "utf-8"); 112 | const json = JSON.parse(data); 113 | this.cache.set(key, json); 114 | this.indexes.forEach((i) => i.consume([key, json])); 115 | delete this.readPromise[key]; 116 | resolve(json); 117 | } catch (e) { 118 | //console.log(e.code === 'ENOENT' ? `Cannot read: ${file}`: console.log(e)) 119 | resolve(undefined); 120 | } 121 | })); 122 | } 123 | 124 | async getSync(key) { 125 | const cachedValue = this.cache.get(key); 126 | if (cachedValue !== undefined) return cachedValue; 127 | return (this.readPromise[key] = new Promise(async (resolve) => { 128 | try { 129 | const file = join(this.path, key + ".json"); 130 | const data = readFileSync(file, "utf-8"); 131 | const json = JSON.parse(data); 132 | this.cache.set(key, json); 133 | this.indexes.forEach((i) => i.consume([key, json])); 134 | resolve(json); 135 | } catch (e) { 136 | //console.log(e.code === 'ENOENT' ? `Cannot read: ${file}`: console.log(e)) 137 | resolve(undefined); 138 | } 139 | })); 140 | } 141 | 142 | async delete(key) { 143 | const value = await this.get(key); 144 | if (value === undefined) return; 145 | const file = join(this.path, key + ".json"); 146 | if (this.cache.has(key)) this.cache.delete(key); 147 | this.indexes.forEach((i) => i.delete(key, value)); 148 | await unlink(file); 149 | } 150 | 151 | deleteOne(condition) {} 152 | 153 | async purge() { 154 | this.cache = new Map(); 155 | await rmdir(this.path, { recursive: true }); 156 | this.indexes.forEach((i) => i.purge()); 157 | console.debug("pd purged"); 158 | } 159 | find(query, opts = {}) { 160 | return new Cursor({$db:this, query, opts}).exec(); 161 | } 162 | findOne(query, opts = {}) { 163 | return new Cursor({$db:this, query, opts:{ ...opts, limit: 1 }}).exec().then(s=>s.toArray()[0]); 164 | } 165 | 166 | index(keyPath, fn) { 167 | new Index(this, keyPath, fn); 168 | } 169 | } 170 | 171 | Database.open = (opts) => new Database(opts); 172 | Database.create = (opts) => new Database({ ...opts, forceCreate: true }); 173 | 174 | module.exports = Database; 175 | -------------------------------------------------------------------------------- /mod/core/common/station.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ███████ ████████ █████ ████████ ██ ██████ ███ ██ 22 | ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ 23 | ███████ ██ ███████ ██ ██ ██ ██ ██ ██ ██ 24 | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 25 | ███████ ██ ██ ██ ██ ██ ██████ ██ ████ ### 26 | 27 | $obj.register class Station extends Stellar 28 | @interfaces: [$obj,Stellar,Station,Shootable] 29 | @type:'station' 30 | level:1 31 | population:1 32 | shield:1000 33 | armour:1000 34 | weapon:'LaserTurretMK' 35 | interval:1000 36 | massMax:100 37 | orbits:[] 38 | constructor:(opts)-> 39 | super Economy.defaults opts, 40 | Station.template[opts.template = opts.template || 'Outpost'] 41 | if @template is 'Mine' and not @mines 42 | @mines = 'Fe' 43 | if @mines and @zone 44 | @mines = @zone.deterministic.element @zone.provides() 45 | console.log @zone.root.name, 'mines', @mines if debug 46 | @produces[@mines] = @allocates[@mines] = min 100, @zone.availableFor @mines 47 | @shieldMax = @shield 48 | @armourMax = @armour 49 | @access = @access || [] 50 | @hostile = [] 51 | @weapon = new Weapon @, @weapon 52 | @weapon.slot = id:0, equip:@weapon 53 | @slots = # Mock items for now 54 | weapon: [ @weapon.slot ] 55 | structure: [ 56 | {id:0, size:'large', equip:null} 57 | {id:0, size:'large', equip:null} 58 | ] 59 | @name += "-#{@id}" 60 | # @name += " (#{@constructor.name})" if isClient 61 | return if isClient 62 | do @weapon.blur = => 63 | return if @destructing 64 | console.log @name, 'lost target' if debug 65 | @weapon.release() 66 | Weapon.Defensive.add @weapon 67 | destructor:-> 68 | Weapon.Defensive.remove @weapon 69 | @weapon.destructor() 70 | @weapon = null 71 | super() 72 | toJSON: -> return { 73 | id: @id 74 | key: @key 75 | sprite: @sprite 76 | state: @state 77 | name: @name 78 | mines: @mines 79 | provides: @provides 80 | allocates: @allocates 81 | produces: @produces 82 | consumes: @consumes 83 | template: @template 84 | owner: @owner 85 | access: @access } 86 | 87 | Station.blueprint = 88 | name: 'Station' 89 | sprite: 'sprite@station-shipyard' 90 | weapon: 'LaserTurretMK' 91 | population: 10 92 | massMax: 100 93 | shield: 1000 94 | armour: 1000 95 | produces: {} 96 | provides: {} 97 | consumes: {} 98 | allocates: e:100 99 | mines: false 100 | upgrades: false 101 | requires: false 102 | 103 | Station.template = 104 | Outpost: 105 | sprite: 'station-sphere' 106 | population: 5 107 | shield: 10000 108 | armour: 10000 109 | provides: e:100 110 | 111 | Stronghold: 112 | upgrades: 'Outpost' 113 | sprite: 'station-sphere' 114 | population: 5 115 | shield: 50000 116 | armour: 10000 117 | provides: e:1000 118 | 119 | Fortress: 120 | upgrades: 'Stronghold' 121 | sprite: 'base' 122 | population: 10 123 | shield: 100000 124 | armour: 100000 125 | weapon: 'GraveBeam' 126 | allocates: e:1000 127 | 128 | Powerplant: 129 | sprite: 'station-powerplant' 130 | population: 0 131 | provides: e:5000 132 | scannerSymbol:'䷡' 133 | 134 | Farm: 135 | sprite: 'station-agriculture' 136 | population: 10 137 | allocates: e:100, Farmland:100, H20:10 138 | produces: Food:100 139 | scannerSymbol:'🍽' 140 | 141 | LargeFarm: 142 | upgrades: 'Farm' 143 | sprite: 'station-commerce3' 144 | population: 100 145 | allocates: e:10, Farmland:1000 146 | consumes: H20:20 147 | produces: Food:1000 148 | scannerSymbol:'🍽' 149 | 150 | Habitat: 151 | upgrades: 'Farm' 152 | sprite: 'station-commerce' 153 | population: 100000 154 | allocates: e:10, Executives:10, H20:10000, Food:100000 155 | provides: Executives:100, Workers:50000 156 | scannerSymbol:'🏘' 157 | 158 | Mine: 159 | sprite: 'station-commerce' 160 | population: 2000 161 | allocates: e:200, Food:100 162 | scannerSymbol:'⚒' 163 | 164 | Trade: 165 | sprite: 'station-commerce2' 166 | population: 10000 167 | massMax: 1000000 168 | allocates: e:100, Executives:30, Food:1000 169 | scannerSymbol:'💰' 170 | 171 | Factory: 172 | sprite: 'station-shipyard' 173 | population: 10 174 | allocates: e:100, Executives:10, Food:10 175 | consumes: Fe:10 176 | produces: Kestrel: 1 177 | scannerSymbol:'🏭' 178 | -------------------------------------------------------------------------------- /mod/core/client/vt100.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | $public class VT100 extends Window 24 | line: [] 25 | hist: [] 26 | frame: null 27 | cursor: x: 0, y: 0 28 | inputBuffer: '' 29 | promptActive: no 30 | 31 | constructor: (opts={}) -> 32 | super name:'VT100' 33 | @$.addClass 'vt full' 34 | @body.append @input$ = $ """
""" 35 | console.user = @write 36 | @write """\ 37 |
nuu console / v#{$version}\ 38 | (c) 2007-2022 Sebastian Glaser <anx@ulzq.de> / (c) 2007-2022 flyc0r\ 39 | GNU General Public License v3 / see license screen (alt-L)""" 40 | return 41 | 42 | draw: => 43 | c = @cursor.x 44 | p = if @promptQuery then @promptQuery + ": " else '' 45 | b = @inputBuffer 46 | b = b.replace /./g, "*" if @stars 47 | b = b.substr(0,c) + '' + b.substr c 48 | @input$.html p + b 49 | @$[0].scroll top: @body.height() 50 | 51 | write: (lines) => 52 | @input$.before $ """
#{lines}
""" 53 | do @draw 54 | 55 | status: (p,t)-> 56 | do @show 57 | if @lastSP and ( @lastSP isnt p or @lastST isnt t ) 58 | log @lastSP+':', @lastST 59 | @inputBuffer = t+'\n' 60 | @cursor.x = t.length + 1 61 | @draw @promptQuery = p 62 | @lastSP = p; @lastST = t 63 | 64 | prompt: (p,callback,override) => 65 | log @lastSP+':', @lastST if @lastSP and not @stars; @lastST = @lastSP = null 66 | return false if @promptActive unless override or p.override 67 | if typeof p is 'object' 68 | @stars = p.stars || false 69 | @overrideKeys = p.key 70 | callback = p.then 71 | p = p.p 72 | @focus() 73 | @promptActive = yes 74 | @promptQuery = p 75 | @inputBuffer = '' 76 | @onReturn = (cmd)=> 77 | log @lastSP+':', @lastST if @lastSP and not @stars; @lastST = @lastSP = null 78 | return true if true is callback.call @, cmd 79 | @promptQuery = 'nuu#' 80 | @hide() 81 | false 82 | @cursor.x = 0 83 | @draw() 84 | true 85 | 86 | pasteHandler: (e)-> 87 | c = @cursor.x 88 | d = e.clipboardData 89 | .getData('text') 90 | .replace(/\n/g,'; ') 91 | @inputBuffer = @inputBuffer.substr(0,c) + d + @inputBuffer.substr(c) 92 | @cursor.x += d.length 93 | do @draw 94 | 95 | keyHandler: (e,code)-> 96 | return if true is @overrideKeys e if @overrideKeys 97 | c = @cursor.x 98 | if code is 'Enter' 99 | if (fnc = @onReturn)? 100 | i = @inputBuffer 101 | delete @onReturn 102 | @write @promptQuery + ': ' + if @stars then @inputBuffer.replace(/./g,'*') else @inputBuffer 103 | @hist.cursor = @hist.push(@inputBuffer) - 1 104 | @cursor.x = 0 105 | @promptActive = no 106 | @inputBuffer = '' 107 | res = fnc i unless e.shiftKey 108 | @hide() unless res is true 109 | else if code is 'Escape' or code is 'sEscape' or code is 'Backquote' 110 | res = fnc null if not e.shiftKey and ( fnc = @onReturn )? 111 | @hide() unless res is true 112 | else if code is 'ArrowLeft' 113 | @cursor.x = max(0,--@cursor.x) 114 | else if code is 'ArrowRight' 115 | @cursor.x = min(@inputBuffer.length,++@cursor.x) 116 | else if code is 'ArrowUp' 117 | @hist.cursor = max(0,--@hist.cursor) 118 | @inputBuffer = @hist[@hist.cursor] 119 | @cursor.x = @inputBuffer.length 120 | else if code is 'ArrowDown' 121 | @hist.cursor = min(@hist.length-1,++@hist.cursor) 122 | @inputBuffer = @hist[@hist.cursor] 123 | @cursor.x = @inputBuffer.length 124 | else if code is 'Delete' 125 | @inputBuffer = @inputBuffer.substr(0,c) + @inputBuffer.substr(c+1) 126 | else if code is 'aDelete' 127 | @inputBuffer = @inputBuffer.substr(0,c) 128 | @cursor.x = @inputBuffer.length 129 | else if code is 'Backspace' 130 | @inputBuffer = @inputBuffer.substr(0,c-1) + @inputBuffer.substr(c) 131 | @cursor.x = max(0,--@cursor.x) 132 | else if code is 'aBackspace' 133 | @inputBuffer = @inputBuffer.substr(c) 134 | @cursor.x = 0 135 | else 136 | k = e.char || e.key || String.fromCharCode e.charCode 137 | if k.length is 1 138 | @inputBuffer = @inputBuffer.substr(0,c) + k + @inputBuffer.substr(c) 139 | @cursor.x++ 140 | @draw() 141 | false 142 | 143 | VT100.toggle = -> 144 | vt.show() 145 | vt.rootPrompt() 146 | 147 | VT100::rootPrompt = (force=no)-> 148 | p = (text) -> 149 | return false unless text 150 | try 151 | v = eval(text) 152 | console.user v.toString() if v? 153 | catch e 154 | console.user ( if e and e.message then e.message else e ) 155 | true 156 | setTimeout ( new Function 'VT100.toggle()' ), 0 157 | true 158 | vt.prompt 'nuu #', p, force 159 | 160 | Kbd.macro 'console', 'Backquote', 'Show / hide console', VT100.toggle 161 | -------------------------------------------------------------------------------- /mod/nuu/common/asteroid.coffee: -------------------------------------------------------------------------------- 1 | 2 | # █████ ███████ ████████ ███████ ██████ ██████ ██ ██████ 3 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 4 | # ███████ ███████ ██ █████ ██████ ██ ██ ██ ██ ██ 5 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 6 | # ██ ██ ███████ ██ ███████ ██ ██ ██████ ██ ██████ 7 | 8 | # belt = Array.random [5.0325e8,5.984e+9] 9 | 10 | $obj.register class Asteroid extends $obj 11 | @interfaces: [$obj,Shootable,Debris,Asteroid] 12 | constructor: (opts)-> 13 | opts.sprite = 'asteroid-D' + ( opts.size - 10 ).toString().padStart 2,'0' 14 | super opts 15 | @armour = @armourMax = 10 * @size 16 | toJSON:-> undefined 17 | 18 | Asteroid::virtual = yes if isServer 19 | 20 | $obj.register class Asteroid.Belt extends $obj 21 | bigMass:yes 22 | @interfaces: [$obj,Stellar] 23 | constructor: (opts={})-> 24 | opts = Object.assign { 25 | seed: 'asdasdas213' 26 | belt: 5.0325e8 # 5.984e+9 27 | width: 1e8 28 | count: 1000 29 | }, opts 30 | opts.parent = $obj.byId[opts.parent] if isClient 31 | opts.state = opts.state || State.orbit.relto opts.parent, opts.belt, 1 32 | super opts 33 | unless @base 34 | @ids = new IdPool name:@name, max:@count unless @ids? 35 | @base = @ids.s 36 | @noise = new Deterministic @seed 37 | @list = new Array @count 38 | for i in [0..@count] 39 | oo = @belt - @width/2 + @width*@noise.doubell() 40 | @list[i] = new Asteroid 41 | resource: ( Element.deterministic @noise for j in [0...5]) 42 | state: State.orbit.relto @parent, oo, 1, TAU * @noise.double() 43 | size: max 10, floor @noise.double() * 73 44 | belt: @ 45 | id: @base + i 46 | name: @name + '-' + ( @base + i ) 47 | $obj.select @list if isClient 48 | loadAssets:-> 49 | toJSON:-> id:@id,key:@key,state:@state,seed:@seed,base:@base,count:@count,belt:@belt,width:@width,name:@name,parent:@parent.id 50 | 51 | $obj::closestAsteroid = -> 52 | return no unless Asteroid.list.length > 0 53 | closest = null; dist = Infinity 54 | for p in Asteroid.list 55 | continue if p.destructing 56 | if dist > d = abs $dist @,p 57 | closest = p 58 | dist = d 59 | return [closest,dist] 60 | 61 | return if isClient 62 | 63 | Asteroid.autospawn = (opts={})-> 64 | NUU.on 'start', -> 65 | center = $obj.byId[0] 66 | roids = [ 67 | { name:"Asteroid Belt", parent:center, belt:4.0325e8, width:3e8, count:2000 } 68 | { name:"Kuyper Belt", parent:center, belt:5.984e9, width:2.992e9, count:5000 } 69 | { name:"D Ring", parent:$obj.byName.Saturn, belt:78315, width:7610, count:500 } 70 | { name:"C Ring", parent:$obj.byName.Saturn, belt:100671, width:17342, count:500 } 71 | { name:"B Ring", parent:$obj.byName.Saturn, belt:130370, width:25580, count:500 } 72 | { name:"Cassini Division", parent:$obj.byName.Saturn, belt:124465, width:4590, count:500 } 73 | { name:"A ring", parent:$obj.byName.Saturn, belt:144077, width:14605, count:500 } 74 | { name:"Roche Division", parent:$obj.byName.Saturn, belt:140682, width:2605, count:500 } 75 | { name:"F Ring", parent:$obj.byName.Saturn, belt:139930, width:500, count:500 } 76 | { name:"Janus/Epimetheus Ring", parent:$obj.byName.Saturn, belt:156500, width:5000, count:1000 } 77 | { name:"G Ring", parent:$obj.byName.Saturn, belt:179500, width:9000, count:1000 } 78 | { name:"Methone Ring Arc", parent:$obj.byName.Saturn, belt:194230, width:500, count:1000, arc:PI/2 } 79 | { name:"Anthe Ring Arc", parent:$obj.byName.Saturn, belt:197665, width:500, count:1000, arc:PI/2 } 80 | { name:"Pallene Ring", parent:$obj.byName.Saturn, belt:214750, width:2500, count:1000 } 81 | { name:"E Ring", parent:$obj.byName.Saturn, belt:630000, width:300000, count:1000 } 82 | { name:"Phoebe Ring", parent:$obj.byName.Saturn, belt:4500000, width:9000000, count:1000 }] 83 | new Asteroid.Belt o for o in roids 84 | return 85 | $worker.push => 86 | # roids = @list.length 87 | # if roids < opts.max 88 | # dt = opts.max - roids 89 | # new Asteroid for i in [0...dt] 90 | 1000 91 | return 92 | 93 | $obj.register class Asteroid.Fragment extends $obj 94 | @interfaces: [$obj,Shootable,Debris,Asteroid] 95 | ttlFinal: true 96 | localObject: true 97 | constructor: (opts)-> 98 | console.log 'fragment' 99 | opts.sprite = 'asteroid-D' + ( opts.size - 10 ).toString().padStart 2, '0' 100 | opts.ttl = NUU.time() + 60000 101 | super opts 102 | @armour = @armourMax = 10 * @size 103 | toJSON:-> id:@id, key:@key, hostile:@hostile, resource:@resource, state:@state, size:@size, ttl:@ttl 104 | 105 | Asteroid::hit = (perp,weapon)-> 106 | return if @destructing 107 | return unless dmg = weapon.stats.physical 108 | @armour = max 0, @armour - dmg 109 | NET.mods.write @, ( if @armour is 0 then 'destroyed' else 'hit' ), 0, @armour 110 | return unless @armour is 0 111 | if @resource.length > 1 then for r in @resource 112 | @update() 113 | console.log @v 114 | fragment = new Asteroid 115 | toJSON:-> id:@id, key:@key, hostile:@hostile, resource:@resource, state:@state, size:@size, ttl:@ttl 116 | virtual: false 117 | hostile: [] 118 | resource: [r] 119 | size: size = max 10, floor random() * @size / 2 120 | state: S:$moving, x:@x, y:@y, v: [ @v[0] - .02 + random() * .04, @v[1] - .02 + random() * .04 ] 121 | Weapon.hostility perp, fragment 122 | else 123 | NUU.emit 'asteroid:destroyed', perp, @resource 124 | console.log "mined fragment" 125 | @destructor() 126 | null 127 | -------------------------------------------------------------------------------- /mod/core/common/worker.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | window.global = window if window? 24 | global.TIME = NUU.time() 25 | 26 | $static '$worker', new class TickWorker 27 | constructor:(interval=TICK)-> 28 | @list = [] 29 | @remove = @remove.bind @ 30 | @tick = @tick.bind @ 31 | @push = @push.bind @ 32 | @timer = setInterval @tick, interval 33 | tick:-> 34 | list = @list.filter @notStopped 35 | while f = list.shift() 36 | continue if f.notBefore > time = NUU.time() 37 | global.TIME = time 38 | global.ETIME = Math.floor(TIME/1000000)*1000000 39 | if typeof f isnt 'function' 40 | else if f.stop 41 | else if not isNaN r = f time 42 | f.notBefore = NUU.time() + r 43 | else f.stop = r isnt false 44 | @list = @list.filter @notStopped 45 | push:(f)-> f.stop = false; @list.push f; f 46 | remove:(f)-> f.stop = true 47 | notStopped:(f)-> f.stop isnt true 48 | 49 | class $worker.InlineThread 50 | constructor:(init=@init)-> 51 | source = [ '( async function(self){' ] 52 | source.push @workerInit.toInlineCode() if @workerInit 53 | source.push @worker .toInlineCode() if @worker 54 | source.push '} ).call(this,self)' 55 | if source.length isnt 2 56 | @thread = new Worker URL.createObjectURL new Blob [source.join '\n'],type:'text/javascript' 57 | @thread.onmessage = (m)=> 58 | @[k]? v for k,v of m.data 59 | return 60 | @init?() 61 | 62 | $worker.List = (worker)-> 63 | list = c = n = count = null 64 | listWorker = (time)-> 65 | { count, list } = listWorker 66 | c = n = 0 67 | worker.call at, time while ( at = list[c++] )? 68 | null 69 | listWorker.worker = worker 70 | listWorker.list = [] 71 | listWorker.count = 0 72 | listWorker.remove = (item)-> Array.remove @list, item 73 | listWorker.add = (item)-> 74 | @list[@count++] = item 75 | @count 76 | listWorker.remove = (item)-> 77 | return false unless @list.includes item 78 | Array.remove @list, item 79 | --@count 80 | listWorker.worker = worker 81 | $worker.push listWorker 82 | 83 | $worker.ReduceList = (worker)-> 84 | swap = []; list = c = n = count = null 85 | listWorker = (time)-> 86 | { count, list } = listWorker 87 | c = n = 0 88 | while c < count and ( at = list[c++] )? 89 | unless false is worker.call at, time 90 | swap[n++] = at 91 | listWorker.list = swap; swap = list 92 | listWorker.count = n 93 | null 94 | listWorker.worker = worker 95 | listWorker.list = [] 96 | listWorker.count = 0 97 | listWorker.add = (item)-> 98 | @list[@count++] = item 99 | @count 100 | listWorker.remove = (item)-> 101 | return false unless @list.includes item 102 | Array.remove @list, item 103 | --@count 104 | $worker.push listWorker 105 | 106 | $worker.PauseList = (opts,worker)-> 107 | unless worker 108 | opts = {} 109 | worker = opts 110 | listKey = opts.listKey || "pause" + $worker.PauseList.key++ 111 | if debug then setInterval ( -> 112 | console.log '$PauseWorker', listKey, listWorker.count 113 | ), 5000 114 | listWorker = (time)-> 115 | { count, list } = listWorker 116 | c = -1; n = 0 117 | while count > ++c 118 | item = list[c] 119 | delay = item[listKey] 120 | if -1 is delay 121 | delete item[listKey] 122 | continue 123 | if time < delay 124 | list[n++] = item 125 | continue 126 | res = worker.call item, time 127 | if -1 is res or -1 is item[listKey] 128 | delete item[listKey] 129 | continue 130 | item[listKey] = time + res 131 | list[n++] = item 132 | listWorker.count = n 133 | return true 134 | listWorker.worker = worker 135 | listWorker.list = [] 136 | listWorker.count = 0 137 | listWorker.add = (item)-> 138 | item[listKey] = 0 139 | @list[@count++] = item 140 | Object.assign item, opts 141 | listWorker.remove = (item)-> 142 | item[listKey] = -1 143 | $worker.push listWorker 144 | $worker.PauseList.key = 0 145 | 146 | $worker.DeadLine = (waitFor,deadline,worker)-> 147 | listKey = "deadline" + $worker.DeadLine.key 148 | listKeyLast = "deadlineLast" + $worker.DeadLine.key++ 149 | listWorker = (time)-> 150 | { count, list } = listWorker 151 | c = -1; n = 0 152 | while count > ++c 153 | item = list[c] 154 | delay = item[listKey] 155 | deadlay = item[listKeyLast] 156 | if delay is false 157 | delete item[listKey] 158 | delete item[listKeyLast] 159 | continue 160 | if time < delay and time < deadlay 161 | list[n++] = item 162 | continue 163 | worker.call item, time 164 | delete item[listKey] 165 | delete item[listKeyLast] 166 | listWorker.count = n 167 | return 168 | listWorker.worker = worker 169 | listWorker.list = [] 170 | listWorker.count = 0 171 | listWorker.add = (item)-> 172 | item[listKey] = waitFor + time = NUU.time() 173 | unless item[listKeyLast] 174 | item[listKeyLast] = deadline + time 175 | @list[@count++] = item 176 | listWorker.remove = (item)-> 177 | item[listKey] = false 178 | $worker.push listWorker 179 | $worker.DeadLine.key = 0 180 | -------------------------------------------------------------------------------- /mod/preql/common/unit.coffee: -------------------------------------------------------------------------------- 1 | 2 | $public class URPlayer 3 | @byId : {} 4 | @nextid : 0 5 | credits : 0 6 | constructor : -> 7 | URPlayer.byId[@id = URPlayer.nextid++] = @ 8 | 9 | $public class URUnit 10 | @nextid : 0 11 | @byId : {} 12 | @byPos : {} 13 | @byPlayer : {} 14 | 15 | @tpl : 16 | byType : u : {}, b : {} 17 | bld: type: 'u', name:'Builder', icon: 'left', cost: 80, hp:5, size:1.5, range:1,dps:1,tps:1,color:'#FF0',actions:['move','attack','build','repair'],build:['brk','trt'] 18 | wrk: type: 'u', name:'Worker', icon: 'left', cost: 150, hp:2, size:1.5, range:1,dps:1,tps:1,color:'#FF0',actions:['move','mine','repair'] 19 | inf: type: 'u', name:'Infantry', icon: 'left', cost: 100, hp:20, size:1, range:5,dps:5,tps:2,color:'#0F0',actions:['attack','move'] 20 | inf: type: 'u', name:'Tank', icon: 'left', cost: 1000, hp:300, size:2, range:15,dps:50,tps:4,color:'#0F0',actions:['attack','move'] 21 | brk: type: 'b', name:'Barraks', icon: 'left', cost: 2000, hp:500, size:10, color:'#F22', actions:['build','setrelay'], build: ['inf','bld','wrk'] 22 | trt: type: 'b', name:'Turret', icon: 'left', cost: 500, hp:100, size:8, color:'#F22', actions:['attack'] 23 | 24 | selected : no 25 | 26 | constructor : (opts={}) -> 27 | 28 | @order = (o='wait',rec={}) => 29 | # if rec.force 30 | @order.c.cancel() if @order.c and @order.c.cancel 31 | @order.q = [] 32 | done = (success) => 33 | console.log @id, o, 'done', rec, rec 34 | delete Control.worker.list[@id] 35 | rec.success() if rec.success 36 | @order.q.shift().start() if @order.q.length > 0 37 | name : 0 38 | target : target = rec.target 39 | rec.start = start = => 40 | console.log @id, o, rec 41 | Control.worker.list[@id] = @ 42 | @order.c = rec 43 | @[o](rec,done) 44 | if @order.q.length is 0 then start() 45 | else @order.q.push rec 46 | 47 | {x,y,tpl,@owner} = opts 48 | @owner = Control.player unless @owner 49 | URUnit.byId[@id = URUnit.nextid++] = @ 50 | URUnit.byPlayer[@owner.id] = @ 51 | @setpos(x,y) 52 | @tpl = URUnit.tpl[tpl||'bld'] 53 | if @tpl.type is "u" then @unit() 54 | else @building() 55 | 56 | unit : -> 57 | @hp = @tpl.hp 58 | @order 'wait', force: yes 59 | 60 | building : -> 61 | @hp = 0 62 | @operational = 0 63 | 64 | setpos : (x,y) -> 65 | sector = x+"x"+y 66 | if URUnit.byPos[(oldsector = @x+'x'+@y)] and URUnit.byPos[oldsector][@id] 67 | delete URUnit.byPos[oldsector][@id] 68 | if Object.keys(URUnit.byPos[oldsector]) is 0 69 | delete URUnit.byPos[oldsector] 70 | @x = x; @y = y 71 | URUnit.byPos[sector] = {} unless URUnit.byPos[sector] 72 | URUnit.byPos[sector][@id] = @ 73 | 74 | 75 | wait : (order,callback) -> callback true 76 | 77 | repair : (order,callback) -> 78 | target = order.target 79 | order.cancel = => delete @work 80 | @move order, (success) => 81 | return callback false unless success 82 | @work = => 83 | target.hp += 1 84 | if target.hp > target.tpl.hp 85 | target.hp = target.tpl.hp 86 | delete @work 87 | callback true 88 | 89 | 90 | attack : (order,callback) -> 91 | target = order.target 92 | inrange = => 93 | order.cancel = => delete @work 94 | @work = => 95 | target.hp -= @tpl.dps / 1000 * 33 96 | if target.hp < 0 97 | target.hp = 0 98 | callback true 99 | order.onwaypoint = => 100 | if @distTo(target.x,target.y) <= @tpl.range 101 | order.cancel() 102 | inrange() 103 | @move order, (result) => 104 | return callback false unless result 105 | inrange() 106 | 107 | move : (order,callback) -> 108 | return unless @tpl.tps 109 | done = => 110 | @setpos(@moverec.x,@moverec.y) 111 | @moverec = null 112 | order.cancel = null 113 | callback true if callback 114 | waypoint = => 115 | if @path.length > 0 116 | {x,y} = @path.shift() 117 | @setpos(@moverec.x,@moverec.y) if @moverec 118 | @moverec = 119 | x : x 120 | y : y 121 | eta : eta = 1 / @tpl.tps 122 | start : Date.now() 123 | timer : setTimeout waypoint, eta * 1000 124 | order.cancel = => 125 | console.log 'cancel' 126 | @setpos(@moverec.x,@moverec.y) 127 | order.cancel = null 128 | clearTimeout @moverec.timer 129 | order.onwaypoint() if order.onwaypoint 130 | else done() 131 | {x,y} = order 132 | {target:{x,y}} = order unless x > 0 and y > 0 133 | try 134 | graph = new Graph(Map.walkmap(),diagonal:yes,heuristic:astar.heuristics.diagonal) 135 | start = graph.grid[@x][@y] 136 | end = graph.grid[x][y] 137 | @path = astar.search(graph,start,end) 138 | console.log @path 139 | waypoint() 140 | catch e 141 | callback false 142 | 143 | distTo : (x,y) -> Math.sqrt (dx=@x-x)*dx+(dy=@y-y)*dy 144 | 145 | render : (ctx,x,y,scale,sb2,now) -> 146 | if @moverec 147 | seconds_passed = (now - @moverec.start) / 1000 148 | completed = Math.min( seconds_passed / @moverec.eta, 1 ) 149 | movex = completed * (@moverec.x - @x) * scale 150 | movey = completed * (@moverec.y - @y) * scale 151 | else movex = movey = 0 152 | sx = x * scale + movex + sb2 153 | sy = y * scale + movey + sb2 154 | ss = scale/10*@tpl.size 155 | s2 = ss * 2 156 | if @selected is true 157 | ctx.fillStyle = "#F00" 158 | else ctx.fillStyle = "#FF0" 159 | ctx.beginPath() 160 | ctx.arc sx,sy,ss,0,Math.PI*2 161 | ctx.fill() 162 | ctx.strokeStyle = "solid 1px #000" 163 | ctx.strokeRect sx-ss,sy-ss-5,s2,3 164 | ctx.fillStyle = "#F00" 165 | ctx.fillRect sx-ss,sy-ss-5,s2,3 166 | ctx.fillStyle = "#0F0" 167 | ctx.fillRect sx-ss,sy-ss-5,Math.round((@hp/@tpl.hp)*s2),3 168 | ctx.fillStyle = "#000" 169 | ctx.fillText sx-ss,sy-ss,@hp+'/'+@tpl.hp 170 | 171 | URUnit.tpl.byType[v.type][k] = v for k,v of URUnit.tpl when v.type? 172 | -------------------------------------------------------------------------------- /mod/nuu-mbt/shader/gas_giant.frag: -------------------------------------------------------------------------------- 1 | uniform sampler2D tex0; 2 | uniform sampler2D star_spectrum; 3 | uniform float seed; 4 | uniform float time; 5 | uniform float temperature; 6 | uniform vec3 light; 7 | varying vec3 vNormal; 8 | varying vec2 vTex; 9 | 10 | #define PI 3.1415926535897932384626433832795 11 | 12 | vec3 random3(vec3 c) { 13 | float j = seed + 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0))); 14 | vec3 r; 15 | r.z = fract(512.0*j); 16 | j *= .125; 17 | r.x = fract(512.0*j); 18 | j *= .125; 19 | r.y = fract(512.0*j); 20 | return r-0.5; 21 | } 22 | 23 | const float F3 = 0.3333333; 24 | const float G3 = 0.1666667; 25 | float snoise(vec3 p) { 26 | vec3 s = floor(p + dot(p, vec3(F3))); 27 | vec3 x = p - s + dot(s, vec3(G3)); 28 | vec3 e = step(vec3(0.0), x - x.yzx); 29 | vec3 i1 = e*(1.0 - e.zxy); 30 | vec3 i2 = 1.0 - e.zxy*(1.0 - e); 31 | vec3 x1 = x - i1 + G3; 32 | vec3 x2 = x - i2 + 2.0*G3; 33 | vec3 x3 = x - 1.0 + 3.0*G3; 34 | vec4 w, d; 35 | w.x = dot(x, x); 36 | w.y = dot(x1, x1); 37 | w.z = dot(x2, x2); 38 | w.w = dot(x3, x3); 39 | w = max(0.6 - w, 0.0); 40 | d.x = dot(random3(s), x); 41 | d.y = dot(random3(s + i1), x1); 42 | d.z = dot(random3(s + i2), x2); 43 | d.w = dot(random3(s + 1.0), x3); 44 | w *= w; 45 | w *= w; 46 | d *= w; 47 | return dot(d, vec4(52.0)); } 48 | 49 | float snoise(vec3 uv, float res){ 50 | const vec3 s = vec3(1e0, 1e2, 1e4); 51 | uv *= res; 52 | vec3 uv0 = floor(mod(uv, res))*s; 53 | vec3 uv1 = floor(mod(uv+vec3(1.), res))*s; 54 | vec3 f = fract(uv); f = f*f*(3.0-2.0*f); 55 | vec4 v = vec4(uv0.x+uv0.y+uv0.z, uv1.x+uv0.y+uv0.z, uv0.x+uv1.y+uv0.z, uv1.x+uv1.y+uv0.z); 56 | vec4 r = fract(sin(v*1e-3)*1e5); 57 | float r0 = mix(mix(r.x, r.y, f.x), mix(r.z, r.w, f.x), f.y); 58 | r = fract(sin((v + uv1.z - uv0.z)*1e-3)*1e5); 59 | float r1 = mix(mix(r.x, r.y, f.x), mix(r.z, r.w, f.x), f.y); 60 | return mix(r0, r1, f.z)*2.-1.; } 61 | 62 | float snoiseFractal(vec3 m) { 63 | return 0.5333333 * 64 | snoise(m,2.) + 65 | 0.2666667 * snoise(2.0*m,2.) + 66 | 0.1333333 * snoise(4.0*m,2.) + 67 | 0.0666667 * snoise(8.0*m,2.); } 68 | 69 | float freqs[4]; 70 | 71 | vec4 baseColor(){ 72 | float u = (temperature - 800.0) / 29200.0; 73 | return texture2D(star_spectrum, vec2(u,0)); } 74 | 75 | float shading(vec3 position){ 76 | vec3 l = normalize(light); 77 | return max(0.015, dot(position, l)); } 78 | 79 | vec4 fineNoise(vec2 p){ 80 | float xx = snoise(vec3(p*4.,0.), 100.); 81 | float yy = snoise(vec3(p*4.,0.), 100.); 82 | float zz = snoise(vec3(p*4.,0.), 100.); 83 | float x = xx + snoise(vec3(p*20.,10.), 64.); 84 | float y = yy + snoise(vec3(p*20.,10.), 64.); 85 | float z = zz + snoise(vec3(p*20.,10.), 64.); 86 | return vec4(x,x,x,time); } 87 | 88 | float fnoise(vec3 position, const int octaves, float frequency, float persistence) { 89 | float total = 0.0; 90 | float maxAmplitude = 0.0; 91 | float amplitude = 1.0; 92 | total += snoise(position * frequency) * amplitude; 93 | frequency *= 2.0; 94 | maxAmplitude += amplitude; 95 | amplitude *= persistence; 96 | total += snoise(position * frequency) * amplitude; 97 | frequency *= 2.0; 98 | maxAmplitude += amplitude; 99 | amplitude *= persistence; 100 | total += snoise(position * frequency) * amplitude; 101 | frequency *= 2.0; 102 | maxAmplitude += amplitude; 103 | amplitude *= persistence; 104 | total += snoise(position * frequency) * amplitude; 105 | frequency *= 2.0; 106 | maxAmplitude += amplitude; 107 | amplitude *= persistence; 108 | total += snoise(position * frequency) * amplitude; 109 | frequency *= 2.0; 110 | maxAmplitude += amplitude; 111 | amplitude *= persistence; 112 | total += snoise(position * frequency) * amplitude; 113 | frequency *= 2.0; 114 | maxAmplitude += amplitude; 115 | amplitude *= persistence; 116 | return total / maxAmplitude; } 117 | 118 | float rnoise(vec3 position, const int octaves, float frequency, float persistence) { 119 | float total = 0.0; 120 | float maxAmplitude = 0.0; 121 | float amplitude = 1.0; 122 | total += ((1.0 - abs(snoise(position * frequency))) * 2.0 - 1.0) * amplitude; 123 | frequency *= 2.0; 124 | maxAmplitude += amplitude; 125 | amplitude *= persistence; 126 | total += ((1.0 - abs(snoise(position * frequency))) * 2.0 - 1.0) * amplitude; 127 | frequency *= 2.0; 128 | maxAmplitude += amplitude; 129 | amplitude *= persistence; 130 | total += ((1.0 - abs(snoise(position * frequency))) * 2.0 - 1.0) * amplitude; 131 | frequency *= 2.0; 132 | maxAmplitude += amplitude; 133 | amplitude *= persistence; 134 | total += ((1.0 - abs(snoise(position * frequency))) * 2.0 - 1.0) * amplitude; 135 | frequency *= 2.0; 136 | maxAmplitude += amplitude; 137 | amplitude *= persistence; 138 | total += ((1.0 - abs(snoise(position * frequency))) * 2.0 - 1.0) * amplitude; 139 | frequency *= 2.0; 140 | maxAmplitude += amplitude; 141 | amplitude *= persistence; 142 | return total / maxAmplitude; } 143 | 144 | float u_k = .1; 145 | vec4 plasma(vec2 p){ 146 | float t = time / 10.; 147 | float v = 0.0; 148 | vec2 c = vec2(p.y,0.) * u_k - u_k/2.0; 149 | v += sin((c.x+t)); 150 | v += sin((c.y+t)/2.0); 151 | v += sin((c.x+c.y+t)/2.0); 152 | c += u_k/2.0 * vec2(sin(t/3.0), cos(t/2.0)); 153 | v += sin(sqrt(c.x*c.x+c.y*c.y+1.0)+t); 154 | v = v/2.0; 155 | vec3 col = vec3(1, sin(PI*v), cos(PI*v)); 156 | return vec4(col, 1); } 157 | 158 | float computeDiffuse(vec3 normal) { 159 | return dot( normal, vec3(1.) ); } 160 | 161 | vec4 colorAt(vec2 p){ 162 | return plasma(p * 100.) * .5 + plasma(p * 1000.); } 163 | 164 | void main() { 165 | vec2 p = vTex; 166 | float n1 = fnoise(vNormal.xyz, 6, 0.1, 0.8) * 0.01; 167 | float n2 = rnoise(vNormal.xyz, 5, 5.8, 0.75) * 0.015 - 0.01; 168 | 169 | // c = vec4(.1); 170 | float s = 0.6; 171 | float t1 = snoise( vNormal.xyz * 2.0 ) - s; 172 | float t2 = snoise((vNormal.xyz + 800.0 ) * 2.0) - s; 173 | float t3 = snoise((vNormal.xyz + 1600.0) * 2.0) - s; 174 | float threshold = max(t1 * t2 * t3, 0.0); 175 | float n3 = sin( snoise(vNormal.xyz * 0.2) ) * threshold; 176 | p.y += n1 * 3. + n2 * 1. + n3; 177 | 178 | vec4 c = colorAt(p); 179 | // c += vec4(threshold * 3.0, 0.0, 0.0, 0.0); 180 | gl_FragColor = vec4( c.xyz * shading(vNormal.xyz), 1.);} 181 | -------------------------------------------------------------------------------- /mod/core/common/stellar.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▒▒▒ 22 | ▒▒▒▓▓▓▓▓▓▓▓▓▓█████▓▓▓▓▓▓▒▒▒ 23 | ▒▒▒▒▓▓▓▓▓▓▓▓▓▓███▓█▓▓▓▓▓▓▓▓▓▓▒▒▒▒ 24 | ▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒▒▒ 25 | ▒▒▒▒▒▒▓▓▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒▒ ▒▒ 26 | ▓▓▓▒▒▒▒▓▒▒▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒ 27 | ▒▓▓▓▓▓▓▒▒▒▒▒▒▒▓▓▒▒ ▒▒▓▓▓▒▒ 28 | ▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒ ▒▓▓▒ 29 | ▒▒▒▒▒ ▒▒▒▒▒ ▒ ▒▓▓▓ ▒▒ ▒ 30 | ▒▒▒ ▒▒▓▓▓▒▒▒▓▓▓▓▒▒▒▒▒▒▒▒▒▒ 31 | ▒▒▒▒▒▒ ▒▒▓▓▓▒▒▒▒▒▓▓▓▓▒▒▒▓▒▒▓▓▓▓▒▒▒▓▒▒ 32 | ▒ ▒▒▓▓▒▒▒▒▒▓▓▓▓▒▒ ▒▒▒ 33 | ▒▒▒ ▒▒▒▒▒▒▒▒▓▓▓▒▓▓▒▒▒▒ ▒▒▒▒▒▒▒▒ 34 | ▒▓▓▓▒ ▒ ▒▒▒▒▒▒▒▒▒▓▒▒ ▒ ▒▒▒▒▒▒ 35 | ▓▒▓▒ ▒▒▒▒▒▓▓▓▓▓▒▒▒ ▒ ▒▓▓▒▒▒ 36 | ▒▓▓▒ ▒▒▒▒▒▒▒▒▓▓▓▒▒▒ ▒▒▒▒ ▒▒▒▒ 37 | ▒▒▒▒▒▒▒▓▓▒▒▒▒ ▒▒▒▒▓▓▒ 38 | ▒▒▒ ▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒ 39 | ▒▒ 40 | ▒ 41 | ▒ 42 | ▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒ 43 | 44 | ██████ ██████ ███ ██ ██████ █████ ██████ ██ ██████ ██ ██ 45 | ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ 46 | ██ ██ ██ ██ ██ ██ ██ ██ ██ ███████ ██ ███ ██ ██ ██ ██ █ ██ 47 | ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ███ ██ 48 | ██████ ██████ ██ ████ ██████ ██ ██ ██████ ███████ ██████ ███ ███ 49 | https://en.wikipedia.org/wiki/Don_Daglow ### 50 | 51 | # ███████ ████████ ███████ ██ ██ █████ ██████ 52 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ 53 | # ███████ ██ █████ ██ ██ ███████ ██████ 54 | # ██ ██ ██ ██ ██ ██ ██ ██ ██ 55 | # ███████ ██ ███████ ███████ ███████ ██ ██ ██ ██ 56 | 57 | $obj.byName = {} 58 | $obj.register class Stellar extends $obj 59 | interval: 1000 60 | @interfaces: [$obj,Stellar] 61 | constructor:(opts)-> 62 | super opts 63 | unless @orbits then @orbits = ( 64 | if @size > 500 then [500,1000,1500,2000] 65 | else if @size > 300 then [500,1000,1500] 66 | else if @size > 100 then [500,1000] 67 | else [500] ) 68 | @lastCycle = @nextCyle = 0 69 | @name = "#{@constructor.name} [#{@id}]" unless @name 70 | $obj.byName[@name] = @ 71 | console.log @constructor.name.yellow, @name, ( @buildRoot?.name || '' ).red,( @state?.relto?.name || '' ).bold if debug 72 | Economy.attach @ if isServer 73 | destructor:-> 74 | @zone.detach @ if @zone 75 | super() 76 | toJSON: -> return { 77 | id: @id 78 | key: @key 79 | sprite: @sprite 80 | state: @state 81 | name: @name 82 | orbits: if @orbits[0] is 500 then undefined else @orbits 83 | produces: @produces 84 | consumes: @consumes } 85 | produce:-> e:@produces.e * @level 86 | 87 | Stellar::actions = ['travel','orbit','land','jump'] 88 | Stellar::defaultAction = -> 89 | d = VEHICLE.dist TARGET 90 | mode = 'travel' 91 | mode = 'orbit' if d < 10e3 and TARGET.bigMass 92 | mode = 'land' if d < TARGET.size + VEHICLE.size 93 | mode 94 | 95 | Object.defineProperty Stellar::, 'zoneDomain', get:-> 96 | "#{@name}.#{@zone.root.name}" 97 | 98 | Stellar.init = -> 99 | console.log ':nuu', 'init:stars' if debug 100 | orbits = {} 101 | now = Date.now() 102 | rules.lastId = 256 103 | for i in rules.stars 104 | continue unless o = i[7] 105 | continue unless o.occupiedBy 106 | rules.seedEconomy i, o 107 | for i in rules.stars 108 | [ id, Constructor, name, sprite, orbit, state, relto, args ] = i 109 | orbits[relto+'_'+orbit] = l = orbits[relto+'_'+orbit] || [] 110 | l.push id 111 | for i in rules.stars 112 | [ id, Constructor, name, sprite, orbit, state, relto, args ] = i 113 | args = {} unless args 114 | odx = orbits[relto+'_'+orbit].indexOf id 115 | oct = ( orbits[relto+'_'+orbit] || [] ).length 116 | relto$ = $obj.byId[relto] || x:0,y:0,update:$void 117 | relto$.update() 118 | rand = if oct is 1 then TAU * random() else ( TAU / oct ) * odx 119 | vel = 0.05 120 | if 0 < hrs = args.t 121 | vel = ( TAU * orbit ) / ( hrs * 360000 ) # ten times faster 122 | stp = TAU / ( ( TAU * orbit ) / vel ) 123 | state = S:state, relto:relto$, t:now, orb:orbit, vel:vel, stp:stp, off:rand 124 | opts = Object.assign args||{}, id:id, name:name, sprite:sprite, state:state 125 | new Constructor opts 126 | return 127 | 128 | Object.defineProperty Stellar::, 'buildRoot', get:-> 129 | p = @; u = {}; u[p.id] = true 130 | console.log '-', @name, @state.relto.name if @state.relto if debug 131 | p.state.update time = NUU.time() 132 | while r = p.state.relto 133 | console.log '|', p.name if debug 134 | r.state.update time 135 | if 150000 < d = $dist(p,r) 136 | console.log 'x:dist', d if debug 137 | break 138 | if u[r.id] 139 | console.log 'x:uniq', r.name if debug 140 | break 141 | u[(p = r).id] = true 142 | console.log '->', p.name, p.constructor.name if debug 143 | switch p.constructor.name 144 | when 'Star','Planet','Moon' then p 145 | else null 146 | 147 | $obj.register class Star extends Stellar 148 | @interfaces: [$obj,Stellar] 149 | provides: e:1000 150 | bigMass:yes 151 | 152 | $obj.register class Planet extends Stellar 153 | @interfaces: [$obj,Stellar] 154 | bigMass:yes 155 | 156 | $obj.register class Moon extends Stellar 157 | @interfaces: [$obj,Stellar] 158 | bigMass:yes 159 | -------------------------------------------------------------------------------- /mod/nuu/sprites/gov/hks.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 39 | 41 | 42 | 44 | image/svg+xml 45 | 47 | 48 | 49 | 50 | 51 | 56 | 61 | 68 | 73 | 80 | 85 | 92 | 99 | 106 | 113 | 120 | 125 | 132 | 139 | 146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /mod/core/client/keyboard.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | $static 'Kbd', new EventEmitter 24 | 25 | Kbd.init = -> 26 | Kbd = @ 27 | @help = {} 28 | @state = {} 29 | @mmap = {} 30 | @rmap = {} 31 | @up = {} 32 | @dn = {} 33 | window.addEventListener 'keyup', @onKeyUp.bind @ 34 | window.addEventListener 'keydown', @onKeyDown.bind @ 35 | null 36 | 37 | # source: mdn these keycodes should be available on all major platforms 38 | Kbd.workingKeycodes2018 = ["AltLeft","AltRight","ArrowDown","ArrowLeft","ArrowRight","ArrowUp","Backquote","Backslash","Backspace","BracketLeft","BracketRight","CapsLock","Comma","ContextMenu","ControlLeft","ControlRight","Convert","Copy","Cut","Delete","Digit0","Digit1","Digit2","Digit3","Digit4","Digit5","Digit6","Digit7","Digit8","Digit9","End","Enter","Equal","Escape","F1","F10","F11","F12","F13","F14","F15","F16","F17","F18","F19","F2","F20","F3","F4","F5","F6","F7","F8","F9","Find","Help","Home","Insert","IntlBackslash","KeyA","KeyB","KeyC","KeyD","KeyE","KeyF","KeyG","KeyH","KeyI","KeyJ","KeyK","KeyL","KeyM","KeyN","KeyO","KeyP","KeyQ","KeyR","KeyS","KeyT","KeyU","KeyV","KeyW","KeyX","KeyY","KeyZ","Minus","NonConvert","NumLock","Numpad0","Numpad1","Numpad2","Numpad3","Numpad4","Numpad5","Numpad6","Numpad7","Numpad8","Numpad9","NumpadAdd","NumpadDecimal","NumpadDivide","NumpadEnter","NumpadEqual","NumpadMultiply","NumpadSubtract","Open","OSLeft","OSRight","PageDown","PageUp","Paste","Pause","Period","PrintScreen","Props","Quote","ScrollLock","Select","Semicolon","ShiftLeft","ShiftRight","Slash","Space","Tab","Undo"] 39 | 40 | Kbd.macro = (name,key,d10,func)-> 41 | NUU.settings.bind = {} unless NUU.settings.bind? 42 | key = NUU.settings.bind[name] || key 43 | console.log key, name, NUU.settings.bind[name]? if debug 44 | @macro[name] = func 45 | @bind key, name if key 46 | @d10[name] = d10 47 | 48 | Kbd.bind = (combo,macro,opt) -> 49 | opt = @macro[macro] unless opt? 50 | delete @rmap[combo] 51 | delete @help[combo] 52 | return console.log ':kbd', 'bind:opt:undefined', macro, key, combo, opt unless opt? 53 | opt = up: opt if typeof opt is 'function' 54 | key = combo.replace /^[cas]+/,'' 55 | return console.log ':kbd', 'bind:key:unknown', macro, key, combo, opt if -1 is @workingKeycodes2018.indexOf key 56 | console.log ':kbd', 'bind', combo, opt if debug 57 | @up[macro] = opt.up if opt.up? 58 | @dn[macro] = opt.dn if opt.dn? 59 | @mmap[macro] = combo 60 | @rmap[combo] = macro 61 | @help[combo] = macro 62 | @state[key] = off 63 | 64 | Kbd.onKeyDown = (e) -> 65 | # allow some browser-wide shortcuts that would otherwise not work 66 | return if e.ctrlKey and e.code is 'KeyC' if isClient 67 | return if e.ctrlKey and e.code is 'KeyV' if isClient 68 | return if e.ctrlKey and e.code is 'KeyR' if isClient 69 | return if e.ctrlKey and e.code is 'KeyL' if isClient 70 | # allow the inspector; but only in debug mode ;) 71 | return if e.ctrlKey and e.shiftKey and e.code is 'KeyI' if debug 72 | code = e.code 73 | code = 'c' + code if e.ctrlKey 74 | code = 'a' + code if e.altKey 75 | code = 's' + code if e.shiftKey 76 | if @onkeydown 77 | return @onkeydown e, code 78 | return true if @onkeyup 79 | e.preventDefault() unless e.allowDefault 80 | macro = @rmap[code] 81 | notice 500, "d[#{code}]:#{macro} #{e.code}" if debug 82 | return if @state[code] is true 83 | @state[code] = true 84 | @dn[macro](e) if @dn[macro]? 85 | 86 | Kbd.onKeyUp = (e) -> 87 | e.preventDefault() 88 | code = e.code 89 | code = 'c' + code if e.ctrlKey 90 | code = 'a' + code if e.altKey 91 | code = 's' + code if e.shiftKey 92 | return @onkeyup e, code if @onkeyup 93 | macro = @rmap[code] 94 | notice 500, "u[#{code}]:#{macro}" if debug 95 | return if @state[code] is false 96 | @state[code] = false 97 | @up[macro](e) if @up[macro]? 98 | 99 | Kbd.stack = [] 100 | 101 | Kbd.clearHooks = (key)-> 102 | @focus = null 103 | document.removeEventListener 'paste', @onpaste if @onpaste 104 | delete @onpaste 105 | delete @onkeyup 106 | delete @onkeydown 107 | true 108 | 109 | Kbd.grab = (focus,opts)-> 110 | # console.log ':kbd', 'grab', focus.name if debug 111 | if @focus 112 | if @focus is focus and opts.onkeydown is @onkeydown and opts.onkeyup is @onkeyup and opts.onpaste is @onpaste 113 | console.log ':kbd', 'same', @focus.name if debug 114 | else 115 | console.log ':kbd', 'obscure', @focus.name # if debug 116 | @stack.push focus:@focus, onkeydown:@onkeydown, onkeyup:@onkeyup, onpaste:@onpaste 117 | do @clearHooks 118 | else 119 | console.log ':kbd', 'grab', focus.name if debug 120 | @focus = focus 121 | Object.assign @, opts 122 | @focus.raise() if @focus.raise? 123 | document.addEventListener 'paste', @onpaste if @onpaste 124 | Mouse.disableTemp() 125 | # console.log ':kbd', 'grabbed', @focus.name if debug 126 | true 127 | 128 | Kbd.release = (focus)-> 129 | if @focus is focus 130 | console.log ':kbd', 'release_current', focus.name if debug 131 | do @clearHooks 132 | if @stack.length is 0 133 | console.log ':kbd', 'main-focus' if debug 134 | Mouse.enableIfWasEnabled() 135 | return true 136 | item = @stack.pop() 137 | @grab item.focus, item 138 | console.log ':kbd', 'main' unless @focus if debug 139 | true 140 | else if @stack.length > 0 and item = @stack.reverse().reduce( (v,c=no)-> if v.focus is focus then v else c ) 141 | console.log ':kbd', 'release_obscured', focus.name if debug 142 | Array.remove @stack, item 143 | console.log ':kbd', 'main' unless @focus if debug 144 | true 145 | else false 146 | 147 | Kbd.defaultMap = 148 | boost: 'sArrowUp' 149 | accel: 'ArrowUp' 150 | retro: 'ArrowDown' 151 | left: 'ArrowLeft' 152 | right: 'ArrowRight' 153 | 154 | Kbd.d10 = 155 | execute: "Execute something" 156 | accel: "Accelerate" 157 | retro: "Decelerate" 158 | left: "Turn left" 159 | right: "Turn right" 160 | autopilot: "Turn to target" 161 | escape: "Exit something" 162 | boost: "Boost" 163 | 164 | do Kbd.init 165 | -------------------------------------------------------------------------------- /mod/nuu/client/target.coffee: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | * c) 2007-2022 Sebastian Glaser 4 | * c) 2007-2022 flyc0r 5 | 6 | This file is part of NUU. 7 | 8 | NUU is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | NUU is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with NUU. If not, see . 20 | 21 | ### 22 | 23 | NUU.on 'target:new', (opts)-> 24 | Target.widget() 25 | 26 | NUU.on '$obj:destroyed', (v)-> 27 | delete Target.hostile[k] for k,i of Target.hostile when i.id is v.id 28 | Target.enemy() if Target.hostile.length > 0 29 | return 30 | 31 | NET.on 'hostile', addHostile = (id)-> 32 | count = 1 33 | doAdd = (i)-> 34 | return console.log ':tgt', 'hostile:unknown', i unless v = $obj.byId[i] 35 | return if v.destructing 36 | Target.hostile[v.id] = v 37 | NUU.emit 'hostile', i 38 | if Array.isArray id 39 | Array.empty Target.hostile 40 | id.map doAdd 41 | count = id.length 42 | else doAdd id 43 | Target.types[0] = Target.hostile 44 | NUU.emit 'hostiles', Target.hostile 45 | if Target.hostile.length is 0 46 | do Target.nothing 47 | else do Target.enemy 48 | return 49 | 50 | window.TARGET = null 51 | 52 | $public class Target 53 | @id: 0 54 | @class: 0 55 | @mode: 'land' 56 | @hostile: h = [] 57 | @typeNames : ['off','hostile','ship','stellar','roid','all'] 58 | @types : [[],h,Ship.byId,Stellar.byId,Asteroid.byId,$obj.byId] 59 | 60 | Target.widget = -> 61 | HUD.widget 'target', "#{Target.mode}", yes 62 | 63 | Target.set = (target,callback)-> 64 | old.unref @ if old = TARGET 65 | unless window.TARGET = target 66 | NUU.emit 'target:new', null, old 67 | return 68 | target.ref @, (v)-> 69 | Target.enemy() 70 | NUU.emit 'target:lost', v 71 | return 72 | unless ( actions = TARGET.actions ).includes oldMode = Target.mode 73 | Target.mode = TARGET.defaultAction?() || actions[0] || '' 74 | return console.log ':tgt', 'nx:ty' unless ty = Target.types 75 | return console.log ':tgt', 'nx:cl' unless cl = ty[Target.class] 76 | return console.log ':tgt', 'nx:ks' unless ks = Object.keys cl 77 | Target.id = if -1 is id = ks.indexOf '' + target.id then 0 else id 78 | callback? TARGET 79 | NUU.emit 'target:new', target, old 80 | return TARGET 81 | 82 | Target.mutate = (fnc)-> again = (callback,skipSelf=false)-> 83 | return console.log ':tgt', 'nx:ty' unless ty = Target.types 84 | return console.log ':tgt', 'nx:cl' unless cl = ty[Target.class] 85 | return console.log ':tgt', 'nx:ks' unless ks = Object.keys cl 86 | ct = ks.length 87 | ix = if ( cu = TARGET || cl[ks[0]] || null ) then ks.indexOf '' + cu.id else 0 88 | id = ks[fnc ix, ct, cl, ks, skipSelf] 89 | ta = cl[id] 90 | if ( skipSelf is false ) and ( ta? and VEHICLE? ) and ( ta.id is VEHICLE.id ) 91 | ta = again callback, VEHICLE.id, window.TARGET = ta 92 | Target.set ta, callback 93 | 94 | Target.prev = Target.mutate (ix,ct)-> ( ct + --ix ) % ct 95 | Target.next = Target.mutate (ix,ct)-> ++ix % ct 96 | 97 | Target.closest = Target.mutate (ix,ct,cl,ks,skipSelf) -> 98 | return console.log ':tgt', 'nx:v' unless v = VEHICLE 99 | dist = Infinity; closest = null 100 | for k,t of cl when t and t.id isnt v.id and (d = $dist v, t) < dist 101 | continue if t.destructing 102 | continue if t.id is skipSelf 103 | dist = d; closest = t 104 | return if closest? then ks.indexOf '' + closest.id else 0 105 | 106 | Target.nothing = -> 107 | Target.class = 0 108 | Target.set null 109 | 110 | Target.enemy = -> 111 | return if TARGET and Target.hostile[TARGET.id] 112 | Target.class = 1 # hostile 113 | do Target.closest 114 | 115 | Target.nextClass = -> 116 | ct = ( list = Target.types ).length 117 | Target.class = ++Target.class % ct 118 | do Target.closest 119 | do Target.nextClass if Target.class is 1 and VEHICLE.hostile.length is 0 120 | return 121 | 122 | Target.prevClass = -> 123 | ct = ( list = Target.types ).length 124 | Target.class = ( ct + --Target.class ) % ct 125 | do Target.closest 126 | do Target.prevClass if Target.class is 1 and VEHICLE.hostile.length is 0 127 | return 128 | 129 | Target.toggleMode = -> 130 | li = TARGET.actions || ['n/a'] 131 | le = li.length 132 | ci = li.indexOf Target.mode 133 | Target.mode = if ci is -1 then ( TARGET.defaultAction?() || li[0] ) else li[++ci%le] 134 | Target.widget() 135 | return 136 | 137 | Target.eva = -> 138 | NET.action.write 0, 'eva' 139 | return 140 | 141 | Target.launch = -> 142 | NET.action.write 0, 'launch' 143 | return 144 | 145 | Target.orbit = -> 146 | return unless t = TARGET 147 | NET.action.write t, Target.mode 148 | return 149 | 150 | Target.jump = -> 151 | return unless t = TARGET 152 | NET.json.write jump: t.id 153 | return 154 | 155 | Target.capture = capture = -> 156 | return unless t = TARGET 157 | NET.action.write t, 'capture' 158 | return 159 | 160 | Target.roid = -> 161 | Target.class = 4 162 | do Target.closest 163 | 164 | Target.captureClosest = -> 165 | Target.class = 5 # all 166 | Target.closest (t)-> capture t if t? 167 | return 168 | 169 | Target.prompt = -> 170 | vt.prompt "target#", ( 171 | (seek)-> 172 | return if seek.trim() is '' 173 | seek = seek.toLowerCase() 174 | t = Object 175 | .keys($obj.byName) 176 | .filter (i)-> null != i.toLowerCase().match seek 177 | .map (i)-> $obj.byName[i] 178 | Target.set t[0] if t[0] 179 | ), yes 180 | 181 | Kbd.macro 'targetSearch', 'KeyG', 'Target search', Target.prompt 182 | Kbd.macro 'targetNothing', 'sKeyW', 'Target nothing', Target.nothing 183 | Kbd.macro 'targetNext', 'KeyD', 'Target next', Target.next 184 | Kbd.macro 'targetClassNext', 'KeyW', 'Target next class', Target.nextClass 185 | Kbd.macro 'targetPrev', 'KeyA', 'Target prev', Target.prev 186 | Kbd.macro 'targetClassPrev', 'KeyS', 'Target prev class', Target.prevClass 187 | Kbd.macro 'targetClosest', 'KeyU', 'Target closest target', Target.closest 188 | Kbd.macro 'targetEnemy', 'KeyE', 'Target closest enemy', Target.enemy 189 | Kbd.macro 'targetRoid', 'KeyR', 'Target closest asteroid', Target.roid 190 | Kbd.macro 'targetMode', 'KeyQ', 'Toggle Land/Dock/Orbit', Target.toggleMode 191 | Kbd.macro 'orbit', 'Tab', 'Land / Dock / Enter Orbit', Target.orbit 192 | Kbd.macro 'launch', 'aKeyQ', 'Launch / Undock', Target.launch 193 | Kbd.macro 'eva', 'saKeyQ', 'EVA', Target.eva 194 | Kbd.macro 'jump', 'KeyJ', 'Jump to target', Target.jump 195 | Kbd.macro 'capture', 'sKeyC', 'Capture target', Target.capture 196 | Kbd.macro 'captureClosest', 'KeyC', 'Capture closest', Target.captureClosest 197 | --------------------------------------------------------------------------------