2023-05-24 20:45:50 -05:00
var files = { } ;
function load ( file ) {
2023-09-18 10:45:51 -05:00
var modtime = cmd ( 0 , file ) ;
2023-05-24 20:45:50 -05:00
files [ file ] = modtime ;
2023-09-18 12:35:40 -05:00
}
2023-05-24 20:45:50 -05:00
2023-09-18 10:45:51 -05:00
load ( "scripts/base.js" ) ;
2023-09-07 16:46:35 -05:00
load ( "scripts/std.js" ) ;
2023-09-05 17:09:25 -05:00
2023-05-29 10:47:30 -05:00
function run ( file )
{
2023-06-08 17:27:37 -05:00
var modtime = cmd ( 119 , file ) ;
2023-05-29 10:47:30 -05:00
if ( modtime === 0 ) {
Log . stack ( ) ;
return false ;
}
files [ file ] = modtime ;
2023-06-08 17:27:37 -05:00
return cmd ( 117 , file ) ;
2023-05-29 10:47:30 -05:00
}
2023-11-02 17:25:00 -05:00
function run _env ( file , env )
{
var script = IO . slurp ( file ) ;
return function ( ) { return eval ( script ) ; } . call ( env ) ;
}
2023-04-22 16:44:26 -05:00
load ( "scripts/diff.js" ) ;
2023-09-05 17:09:25 -05:00
Log . level = 1 ;
2023-05-24 20:45:50 -05:00
2023-04-22 16:44:26 -05:00
var Color = {
2023-09-23 12:35:02 -05:00
white : [ 255 , 255 , 255 ] ,
black : [ 0 , 0 , 0 ] ,
blue : [ 84 , 110 , 255 ] ,
green : [ 120 , 255 , 10 ] ,
yellow : [ 251 , 255 , 43 ] ,
red : [ 255 , 36 , 20 ] ,
teal : [ 96 , 252 , 237 ] ,
gray : [ 181 , 181 , 181 ] ,
2023-06-07 17:26:46 -05:00
cyan : [ 0 , 255 , 255 ] ,
2023-09-21 12:50:39 -05:00
purple : [ 162 , 93 , 227 ] ,
2023-04-22 16:44:26 -05:00
} ;
2023-10-17 12:22:06 -05:00
Color . editor = { } ;
Color . editor . ur = Color . green ;
2023-10-09 13:03:12 -05:00
Color . tohtml = function ( v )
{
var html = v . map ( function ( n ) { return Number . hex ( n * 255 ) ; } ) ;
return "#" + html . join ( '' ) ;
}
Color . toesc = function ( v )
{
return Esc . color ( v ) ;
}
var Esc = { } ;
Esc . reset = "\x1b[0" ;
Esc . color = function ( v ) {
var c = v . map ( function ( n ) { return Math . floor ( n * 255 ) ; } ) ;
var truecolor = "\x1b[38;2;" + c . join ( ';' ) + ';' ;
return truecolor ;
}
2023-09-21 12:50:39 -05:00
Color . Arkanoid = {
2023-09-23 12:35:02 -05:00
orange : [ 255 , 143 , 0 ] ,
teal : [ 0 , 255 , 255 ] ,
green : [ 0 , 255 , 0 ] ,
red : [ 255 , 0 , 0 ] ,
blue : [ 0 , 112 , 255 ] ,
purple : [ 255 , 0 , 255 ] ,
2023-09-21 12:50:39 -05:00
yellow : [ 255 , 255 , 0 ] ,
silver : [ 157 , 157 , 157 ] ,
gold : [ 188 , 174 , 0 ] ,
} ;
Color . Arkanoid . Powerups = {
red : [ 174 , 0 , 0 ] , /* laser */
blue : [ 0 , 0 , 174 ] , /* enlarge */
green : [ 0 , 174 , 0 ] , /* catch */
orange : [ 224 , 143 , 0 ] , /* slow */
purple : [ 210 , 0 , 210 ] , /* break */
cyan : [ 0 , 174 , 255 ] , /* disruption */
gray : [ 143 , 143 , 143 ] /* 1up */
} ;
Color . Gameboy = {
darkest : [ 229 , 107 , 26 ] ,
dark : [ 229 , 189 , 26 ] ,
light : [ 189 , 229 , 26 ] ,
lightest : [ 107 , 229 , 26 ] ,
} ;
Color . Apple = {
green : [ 94 , 189 , 62 ] ,
yellow : [ 255 , 185 , 0 ] ,
orange : [ 247 , 130 , 0 ] ,
red : [ 226 , 56 , 56 ] ,
purple : [ 151 , 57 , 153 ] ,
blue : [ 0 , 156 , 223 ]
} ;
2023-09-23 12:35:02 -05:00
Color . Debug = {
boundingbox : Color . white ,
names : [ 84 , 110 , 255 ] ,
} ;
Color . Editor = {
grid : [ 99 , 255 , 128 ] ,
select : [ 255 , 255 , 55 ] ,
newgroup : [ 120 , 255 , 10 ] ,
} ;
/* Detects the format of all colors and munges them into a floating point format */
Color . normalize = function ( c ) {
var add _a = function ( a ) {
var n = this . slice ( ) ;
n . a = a ;
return n ;
} ;
for ( var p of Object . keys ( c ) ) {
var fmt = "nrm" ;
if ( typeof c [ p ] !== 'object' ) continue ;
if ( ! Array . isArray ( c [ p ] ) ) {
Color . normalize ( c [ p ] ) ;
continue ;
}
for ( var color of c [ p ] ) {
if ( color > 1 ) {
fmt = "8b" ;
break ;
}
}
switch ( fmt ) {
case "8b" :
c [ p ] = c [ p ] . map ( function ( x ) { return x / 255 ; } ) ;
}
c [ p ] . alpha = add _a ;
}
} ;
Color . normalize ( Color ) ;
2023-09-21 12:50:39 -05:00
Object . deepfreeze ( Color ) ;
2023-09-22 09:44:58 -05:00
var ColorMap = { } ;
ColorMap . makemap = function ( map )
{
var newmap = Object . create ( ColorMap ) ;
Object . assign ( newmap , map ) ;
return newmap ;
}
ColorMap . Jet = ColorMap . makemap ( {
0 : [ 0 , 0 , 131 ] ,
0.125 : [ 0 , 60 , 170 ] ,
0.375 : [ 5 , 255 , 255 ] ,
0.625 : [ 255 , 255 , 0 ] ,
0.875 : [ 250 , 0 , 0 ] ,
1 : [ 128 , 0 , 0 ]
} ) ;
ColorMap . BlueRed = ColorMap . makemap ( {
0 : [ 0 , 0 , 255 ] ,
1 : [ 255 , 0 , 0 ]
} ) ;
ColorMap . Inferno = ColorMap . makemap ( {
0 : [ 0 , 0 , 4 ] ,
0.13 : [ 31 , 12 , 72 ] ,
0.25 : [ 85 , 15 , 109 ] ,
0.38 : [ 136 , 34 , 106 ] ,
0.5 : [ 186 , 54 , 85 ] ,
0.63 : [ 227 , 89 , 51 ] ,
0.75 : [ 249 , 140 , 10 ] ,
0.88 : [ 249 , 201 , 50 ] ,
1 : [ 252 , 255 , 164 ]
} ) ;
ColorMap . Bathymetry = ColorMap . makemap ( {
0 : [ 40 , 26 , 44 ] ,
0.13 : [ 59.49 , 90 ] ,
0.25 : [ 64 , 76 , 139 ] ,
0.38 : [ 63 , 110 , 151 ] ,
0.5 : [ 72 , 142 , 158 ] ,
0.63 : [ 85 , 174 , 163 ] ,
0.75 : [ 120 , 206 , 163 ] ,
0.88 : [ 187 , 230 , 172 ] ,
1 : [ 253 , 254 , 204 ]
} ) ;
ColorMap . Viridis = ColorMap . makemap ( {
0 : [ 68 , 1 , 84 ] ,
0.13 : [ 71 , 44 , 122 ] ,
0.25 : [ 59 , 81 , 139 ] ,
0.38 : [ 44 , 113 , 142 ] ,
0.5 : [ 33 , 144 , 141 ] ,
0.63 : [ 39 , 173 , 129 ] ,
0.75 : [ 92 , 200 , 99 ] ,
0.88 : [ 170 , 220 , 50 ] ,
1 : [ 253 , 231 , 37 ]
} ) ;
2023-09-23 12:35:02 -05:00
Color . normalize ( ColorMap ) ;
2023-09-22 09:44:58 -05:00
ColorMap . sample = function ( t , map )
{
map ? ? = this ;
if ( t < 0 ) return map [ 0 ] ;
if ( t > 1 ) return map [ 1 ] ;
var lastkey = 0 ;
for ( var key of Object . keys ( map ) . sort ( ) ) {
if ( t < key ) {
var b = map [ key ] ;
var a = map [ lastkey ] ;
var tt = ( key - lastkey ) * t ;
return a . lerp ( b , tt ) ;
}
lastkey = key ;
}
return map [ 1 ] ;
}
2023-10-23 08:08:11 -05:00
ColorMap . doc = {
sample : "Sample a given colormap at the given percentage (0 to 1)." ,
} ;
2023-09-22 09:44:58 -05:00
Object . freeze ( ColorMap ) ;
2023-06-01 15:58:56 -05:00
function bb2wh ( bb ) {
return [ bb . r - bb . l , bb . t - bb . b ] ;
} ;
2023-11-08 01:39:10 -06:00
var Device = {
pc : [ 1920 , 1080 ] ,
macbook _m2 : [ 2560 , 1664 , 13.6 ] ,
ds _top : [ 400 , 240 , 3.53 ] ,
ds _bottom : [ 320 , 240 , 3.02 ] ,
playdate : [ 400 , 240 , 2.7 ] ,
switch : [ 1280 , 720 , 6.2 ] ,
switch _lite : [ 1280 , 720 , 5.5 ] ,
switch _oled : [ 1280 , 720 , 7 ] ,
dsi : [ 256 , 192 , 3.268 ] ,
ds : [ 256 , 192 , 3 ] ,
dsixl : [ 256 , 192 , 4.2 ] ,
ipad _air _m2 : [ 2360 , 1640 , 11.97 ] ,
iphone _se : [ 1334 , 750 , 4.7 ] ,
iphone _12 _pro : [ 2532 , 1170 , 6.06 ] ,
iphone _15 : [ 2556 , 1179 , 6.1 ] ,
gba : [ 240 , 160 , 2.9 ] ,
gameboy : [ 160 , 144 , 2.48 ] ,
gbc : [ 160 , 144 , 2.28 ] ,
steamdeck : [ 1280 , 800 , 7 ] ,
vita : [ 960 , 544 , 5 ] ,
psp : [ 480 , 272 , 4.3 ] ,
imac _m3 : [ 4480 , 2520 , 23.5 ] ,
macbook _pro _m3 : [ 3024 , 1964 , 14.2 ] ,
ps1 : [ 320 , 240 , 5 ] ,
ps2 : [ 640 , 480 ] ,
snes : [ 256 , 224 ] ,
gamecube : [ 640 , 480 ] ,
n64 : [ 320 , 240 ] ,
c64 : [ 320 , 200 ] ,
macintosh : [ 512 , 342 , 9 ] ,
gamegear : [ 160 , 144 , 3.2 ] ,
} ;
2023-09-07 16:46:35 -05:00
load ( "scripts/gui.js" ) ;
2023-04-22 16:44:26 -05:00
2023-11-16 09:27:04 -06:00
var ctimer = {
2023-09-13 07:31:00 -05:00
make ( fn , secs , obj , loop , app ) {
2023-11-07 12:45:52 -06:00
obj ? ? = globalThis ;
2023-09-13 07:31:00 -05:00
app ? ? = false ;
2023-04-22 16:44:26 -05:00
if ( secs === 0 ) {
fn . call ( obj ) ;
return ;
}
2023-09-24 11:26:44 -05:00
var t = Object . create ( this ) ;
2023-11-07 12:45:52 -06:00
t . id = make _timer ( fn , secs , app , obj ) ;
2023-11-02 17:25:00 -05:00
t . loop = loop ;
t . pause ( ) ;
2023-04-28 12:49:18 -05:00
2023-04-22 16:44:26 -05:00
return t ;
} ,
2023-09-13 07:31:00 -05:00
oneshot ( fn , secs , obj , app ) {
app ? ? = false ;
var t = this . make ( fn , secs , obj , 0 , app ) ;
2023-04-28 12:49:18 -05:00
t . start ( ) ;
2023-11-08 01:39:10 -06:00
return t ;
2023-04-22 16:44:26 -05:00
} ,
get remain ( ) { return cmd ( 32 , this . id ) ; } ,
get on ( ) { return cmd ( 33 , this . id ) ; } ,
get loop ( ) { return cmd ( 34 , this . id ) ; } ,
set loop ( x ) { cmd ( 35 , this . id , x ) ; } ,
start ( ) { cmd ( 26 , this . id ) ; } ,
stop ( ) { cmd ( 25 , this . id ) ; } ,
pause ( ) { cmd ( 24 , this . id ) ; } ,
2023-11-08 01:39:10 -06:00
kill ( ) { if ( this . dead ) return ; cmd ( 27 , this . id ) ; this . dead = true ; } ,
2023-04-22 16:44:26 -05:00
set time ( x ) { cmd ( 28 , this . id , x ) ; } ,
get time ( ) { return cmd ( 29 , this . id ) ; } ,
2023-06-05 14:48:53 -05:00
get pct ( ) { return this . remain / this . time ; } ,
2023-10-23 08:08:11 -05:00
} ;
2023-11-16 09:27:04 -06:00
var timer = {
time : 1 ,
remain : 1 ,
loop : false ,
on : false ,
2023-11-27 14:29:55 -06:00
apptime : false , /* If true, based on app's time instead of game world time */
2023-11-16 09:27:04 -06:00
start ( ) {
this . on = true ;
} ,
restart ( ) {
this . remain = this . time ;
this . start ( ) ;
} ,
update ( dt ) {
if ( ! this . on ) return ;
2023-11-27 14:29:55 -06:00
2023-11-16 09:27:04 -06:00
this . remain -= dt ;
if ( this . remain <= 0 )
this . fire ( ) ;
} ,
fire ( ) {
this . fn ( ) ;
if ( this . loop )
this . restart ( ) ;
} ,
2023-11-27 14:29:55 -06:00
pct ( ) { return 1 - ( this . remain / this . time ) ; } ,
2023-11-16 09:27:04 -06:00
kill ( ) {
Register . unregister _obj ( this ) ;
} ,
delay ( fn , secs , desc ) {
var t = timer . make ( fn , secs , desc ) ;
t . loop = false ;
t . restart ( ) ;
t . fn = function ( ) { fn ( ) ; t . kill ( ) ; } ;
return function ( ) { t . kill ( ) ; } ;
} ,
oneshot ( fn , secs , obj , desc ) {
this . delay ( fn , secs , desc ) ;
} ,
make ( fn , secs , desc ) {
var t = Object . create ( this ) ;
Object . assign ( t , desc ) ;
t . time = secs ;
t . remain = secs ;
t . fn = fn ;
Register . update . register ( t . update , t ) ;
return t ;
} ,
} ;
2023-11-02 17:25:00 -05:00
timer . toJSON = function ( ) { return undefined ; } ;
2023-10-23 08:08:11 -05:00
timer . doc = {
doc : "Quickly make timers to fire off events once or multiple times." ,
oneshot : "Executes a given function after the given number of seconds." ,
make : "Returns a timer that can be handled and reused." ,
start : "Starts the timer." ,
stop : "Stops the timer." ,
loop : "Set to true for the timer to repeat when done." ,
kill : "Destroys the timer." ,
pct : "Get the percentange the timer is complete." ,
time : "Set or get the amount of time this timer waits to execute. Does not reset the time, so if it is set to below the elapsed time it will execute immediately." ,
remain : "The time remianing before the function is executed." ,
2023-04-22 16:44:26 -05:00
} ;
var animation = {
time : 0 ,
loop : false ,
playtime : 0 ,
playing : false ,
keyframes : [ ] ,
create ( ) {
var anim = Object . create ( animation ) ;
2023-08-28 17:00:53 -05:00
Register . update . register ( anim . update , anim ) ;
2023-04-22 16:44:26 -05:00
return anim ;
} ,
start ( ) {
this . playing = true ;
this . time = this . keyframes . last [ 1 ] ;
this . playtime = 0 ;
} ,
interval ( a , b , t ) {
return ( t - a ) / ( b - a ) ;
} ,
near _val ( t ) {
for ( var i = 0 ; i < this . keyframes . length - 1 ; i ++ ) {
if ( t > this . keyframes [ i + 1 ] [ 1 ] ) continue ;
return this . interval ( this . keyframes [ i ] [ 1 ] , this . keyframes [ i + 1 ] [ 1 ] , t ) >= 0.5 ? this . keyframes [ i + 1 ] [ 0 ] : this . keyframes [ i ] [ 0 ] ;
}
return this . keyframes . last [ 0 ] ;
} ,
lerp _val ( t ) {
for ( var i = 0 ; i < this . keyframes . length - 1 ; i ++ ) {
if ( t > this . keyframes [ i + 1 ] [ 1 ] ) continue ;
var intv = this . interval ( this . keyframes [ i ] [ 1 ] , this . keyframes [ i + 1 ] [ 1 ] , t ) ;
return ( ( 1 - intv ) * this . keyframes [ i ] [ 0 ] ) + ( intv * this . keyframes [ i + 1 ] [ 0 ] ) ;
}
return this . keyframes . last [ 0 ] ;
} ,
cubic _val ( t ) {
} ,
mirror ( ) {
if ( this . keyframes . length <= 1 ) return ;
for ( var i = this . keyframes . length - 1 ; i >= 1 ; i -- ) {
this . keyframes . push ( this . keyframes [ i - 1 ] ) ;
this . keyframes . last [ 1 ] = this . keyframes [ i ] [ 1 ] + ( this . keyframes [ i ] [ 1 ] - this . keyframes [ i - 1 ] [ 1 ] ) ;
}
} ,
update ( dt ) {
if ( ! this . playing ) return ;
this . playtime += dt ;
if ( this . playtime >= this . time ) {
if ( this . loop )
this . playtime = 0 ;
else {
this . playing = false ;
return ;
}
}
this . fn ( this . lerp _val ( this . playtime ) ) ;
} ,
} ;
var Render = {
normal ( ) {
cmd ( 67 ) ;
} ,
wireframe ( ) {
cmd ( 68 ) ;
} ,
} ;
2023-11-02 17:25:00 -05:00
Render . doc = {
doc : "Functions for rendering modes." ,
normal : "Final render with all lighting." ,
wireframe : "Show only wireframes of models."
} ;
2023-09-07 16:46:35 -05:00
load ( "scripts/physics.js" ) ;
load ( "scripts/input.js" ) ;
2023-09-08 01:26:48 -05:00
load ( "scripts/sound.js" ) ;
2023-11-27 17:04:04 -06:00
load ( "scripts/ai.js" ) ;
2023-04-25 14:59:26 -05:00
2023-10-23 08:08:11 -05:00
function screen2world ( screenpos ) {
if ( Game . camera )
return Game . camera . view2world ( screenpos ) ;
return screenpos ;
}
2023-09-07 16:46:35 -05:00
function world2screen ( worldpos ) { return Game . camera . world2view ( worldpos ) ; }
2023-04-25 16:59:12 -05:00
2023-04-22 16:44:26 -05:00
var Register = {
2023-05-27 10:13:20 -05:00
inloop : false ,
loopcbs : [ ] ,
finloop ( ) {
this . loopcbs . forEach ( x => x ( ) ) ;
this . loopcbs = [ ] ;
} ,
wraploop ( loop ) {
this . inloop = true ;
loop ( ) ;
this . inloop = false ;
this . finloop ( ) ;
} ,
2023-04-22 16:44:26 -05:00
2023-09-02 06:53:52 -05:00
kbm _input ( mode , btn , state , ... args ) {
2023-09-12 17:19:46 -05:00
if ( state === 'released' ) {
btn = btn . split ( '-' ) . last ;
}
2023-09-02 06:53:52 -05:00
switch ( mode ) {
case "emacs" :
Player . players [ 0 ] . raw _input ( btn , state , ... args ) ;
break ;
2023-09-12 17:19:46 -05:00
case "mouse" :
Player . players [ 0 ] . mouse _input ( btn , state , ... args ) ;
break ;
2023-09-14 12:49:29 -05:00
case "char" :
Player . players [ 0 ] . char _input ( btn ) ;
break ;
2023-09-02 06:53:52 -05:00
} ;
2023-04-22 16:44:26 -05:00
} ,
2023-04-25 16:59:12 -05:00
gamepad _playermap : [ ] ,
gamepad _input ( pad , btn , state , ... args ) {
var player = this . gamepad _playermap [ pad ] ;
if ( ! player ) return ;
2023-08-28 17:00:53 -05:00
var statestr = Input . state2str ( state ) ;
2023-04-25 16:59:12 -05:00
var rawfn = ` gamepad_ ${ btn } _ ${ statestr } ` ;
player . input ( rawfn , ... args ) ;
Action . actions . forEach ( x => {
if ( x . inputs . includes ( btn ) )
player . input ( ` action_ ${ x . name } _ ${ statestr } ` , ... args ) ;
} ) ;
} ,
2023-08-28 17:00:53 -05:00
2023-04-22 16:44:26 -05:00
unregister _obj ( obj ) {
2023-08-28 17:00:53 -05:00
Register . registries . forEach ( function ( x ) {
2023-09-06 17:48:08 -05:00
x . unregister _obj ( obj ) ;
2023-08-28 17:00:53 -05:00
} ) ;
2023-08-29 09:41:40 -05:00
Player . uncontrol ( obj ) ;
2023-04-22 16:44:26 -05:00
} ,
2023-05-24 20:45:50 -05:00
2023-05-27 10:13:20 -05:00
endofloop ( fn ) {
if ( ! this . inloop )
fn ( ) ;
else {
this . loopcbs . push ( fn ) ;
}
} ,
2023-04-25 16:59:12 -05:00
2023-08-28 17:00:53 -05:00
clear ( ) {
Register . registries . forEach ( function ( n ) {
n . entries = [ ] ;
} ) ;
} ,
2023-04-22 16:44:26 -05:00
2023-08-28 17:00:53 -05:00
registries : [ ] ,
2023-06-05 17:19:43 -05:00
2023-08-28 17:00:53 -05:00
add _cb ( idx , name ) {
var entries = [ ] ;
var n = { } ;
n . register = function ( fn , obj ) {
2023-09-06 17:48:08 -05:00
if ( ! obj ) {
2023-09-07 16:46:35 -05:00
Log . error ( "Refusing to register a function without a destroying object." ) ;
2023-09-06 17:48:08 -05:00
return ;
}
2023-09-07 16:46:35 -05:00
entries . push ( {
fn : fn ,
obj : obj
} ) ;
2023-08-28 17:00:53 -05:00
}
2023-04-22 16:44:26 -05:00
2023-08-28 17:00:53 -05:00
n . unregister = function ( fn ) {
2023-10-31 12:38:23 -05:00
entries = entries . filter ( function ( e ) { return e . fn !== fn ; } ) ;
2023-09-06 17:48:08 -05:00
}
n . unregister _obj = function ( obj ) {
2023-09-07 16:46:35 -05:00
entries = entries . filter ( function ( e ) { return e . obj !== obj ; } ) ;
2023-08-28 17:00:53 -05:00
}
2023-04-22 16:44:26 -05:00
2023-08-29 17:11:36 -05:00
n . broadcast = function ( ... args ) {
2023-09-07 16:46:35 -05:00
entries . forEach ( x => x . fn . call ( x . obj , ... args ) ) ;
2023-08-28 17:00:53 -05:00
}
2023-04-22 16:44:26 -05:00
2023-08-28 17:00:53 -05:00
n . clear = function ( ) {
entries = [ ] ;
}
2023-04-22 16:44:26 -05:00
2023-08-28 17:00:53 -05:00
register ( idx , n . broadcast , n ) ;
2023-04-22 16:44:26 -05:00
2023-08-28 17:00:53 -05:00
Register [ name ] = n ;
Register . registries . push ( n ) ;
return n ;
} ,
2023-04-22 16:44:26 -05:00
} ;
2023-08-28 17:00:53 -05:00
Register . add _cb ( 0 , "update" ) . doc = "Called once per frame." ;
Register . add _cb ( 1 , "physupdate" ) ;
Register . add _cb ( 2 , "gui" ) ;
Register . add _cb ( 6 , "debug" ) ;
register ( 7 , Register . kbm _input , Register ) ;
Register . add _cb ( 8 , "gamepad_input" ) ;
Register . add _cb ( 10 , "draw" ) ;
2023-05-24 20:45:50 -05:00
2023-08-28 17:00:53 -05:00
register ( 9 , Log . stack , this ) ;
2023-04-22 16:44:26 -05:00
2023-08-28 17:00:53 -05:00
Register . gamepad _playermap [ 0 ] = Player . players [ 0 ] ;
2023-04-22 16:44:26 -05:00
var Signal = {
signals : [ ] ,
obj _begin ( fn , obj , go ) {
this . signals . push ( [ fn , obj ] ) ;
register _collide ( 0 , fn , obj , go . body ) ;
} ,
obj _separate ( fn , obj , go ) {
this . signals . push ( [ fn , obj ] ) ;
register _collide ( 3 , fn , obj , go . body ) ;
} ,
2023-10-31 12:38:23 -05:00
clear _obj ( obj ) {
2023-04-22 16:44:26 -05:00
this . signals . filter ( function ( x ) { return x [ 1 ] !== obj ; } ) ;
} ,
2023-06-06 15:49:55 -05:00
c : { } ,
register ( name , fn ) {
if ( ! this . c [ name ] )
this . c [ name ] = [ ] ;
this . c [ name ] . push ( fn ) ;
} ,
call ( name , ... args ) {
if ( this . c [ name ] )
this . c [ name ] . forEach ( function ( fn ) { fn . call ( this , ... args ) ; } ) ;
} ,
2023-04-22 16:44:26 -05:00
} ;
2023-10-04 08:18:09 -05:00
var game _quit = function ( )
{
Primum . kill ( ) ;
}
Signal . register ( "quit" , game _quit ) ;
2023-11-22 03:51:43 -06:00
var Event = {
events : { } ,
observe ( name , obj , fn ) {
this . events [ name ] ? ? = [ ] ;
this . events [ name ] . push ( [ obj , fn ] ) ;
} ,
unobserve ( name , obj ) {
this . events [ name ] = this . events [ name ] . filter ( x => x [ 0 ] !== obj ) ;
} ,
notify ( name ) {
if ( ! this . events [ name ] ) return ;
this . events [ name ] . forEach ( function ( x ) {
x [ 1 ] . call ( x [ 0 ] ) ;
} ) ;
} ,
} ;
2023-06-06 15:49:55 -05:00
var Window = {
2023-10-16 09:40:43 -05:00
fullscreen ( f ) { cmd ( 145 , f ) ; } ,
2023-09-04 09:48:44 -05:00
set width ( w ) { cmd ( 125 , w ) ; } ,
set height ( h ) { cmd ( 126 , h ) ; } ,
get width ( ) { return cmd ( 48 ) ; } ,
get height ( ) { return cmd ( 49 ) ; } ,
2023-09-06 12:17:16 -05:00
get dimensions ( ) { return [ this . width , this . height ] ; } ,
2023-09-13 01:08:32 -05:00
set name ( str ) { cmd ( 134 , str ) ; } ,
2023-10-04 08:18:09 -05:00
boundingbox ( ) {
return {
t : Window . height ,
b : 0 ,
r : Window . width ,
l : 0
} ;
} ,
2023-06-06 15:49:55 -05:00
} ;
2023-08-28 17:00:53 -05:00
Window . icon = function ( path ) { cmd ( 90 , path ) ; } ;
Window . icon . doc = "Set the icon of the window using the PNG image at path." ;
2023-04-22 16:44:26 -05:00
function reloadfiles ( ) {
Object . keys ( files ) . forEach ( function ( x ) { load ( x ) ; } ) ;
}
2023-05-24 20:45:50 -05:00
load ( "scripts/debug.js" ) ;
2023-04-22 16:44:26 -05:00
2023-05-29 10:47:30 -05:00
/ *
2023-04-22 16:44:26 -05:00
function Color ( from ) {
var color = Object . create ( Array ) ;
Object . defineProperty ( color , 'r' , setelem ( 0 ) ) ;
Object . defineProperty ( color , 'g' , setelem ( 1 ) ) ;
Object . defineProperty ( color , 'b' , setelem ( 2 ) ) ;
Object . defineProperty ( color , 'a' , setelem ( 3 ) ) ;
color . a = color . g = color . b = color . a = 1 ;
Object . assign ( color , from ) ;
return color ;
} ;
2023-05-29 10:47:30 -05:00
* /
2023-04-22 16:44:26 -05:00
2023-10-29 16:39:45 -05:00
var Spline = { } ;
Spline . sample = function ( degrees , dimensions , type , ctrl _points , nsamples )
{
var s = spline _cmd ( 0 , degrees , dimensions , type , ctrl _points , nsamples ) ;
return s ;
}
Spline . type = {
open : 0 ,
clamped : 1 ,
beziers : 2
} ;
2023-04-22 16:44:26 -05:00
load ( "scripts/components.js" ) ;
function find _com ( objects )
{
if ( ! objects || objects . length === 0 )
return [ 0 , 0 ] ;
var com = [ 0 , 0 ] ;
com [ 0 ] = objects . reduce ( function ( acc , val ) {
return acc + val . pos [ 0 ] ;
} , 0 ) ;
com [ 0 ] /= objects . length ;
com [ 1 ] = objects . reduce ( function ( acc , val ) {
return acc + val . pos [ 1 ] ;
} , 0 ) ;
com [ 1 ] /= objects . length ;
return com ;
} ;
var Game = {
2023-10-23 08:08:11 -05:00
init ( ) {
if ( ! Game . edit ) {
load ( "config.js" ) ;
load ( "game.js" ) ;
}
else {
load ( "scripts/editor.js" ) ;
load ( "editorconfig.js" ) ;
editor . enter _editor ( ) ;
}
} ,
2023-04-22 16:44:26 -05:00
objects : [ ] ,
2023-11-08 01:39:10 -06:00
native : Device . pc ,
2023-09-13 01:08:32 -05:00
edit : true ,
2023-04-22 16:44:26 -05:00
register _obj ( obj ) {
this . objects [ obj . body ] = obj ;
} ,
2023-10-11 17:22:41 -05:00
unregister _obj ( obj ) {
if ( this . objects [ obj . body ] === obj )
this . objects [ obj . body ] = undefined ;
} ,
2023-10-17 12:22:06 -05:00
obj _at ( worldpos ) {
var idx = physics . pos _query ( worldpos ) ;
if ( idx === - 1 ) return undefined ;
return Game . objects [ idx ] ;
} ,
2023-04-22 16:44:26 -05:00
/* Returns an object given an id */
object ( id ) {
return this . objects [ id ] ;
} ,
/* Returns a list of objects by name */
find ( name ) {
} ,
/* Return a list of objects derived from a specific prototype */
find _proto ( proto ) {
} ,
/* List of all objects spawned that have a specific tag */
find _tag ( tag ) {
} ,
groupify ( objects , spec ) {
var newgroup = {
locked : true ,
breakable : true ,
objs : objects ,
// get pos() { return find_com(objects); },
// set pos(x) { this.objs.forEach(function(obj) { obj.pos = x; }) },
} ;
Object . assign ( newgroup , spec ) ;
objects . forEach ( function ( x ) {
x . defn ( 'group' , newgroup ) ;
} ) ;
var bb = bb _from _objects ( newgroup . objs ) ;
newgroup . startbb = bb2cwh ( bb ) ;
newgroup . bboffset = newgroup . startbb . c . sub ( newgroup . objs [ 0 ] . pos ) ;
newgroup . boundingbox = function ( ) {
newgroup . startbb . c = newgroup . objs [ 0 ] . pos . add ( newgroup . bboffset ) ;
return cwh2bb ( newgroup . startbb . c , newgroup . startbb . wh ) ;
} ;
if ( newgroup . file )
2023-09-23 12:35:02 -05:00
newgroup . color = Color . Editor . newgroup ;
2023-04-22 16:44:26 -05:00
return newgroup ;
} ,
2023-08-16 20:17:18 -05:00
quit ( )
{
sys _cmd ( 0 ) ;
} ,
pause ( )
{
sys _cmd ( 3 ) ;
} ,
stop ( )
{
2023-08-29 17:11:36 -05:00
Game . pause ( ) ;
2023-08-16 20:17:18 -05:00
} ,
step ( )
{
sys _cmd ( 4 ) ;
} ,
2023-09-19 12:35:12 -05:00
editor _mode ( m ) { sys _cmd ( 10 , m ) ; } ,
2023-09-06 17:48:08 -05:00
2023-08-16 20:17:18 -05:00
playing ( ) { return sys _cmd ( 5 ) ; } ,
paused ( ) { return sys _cmd ( 6 ) ; } ,
2023-08-27 21:57:19 -05:00
stepping ( ) {
return cmd ( 79 ) ; } ,
2023-08-16 20:17:18 -05:00
play ( )
{
sys _cmd ( 1 ) ;
2023-04-22 16:44:26 -05:00
} ,
2023-09-07 16:46:35 -05:00
get dt ( ) {
return cmd ( 63 ) ;
2023-04-22 16:44:26 -05:00
} ,
2023-09-07 16:46:35 -05:00
wait _fns : [ ] ,
2023-04-22 16:44:26 -05:00
2023-09-07 16:46:35 -05:00
wait _exec ( fn ) {
if ( ! phys _stepping ( ) )
fn ( ) ;
2023-04-22 16:44:26 -05:00
else
2023-09-07 16:46:35 -05:00
this . wait _fns . push ( fn ) ;
2023-04-22 16:44:26 -05:00
} ,
2023-09-07 16:46:35 -05:00
exec ( ) {
this . wait _fns . forEach ( function ( x ) { x ( ) ; } ) ;
2023-04-22 16:44:26 -05:00
2023-09-07 16:46:35 -05:00
this . wait _fns = [ ] ;
2023-04-22 16:44:26 -05:00
} ,
2023-09-07 16:46:35 -05:00
} ;
2023-04-22 16:44:26 -05:00
2023-10-23 08:08:11 -05:00
Game . doc = { } ;
Game . doc . object = "Returns the entity belonging to a given id." ;
Game . doc . quit = "Immediately quit the game." ;
Game . doc . pause = "Pause game simulation." ;
Game . doc . stop = "Stop game simulation. This does the same thing as 'pause', and if the game is a debug build, starts its editor." ;
Game . doc . play = "Resume or start game simulation." ;
Game . doc . editor _mode = "Set to true for the game to only update on input; otherwise the game updates every frame." ;
Game . doc . dt = "Current frame dt." ;
2023-10-31 12:38:23 -05:00
Game . doc . view _camera = "Set the camera for the current view." ;
Game . doc . camera = "Current camera." ;
2023-10-23 08:08:11 -05:00
Window . doc = { } ;
Window . doc . width = "Width of the game window." ;
Window . doc . height = "Height of the game window." ;
Window . doc . dimensions = "Window width and height packaged in an array [width,height]" ;
Window . doc . name = "Name in the title bar of the window." ;
Window . doc . boundingbox = "Boundingbox of the window, with top and right being its height and width." ;
2023-09-07 16:46:35 -05:00
Register . update . register ( Game . exec , Game ) ;
2023-04-22 16:44:26 -05:00
2023-09-08 12:35:06 -05:00
load ( "scripts/entity.js" ) ;
2023-05-27 07:01:17 -05:00
2023-10-23 08:08:11 -05:00
function world _start ( ) {
globalThis . preprimum = Object . create ( gameobject ) ;
var preprimum = globalThis . preprimum ;
2023-10-04 17:57:37 -05:00
preprimum . objects = { } ;
2023-10-05 13:33:43 -05:00
preprimum . worldpos = function ( ) { return [ 0 , 0 ] ; } ;
2023-10-05 17:30:17 -05:00
preprimum . worldangle = function ( ) { return 0 ; } ;
2023-11-15 16:42:39 -06:00
preprimum . scale = [ 1 , 1 , 1 ] ;
preprimum . gscale = function ( ) { return [ 1 , 1 , 1 ] ; } ;
2023-10-05 13:33:43 -05:00
preprimum . pos = [ 0 , 0 ] ;
preprimum . angle = 0 ;
2023-10-10 17:37:58 -05:00
preprimum . remove _obj = function ( ) { } ;
2023-10-18 17:20:23 -05:00
preprimum . toString = function ( ) { return "preprimum" ; } ;
2023-10-23 08:08:11 -05:00
globalThis . World = preprimum . make ( preprimum ) ;
globalThis . Primum = World ;
var Primum = globalThis . Primum ;
2023-09-25 16:34:48 -05:00
Primum . level = undefined ;
2023-09-22 09:44:58 -05:00
Primum . toString = function ( ) { return "Primum" ; } ;
2023-10-06 12:38:49 -05:00
Primum . _ed . selectable = false ;
2023-10-16 19:59:58 -05:00
Primum . _ed . check _dirty = function ( ) { } ;
2023-10-26 11:48:02 -05:00
Primum . _ed . dirty = false ;
2023-10-30 17:41:32 -05:00
Primum . revert = function ( ) { } ;
Primum . ur = undefined ;
2023-10-23 08:08:11 -05:00
globalThis . World . reparent = function ( parent ) { Log . warn ( "Cannot reparent the Primum." ) ; }
Game . view _camera ( Primum . spawn ( ur . camera2d ) ) ;
}
2023-09-08 12:35:06 -05:00
2023-04-22 16:44:26 -05:00
/* Load configs */
function load _configs ( file ) {
2023-09-04 09:48:44 -05:00
Log . info ( ` Loading config file ${ file } . ` ) ;
2023-04-22 16:44:26 -05:00
var configs = JSON . parse ( IO . slurp ( file ) ) ;
for ( var key in configs ) {
2023-08-29 09:41:40 -05:00
if ( typeof globalThis [ key ] !== "object" ) continue ;
2023-04-28 12:49:18 -05:00
Object . assign ( globalThis [ key ] , configs [ key ] ) ;
2023-04-22 16:44:26 -05:00
}
Collision . sync ( ) ;
Game . objects . forEach ( function ( x ) { x . sync ( ) ; } ) ;
if ( ! local _conf . mouse ) {
Log . info ( "disabling mouse features" ) ;
Mouse . disabled = function ( ) { } ;
Mouse . hidden = function ( ) { } ;
} ;
} ;
var local _conf = {
mouse : true ,
} ;
2023-09-07 16:46:35 -05:00
if ( IO . exists ( "game.config" ) )
load _configs ( "game.config" ) ;
2023-04-22 16:44:26 -05:00
/* Save configs */
function save _configs ( ) {
Log . info ( "saving configs" ) ;
var configs = { } ;
configs . editor _config = editor _config ;
configs . Nuke = Nuke ;
configs . local _conf = local _conf ;
IO . slurpwrite ( JSON . stringify ( configs , null , 1 ) , "editor.config" ) ;
save _game _configs ( ) ;
} ;
function save _game _configs ( ) {
var configs = { } ;
configs . physics = physics ;
configs . Collision = Collision ;
Log . info ( configs ) ;
IO . slurpwrite ( JSON . stringify ( configs , null , 1 ) , "game.config" ) ;
Collision . sync ( ) ;
Game . objects . forEach ( function ( x ) { x . sync ( ) ; } ) ;
} ;
2023-09-07 16:46:35 -05:00
load ( "scripts/physics.js" ) ;
2023-04-22 16:44:26 -05:00
2023-09-07 16:46:35 -05:00
Game . view _camera = function ( cam )
2023-08-23 17:18:34 -05:00
{
2023-09-07 16:46:35 -05:00
Game . camera = cam ;
cmd ( 61 , Game . camera . body ) ;
2023-11-08 01:39:10 -06:00
// cam.zoom = cam.zoom;
2023-08-23 17:18:34 -05:00
}
2023-09-13 01:08:32 -05:00
Window . name = "Primum Machinam (V0.1)" ;
2023-09-12 17:19:46 -05:00
Window . width = 1280 ;
Window . height = 720 ;
2023-10-29 16:39:45 -05:00
2023-11-02 17:25:00 -05:00
var Asset = { } ;
Asset . doc = {
doc : "Functions to manage the loading and unloading of assets, like sounds and images."
} ;
2023-11-08 01:39:10 -06:00