You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
16141 lines
2.6 MiB
HTML
16141 lines
2.6 MiB
HTML
3 years ago
|
<!DOCTYPE HTML>
|
||
|
<html>
|
||
|
|
||
|
<!-- HEADER -->
|
||
|
<head>
|
||
|
|
||
|
<meta charset="UTF-8">
|
||
|
|
||
|
<title></title>
|
||
|
|
||
|
<script type="text/bitsyGameData" id="exportedGameData">
|
||
|
|
||
|
|
||
|
# BITSY VERSION 7.3
|
||
|
|
||
|
! ROOM_FORMAT 1
|
||
|
|
||
|
PAL 0
|
||
|
NAME black
|
||
|
0,0,0
|
||
|
57,255,20
|
||
|
57,255,20
|
||
|
|
||
|
ROOM 10
|
||
|
81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,7s,0,7m,74,79,7c,7e,7i,7j,0,0,0,0,0,80
|
||
|
80,7r,7q,7n,75,78,7a,7d,7g,7l,0,0,0,0,0,80
|
||
|
80,0,7p,7o,76,77,7b,7f,7h,7k,0,0,0,0,0,80
|
||
|
80,0,0,0,0,86,87,8a,0,8e,8f,8i,8l,0,0,80
|
||
|
80,0,y,10,0,83,84,88,0,8c,8g,8j,8m,0,0,80
|
||
|
80,0,0,0,0,85,0,89,8b,8d,8h,8k,0,0,0,80
|
||
|
80,0,0,0,0,46,0,0,0,0,0,0,0,46,0,80
|
||
|
81,81,81,81,81,a2,81,81,81,81,81,81,81,a2,81,80
|
||
|
80,80,80,80,80,a1,80,80,80,80,80,80,80,a1,80,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,80,80,a1,80,80
|
||
|
80,0,x,y,z,0,18,10,t,0,0,80,80,a1,80,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,80,80,0,0,0
|
||
|
80,0,0,0,u,y,1b,t,10,0,0,80,80,81,81,81
|
||
|
80,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 12
|
||
|
80,80,0,1b,1k,t,1a,0,x,y,z,0,1m,y,0,0
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
80,80,0,s,y,1l,t,w,1k,1d,1a,19,0,1c,10,0
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
80,80,0,y,1m,z,v,w,1d,30,t,0,1d,1a,0,0
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
80,80,0,x,y,z,10,0,11,10,t,t,0,w,1d,0
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
80,80,0,1l,t,0,1d,s,0,1d,w,0,s,w,1d,0
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
80,80,0,u,u,0,u,t,1d,s,z,10,t,1n,0,0
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
80,80,81,81,81,81,81,81,81,81,81,81,81,81,81,81
|
||
|
80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80
|
||
|
80,0,0,0,0,80,80,0,0,0,0,80,80,0,0,80
|
||
|
80,0,0,0,0,80,80,0,0,0,0,80,80,81,81,80
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 14
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,98,9b,8z,94,8a,0,9q,9t,0,0,0,0,0
|
||
|
0,0,0,99,9c,90,93,88,0,9r,9u,a3,0,0,0,0
|
||
|
0,0,0,9a,9d,91,92,89,8b,9s,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,7s,0,7m,74,79,7c,7e,7i,7j,0,0,0,0,0,0
|
||
|
0,7r,7q,7n,75,78,7a,7d,7g,7l,0,0,0,0,0,0
|
||
|
0,0,7p,7o,76,77,7b,7f,7h,7k,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 16
|
||
|
81,81,81,81,81,81,81,81,81,81,81,81,81,0,81,81
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,8a,0,8e,8f,9l,9n,74,79,9e,9j,7c,7e,0,80
|
||
|
80,0,88,0,8c,8g,9k,9o,75,78,9f,9i,7a,7d,0,80
|
||
|
80,0,89,8b,8d,8h,9m,9p,76,77,9g,9h,7b,7f,0,80
|
||
|
80,0,0,0,7s,0,7m,74,79,7c,7e,7i,7j,0,0,80
|
||
|
80,0,y,10,7r,7q,7n,75,78,7a,7d,7g,7l,0,81,80
|
||
|
80,0,0,0,0,7p,7o,76,77,7b,7f,7h,7k,0,80,80
|
||
|
80,0,0,46,0,0,0,0,0,0,0,0,0,0,80,80
|
||
|
80,81,81,a2,81,81,81,81,81,81,81,81,81,81,80,80
|
||
|
80,80,80,a1,80,80,80,80,80,80,80,80,80,80,80,80
|
||
|
80,80,80,a1,80,80,80,80,80,80,80,80,80,80,80,80
|
||
|
80,80,80,a1,80,80,80,80,80,80,80,80,80,80,80,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,u,18,31,y,z,10,3t,0,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 1 labour
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 18
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,s,0,w,1k,t,0,1c,10,y,11,1d,w,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1l,18,10,19,1d,1a,s,0,y,11,0,18,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,v,y,y,1c,t,10,18,w,1d,y,1a,6i,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,1a,0,w,1k,t,0,1b,y,10,u,1m,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,y,11,0,u,18,31,y,z,10,0,w,1k,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,t,0,t,1l,1c,u,y,x,t,t,0,1d,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,s,0,18,0,s,1l,18,u,u,0,18,1a,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 3 labour
|
||
|
PAL 0
|
||
|
|
||
|
ROOM a
|
||
|
b,g,c,a,a,a,b,e,a,c,a,c,a,b,c,a
|
||
|
c,0,0,0,0,0,c,0,a,0,a,c,0,a,0,f
|
||
|
e,b,a,a,c,0,0,0,a,0,a,0,0,0,0,b
|
||
|
c,c,c,c,b,c,a,0,0,0,0,0,a,0,e,e
|
||
|
a,0,c,0,e,e,c,c,a,0,c,0,0,0,0,a
|
||
|
c,0,0,0,c,a,c,d,0,0,b,0,a,b,0,a
|
||
|
a,0,a,0,0,0,0,d,a,0,a,0,a,c,0,c
|
||
|
c,0,a,b,0,a,a,d,a,0,a,0,0,c,0,e
|
||
|
e,e,b,a,a,c,c,d,c,0,a,b,0,a,0,e
|
||
|
e,c,0,0,0,0,0,d,b,0,e,b,c,a,0,b
|
||
|
c,0,c,a,a,0,a,d,e,0,0,0,0,a,0,a
|
||
|
a,0,b,e,0,0,c,d,c,0,a,0,a,c,0,c
|
||
|
a,0,0,0,0,a,a,d,a,0,a,0,b,b,0,c
|
||
|
b,c,a,c,0,0,c,d,a,0,a,c,c,a,0,a
|
||
|
h,0,0,0,0,c,b,d,c,0,0,0,d,c,0,a
|
||
|
e,c,c,a,a,a,e,e,c,c,c,a,e,b,i,c
|
||
|
NAME Now
|
||
|
EXT 14,15 b 2,11 FX wave DLG n
|
||
|
PAL 0
|
||
|
|
||
|
ROOM c
|
||
|
ai,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,aj
|
||
|
ae,0,0,0,0,0,0,0,0,0,0,0,0,0,0,af
|
||
|
ae,0,0,18,10,t,0,x,y,z,0,1d,1a,0,0,af
|
||
|
ae,0,0,1y,1y,1y,1y,1y,1y,1y,1y,1y,1y,0,0,af
|
||
|
ae,0,s,t,18,10,v,1k,0,y,11,0,0,0,0,af
|
||
|
ae,0,1y,1y,1y,1y,1y,1y,1y,1y,1y,0,0,0,0,af
|
||
|
ae,0,0,0,18,0,0,0,0,0,0,0,0,0,0,af
|
||
|
ae,0,0,0,1y,0,0,0,0,0,0,0,0,0,0,af
|
||
|
ae,0,0,0,0,0,10,18,1a,1m,y,1l,0,0,0,af
|
||
|
ae,0,0,0,0,0,1y,1y,1y,1y,1y,1y,0,0,0,af
|
||
|
ae,0,0,t,17,0,0,0,0,0,0,0,0,0,0,af
|
||
|
ae,0,0,1y,1y,1d,0,0,0,0,0,0,0,0,0,af
|
||
|
ae,0,0,0,0,1y,0,w,0,1n,0,0,0,0,0,af
|
||
|
ae,0,0,0,0,0,0,1y,0,0,0,0,0,0,0,af
|
||
|
ae,0,0,0,0,0,0,0,0,0,0,0,0,0,r,af
|
||
|
ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad,ad
|
||
|
NAME main time
|
||
|
PAL 0
|
||
|
|
||
|
ROOM f
|
||
|
1q,1x,0,21,18,1a,z,18,10,x,0,k,l,k,20,0
|
||
|
1y,1z,1y,1y,1y,1y,1y,1y,1y,1y,1y,1y,1y,1y,1y,1y
|
||
|
1l,1x,0,0,0,m,0,o,k,0,o,12,0,k,20,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
w,1x,0,0,0,20,0,o,q,0,k,l,0,k,n,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
1b,1x,0,0,0,n,0,o,13,0,k,o,0,k,p,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
w,1x,o,0,0,p,0,o,m,0,k,k,0,k,12,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
11,1x,k,0,0,12,0,o,20,0,k,q,0,q,l,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
s,1x,q,0,o,l,0,o,n,0,k,13,0,q,o,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
s,1x,13,0,o,o,0,o,p,0,k,m,0,0,0,0
|
||
|
0,1x,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
NAME future
|
||
|
PAL 0
|
||
|
|
||
|
ROOM h
|
||
|
1q,0,0,0,0,0,0,0,0,0,0,0,0,0,3k,3j
|
||
|
0,0,a6,a4,a4,a4,a4,a4,a4,a5,2w,2y,0,0,0,0
|
||
|
0,0,2n,1m,1d,s,10,z,1c,2r,2x,2w,2y,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,2r,0,2x,2w,0,0,0
|
||
|
0,0,2n,w,1d,30,t,0,1c,2v,a4,a4,a5,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,u,18,x,2z,v,18,1a,0,19,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,18,1l,1d,1a,19,0,31,t,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,18,0,s,z,31,30,t,10,s,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,1d,30,t,0,18,v,w,1n,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2o,2p,2p,2p,2p,2p,2p,2p,2p,2p,2q,0,0,0
|
||
|
32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,r
|
||
|
NAME ghost file 1
|
||
|
EXT 0,15 p 15,15 FX slide_l
|
||
|
PAL 0
|
||
|
|
||
|
ROOM j
|
||
|
1q,0,0,0,0,0,0,0,0,0,0,0,0,0,3m,3j
|
||
|
0,0,a6,a4,a4,a4,a4,a4,a4,a5,2w,2y,0,0,0,0
|
||
|
0,0,2n,y,s,1l,y,s,1d,2r,2x,2w,2y,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,2r,0,2x,2w,0,0,0
|
||
|
0,0,2n,s,0,y,11,0,0,2v,a4,a4,a5,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,w,1k,y,z,19,1k,w,s,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,r,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,3e,3e,3e,3e,36,3g,1r,3g,3h,2r,0,0,0
|
||
|
0,0,2n,3f,3e,3e,3f,36,3h,3h,3h,3h,2r,0,0,0
|
||
|
0,0,2n,3e,3e,3f,3e,36,1r,1r,3h,3h,2r,0,0,0
|
||
|
0,0,2n,3f,3e,3f,3e,36,3g,1r,3g,1r,2r,0,0,0
|
||
|
0,0,2o,2p,2p,2p,2p,2p,2p,2p,2p,2p,2q,0,0,0
|
||
|
32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,r
|
||
|
NAME ghost file 3
|
||
|
PAL 0
|
||
|
|
||
|
ROOM l
|
||
|
1q,0,0,0,0,0,0,0,0,0,0,0,0,0,3o,3j
|
||
|
0,0,a6,a4,a4,a4,a4,a4,a4,a5,2w,2y,0,0,0,0
|
||
|
0,0,2n,1c,1d,1a,19,2z,1c,2r,2x,2w,2y,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,2r,0,2x,2w,0,0,0
|
||
|
0,0,2n,y,1a,19,0,y,11,2v,a4,a4,a5,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,1d,1m,t,18,s,3t,0,0,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,3x,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,3x,0,3u,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,3x,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,3x,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2o,2p,2p,2p,2p,2p,2p,2p,2p,2p,2q,0,0,0
|
||
|
32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,r
|
||
|
NAME ghost file 5
|
||
|
PAL 0
|
||
|
|
||
|
ROOM n
|
||
|
1q,0,0,0,0,0,0,0,0,0,0,0,0,0,3q,3j
|
||
|
0,0,a6,a4,a4,a4,a4,a4,a4,a5,2w,2y,0,0,0,0
|
||
|
0,0,2n,w,y,0,1c,u,18,2r,2x,2w,2y,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,2r,0,2x,2w,0,0,0
|
||
|
0,0,2n,x,0,18,0,19,18,2v,a4,a4,a5,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,1l,t,0,1c,u,18,x,t,10,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,s,0,1a,t,t,1m,0,w,y,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,18,19,10,t,t,0,y,1a,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,w,1k,t,0,10,z,u,t,s,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,1y,1y,1y,1y,1y,2r,0,0,0
|
||
|
0,0,2o,2p,2p,2p,2p,2p,2p,2p,2p,2p,2q,0,0,0
|
||
|
32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,r
|
||
|
NAME ghost file 7
|
||
|
PAL 0
|
||
|
|
||
|
ROOM p
|
||
|
1q,0,0,0,0,0,0,0,0,0,0,0,0,0,3s,3j
|
||
|
0,0,a6,a4,a4,a4,a4,a4,a4,a5,2w,2y,0,0,0,0
|
||
|
0,0,2n,1k,y,1b,0,1l,18,2r,2x,2w,2y,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,2r,0,2x,2w,0,0,0
|
||
|
0,0,2n,1a,x,0,1a,t,t,2v,a4,a4,a5,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,1m,0,w,y,0,18,19,10,t,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,t,0,y,1a,0,18,1a,0,18,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,u,w,t,10,1a,18,w,t,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2n,10,t,18,u,1d,w,x,1n,0,2r,0,0,0
|
||
|
0,0,2n,0,0,0,0,0,0,0,0,0,2r,0,0,0
|
||
|
0,0,2o,2p,2p,2p,2p,2p,2p,2p,2p,2p,2q,0,0,0
|
||
|
32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,r
|
||
|
NAME ghost file 9
|
||
|
EXT 15,15 h 0,15 FX slide_r
|
||
|
PAL 0
|
||
|
|
||
|
ROOM s
|
||
|
47,1t,1t,1t,1t,1t,1t,1t,1t,1t,1t,48,1r,1r,1r,1r
|
||
|
1r,38,38,4a,49,55,1r,1r,1r,1r,1r,4b,5v,5y,0,0
|
||
|
1r,d,0,1r,55,1r,1r,59,54,1r,4d,4e,5u,5x,0,0
|
||
|
59,4h,4h,1r,4s,4t,4m,4z,4x,50,4f,4g,4c,5w,0,0
|
||
|
65,5n,5l,5m,4r,4u,4n,4y,53,4v,57,58,60,2p,2p,2p
|
||
|
64,1r,5k,5j,4q,4p,4o,52,4w,51,4d,4i,55,14,61,62
|
||
|
64,6v,6u,1r,1r,1r,1r,1r,1r,56,4j,4k,55,14,61,62
|
||
|
66,4d,6r,6t,1r,1r,1r,1r,65,1r,1r,1r,71,5z,2p,2p
|
||
|
6w,4f,6s,1r,d,1r,1r,1r,64,71,70,6y,70,14,0,62
|
||
|
6m,6x,6o,1r,6o,2s,6o,2s,64,2u,2t,6n,6z,14,63,62
|
||
|
47,6k,6l,1r,6p,6q,6p,6q,66,2n,0,48,1r,5z,2p,2p
|
||
|
68,67,67,69,67,6a,67,6b,0,6c,6d,6e,72,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,5h,5g
|
||
|
10,18,s,1c,31,t,10,10,x,0,1c,1d,0,0,5f,5i
|
||
|
NAME raspberry pi 2D
|
||
|
END 14 12,11
|
||
|
PAL 0
|
||
|
|
||
|
ROOM w
|
||
|
47,1t,1t,1t,1t,1t,1t,1t,1t,1t,1t,48,1r,1r,1r,1r
|
||
|
1r,38,38,4a,49,55,1r,1r,1r,1r,1r,4b,5v,5y,0,0
|
||
|
1r,d,0,1r,55,1r,1r,59,54,1r,4d,4e,5u,5x,0,0
|
||
|
59,4h,4h,1r,4s,4t,4m,4z,4x,50,4f,4g,4c,5w,0,0
|
||
|
65,5n,5l,5m,4r,4u,4n,4y,53,4v,57,58,60,2p,2p,2p
|
||
|
64,1r,5k,5j,4q,4p,4o,52,4w,51,4d,4i,55,14,61,62
|
||
|
64,6v,6u,1r,1r,1r,1r,1r,1r,56,4j,4k,55,14,61,62
|
||
|
66,4d,6r,6t,1r,1r,1r,1r,65,1r,1r,1r,71,5z,2p,2p
|
||
|
6w,4f,6s,1r,d,1r,1r,1r,64,71,70,6y,70,14,0,62
|
||
|
6m,6x,6o,1r,6o,2s,6o,2s,64,2u,2t,6n,6z,14,63,62
|
||
|
47,6k,6l,1r,6p,6q,6p,6q,66,2n,0,48,1r,5z,2p,2p
|
||
|
68,67,67,69,67,6a,67,6b,0,6c,6d,6e,0,0,0,0
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||
|
h,0,0,0,0,0,0,0,0,0,0,0,0,0,0,f
|
||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,5h,5g
|
||
|
10,18,s,1c,31,t,10,10,x,0,1c,1d,0,0,5f,5i
|
||
|
NAME raspberry pi 3D
|
||
|
ITM c 6,0
|
||
|
ITM 9 5,4
|
||
|
ITM a 8,4
|
||
|
ITM b 1,2
|
||
|
ITM d 14,2
|
||
|
ITM e 14,9
|
||
|
ITM f 10,10
|
||
|
ITM g 8,9
|
||
|
ITM h 4,10
|
||
|
ITM h 6,10
|
||
|
ITM i 1,10
|
||
|
ITM j 0,3
|
||
|
ITM k 14,6
|
||
|
ITM l 11,1
|
||
|
ITM m 0,6
|
||
|
END 13 15,13
|
||
|
END 13 0,13
|
||
|
PAL 0
|
||
|
|
||
|
ROOM y
|
||
|
2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l
|
||
|
2f,7w,7w,7w,7w,7w,7w,7w,7w,7w,7w,7w,7w,7w,7w,7t
|
||
|
7v,7s,0,7m,74,79,7c,7e,7i,7j,0,0,0,0,0,7u
|
||
|
7v,7r,7q,7n,75,78,7a,7d,7g,7l,0,0,0,0,0,7u
|
||
|
7v,0,7p,7o,76,77,7b,7f,7h,7k,0,0,0,0,0,7u
|
||
|
7v,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7u
|
||
|
7v,0,0,0,y,10,0,u,18,31,y,z,10,1n,0,7u
|
||
|
7v,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7u
|
||
|
2g,39,39,39,39,39,39,39,39,39,39,39,39,39,39,7x
|
||
|
2i,2i,2i,2i,2i,2i,2i,2i,2i,2i,2i,2i,2i,2i,2i,2i
|
||
|
2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l,2l
|
||
|
2f,38,38,38,38,38,38,38,38,38,38,38,38,38,38,7t
|
||
|
3a,31,0,31,0,31,31,31,31,0,31,31,31,31,31,7u
|
||
|
3a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7u
|
||
|
3a,31,31,31,31,31,31,31,0,31,31,31,31,31,0,7u
|
||
|
3a,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7u
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1a
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1c,z,10,1c,y,s,t,6i,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,46,0,0,80
|
||
|
81,81,81,81,81,81,81,81,81,81,81,81,a2,81,81,80
|
||
|
80,80,80,80,80,80,80,80,80,80,80,80,a1,80,80,80
|
||
|
80,0,0,0,0,0,0,0,80,80,80,80,a1,80,80,80
|
||
|
80,0,1b,y,10,35,3t,0,80,80,80,80,a1,80,80,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1b,y,10,35,0,1d,s,0,18,0,1c,10,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,y,v,t,s,s,0,1b,1k,t,10,t,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,w,1k,t,0,1d,1a,1m,1d,30,1d,1m,z,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,18,u,0,1l,1d,1a,1m,0,18,1a,1m,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 5 labour
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1c
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,1m,0,1m,1d,10,t,v,w,u,x,6i,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,1a,s,w,t,18,1m,0,w,1k,t,x,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,s,t,u,u,0,w,1k,t,0,1c,10,y,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1m,z,v,w,0,y,11,0,w,1k,t,1d,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,10,0,1b,y,10,35,6i,0,0,46,0,46,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,81,a2,81,a2,81,80
|
||
|
80,0,0,0,0,0,0,0,0,0,80,a1,80,a1,80,80
|
||
|
81,81,81,81,81,81,81,81,81,81,80,a1,80,a1,80,80
|
||
|
80,80,80,80,80,80,80,80,80,80,80,a1,80,0,0,0
|
||
|
80,80,80,80,80,80,80,80,80,80,80,a1,80,80,80,80
|
||
|
80,80,80,80,80,80,80,80,80,80,80,a1,80,80,80,80
|
||
|
NAME 7 labour
|
||
|
EXT 15,13 1d 1,0
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1e
|
||
|
80,80,80,80,80,80,80,80,80,80,80,80,a1,80,80,80
|
||
|
80,80,0,0,0,0,0,0,0,0,0,0,a1,80,80,80
|
||
|
80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1c,u,18,x,0,1d,s,0,1a,y,0,u,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,y,1a,19,t,10,0,18,0,v,y,z,1a,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,w,t,10,0,w,y,0,1b,y,10,35,6i,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1c,u,18,x,0,31,t,v,y,1l,t,s,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1b,y,10,35,6i,0,1b,y,10,35,0,31,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,t,v,y,1l,t,s,0,1c,u,18,x,6i,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 2 work
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1g
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,t,s,s,0,18,1a,1m,0,1a,y,w,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,11,y,10,0,w,1k,t,0,11,z,u,11,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,u,u,1l,t,1a,w,0,y,11,0,w,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1k,t,0,1b,y,10,35,t,10,s,6i,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1b,y,10,35,0,w,1k,18,w,0,1d,s,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,w,18,10,1a,t,1m,0,18,s,0,18,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,19,18,1l,t,0,1d,s,0,s,w,1d,u,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 4 work
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1i
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,z,10,t,0,y,11,0,1m,y,1l,1d,1a,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,18,w,1d,y,1a,0,s,1d,1l,1d,u,18,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,10,0,w,y,0,1b,1k,18,w,0,1b,t,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,11,1d,1a,1m,0,1d,1a,0,w,1k,t,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,10,t,18,u,0,1b,y,10,u,1m,6i,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,31,z,w,0,w,1k,t,x,0,v,10,t,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,18,w,t,0,18,0,s,18,11,t,0,s,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 6 work
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1k
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,10,y,z,s,0,18,1a,1m,0,10,t,1d,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1a,11,y,10,v,t,s,0,18,0,30,1d,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,s,1d,y,1a,0,y,11,0,18,0,1b,y,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,10,u,1m,0,t,1a,w,1d,10,t,u,x,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,19,10,y,z,1a,1m,t,1m,0,1d,1a,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,v,y,1l,1c,t,w,1d,w,1d,y,1a,6i,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,46,0,46,0,81,81,81,81,81,81,81,81,81,80
|
||
|
80,81,a2,81,a2,81,80,80,80,80,80,80,80,80,80,80
|
||
|
80,80,a1,80,a1,80,80,80,80,80,80,80,80,80,80,80
|
||
|
NAME 8 work
|
||
|
EXT 4,13 1l 4,0
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1m
|
||
|
80,80,80,80,80,80,80,80,80,80,80,80,80,80,a1,80
|
||
|
80,80,80,80,0,0,0,0,0,0,0,0,0,0,a1,80
|
||
|
80,80,80,80,a1,80,80,80,80,80,80,80,80,80,80,80
|
||
|
80,80,80,80,0,0,0,a1,80,80,80,80,80,80,80,80
|
||
|
80,80,80,80,80,80,80,a1,80,80,80,80,80,80,80,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,w,1k,t,0,w,t,10,1l,s,0,19,18,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1l,t,0,18,1a,1m,0,1c,u,18,x,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,18,10,t,0,w,1b,y,0,s,t,1c,18,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,10,18,w,t,0,1d,1m,t,18,s,0,1b,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,w,1k,0,10,t,u,18,w,t,1m,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 2 game
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1o
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,1a,0,11,y,10,1l,0,y,11,0,1c,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,u,18,x,6i,0,31,z,w,0,18,u,s,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,y,0,w,1k,t,0,10,t,30,t,10,s,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,t,0,1d,s,0,w,10,z,t,3t,0,19,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,18,1l,t,0,1d,s,0,w,1k,t,0,31,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1d,19,19,t,10,0,w,t,10,1l,0,18,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,1a,1m,0,1d,1a,v,u,z,1m,t,s,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,46,80
|
||
|
NAME 4 game
|
||
|
PAL 0
|
||
|
|
||
|
ROOM 1q
|
||
|
80,80,a1,80,80,80,a1,80,80,80,80,80,80,80,80,80
|
||
|
80,80,a1,80,80,80,a1,80,80,80,80,80,80,80,80,80
|
||
|
80,80,a1,80,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,80,a1,80,0,86,87,8a,0,8e,8f,8i,8l,0,0,80
|
||
|
80,0,0,0,0,83,84,88,0,8c,8g,8j,8m,0,0,80
|
||
|
80,0,y,10,0,85,0,89,8b,8d,8h,8k,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,8a,0,8z,94,96,98,9b,9e,9j,7c,7e,8z,94,80
|
||
|
80,0,88,0,90,93,95,99,9c,9f,9i,7a,7d,90,93,80
|
||
|
80,0,89,8b,91,92,97,9a,9d,9g,9h,7b,7f,91,92,80
|
||
|
80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80
|
||
|
80,0,0,0,0,0,0,0,0,0,46,0,0,0,0,80
|
||
|
80,81,81,81,81,81,81,81,81,81,a2,81,81,81,81,80
|
||
|
80,80,80,80,80,80,80,80,80,80,a1,80,80,80,80,80
|
||
|
80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0
|
||
|
80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80
|
||
|
NAME 6 game
|
||
|
PAL 0
|
||
|
|
||
|
TIL 10
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111100
|
||
|
01101100
|
||
|
01100110
|
||
|
01100110
|
||
|
NAME R
|
||
|
|
||
|
TIL 11
|
||
|
01111110
|
||
|
01111100
|
||
|
01100000
|
||
|
01111000
|
||
|
01110000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME F
|
||
|
|
||
|
TIL 12
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
00011110
|
||
|
00000110
|
||
|
01100110
|
||
|
01111110
|
||
|
NAME 9
|
||
|
|
||
|
TIL 13
|
||
|
00111000
|
||
|
01110000
|
||
|
01100000
|
||
|
01101100
|
||
|
01111110
|
||
|
01111110
|
||
|
00001100
|
||
|
00001100
|
||
|
NAME 4
|
||
|
|
||
|
TIL 14
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
NAME I
|
||
|
|
||
|
TIL 15
|
||
|
11110000
|
||
|
11010000
|
||
|
11010000
|
||
|
11010000
|
||
|
11010000
|
||
|
11010000
|
||
|
11010000
|
||
|
11110000
|
||
|
NAME II
|
||
|
|
||
|
TIL 16
|
||
|
11111100
|
||
|
11010100
|
||
|
11010100
|
||
|
11010100
|
||
|
11010100
|
||
|
11010100
|
||
|
11010100
|
||
|
11111100
|
||
|
NAME III
|
||
|
|
||
|
TIL 17
|
||
|
01100110
|
||
|
01110110
|
||
|
00111100
|
||
|
00011000
|
||
|
00011100
|
||
|
00111110
|
||
|
01101110
|
||
|
01100110
|
||
|
NAME X
|
||
|
|
||
|
TIL 18
|
||
|
00111100
|
||
|
01101110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
NAME A
|
||
|
|
||
|
TIL 19
|
||
|
00111110
|
||
|
01100110
|
||
|
01100000
|
||
|
01100000
|
||
|
01101110
|
||
|
01100110
|
||
|
01100110
|
||
|
00111110
|
||
|
NAME G
|
||
|
|
||
|
TIL 20
|
||
|
01111110
|
||
|
01100110
|
||
|
01100000
|
||
|
01111000
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
|
||
|
TIL 21
|
||
|
01111110
|
||
|
01111110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
01100110
|
||
|
01101110
|
||
|
01111100
|
||
|
|
||
|
TIL 22
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
11111000
|
||
|
11111000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
>
|
||
|
10101011
|
||
|
10101000
|
||
|
10101011
|
||
|
10100000
|
||
|
00001111
|
||
|
00000000
|
||
|
00001111
|
||
|
00000000
|
||
|
|
||
|
TIL 23
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000111
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
>
|
||
|
00101010
|
||
|
00101010
|
||
|
00101010
|
||
|
00000010
|
||
|
00111000
|
||
|
00000000
|
||
|
00111100
|
||
|
00000000
|
||
|
|
||
|
TIL 24
|
||
|
00000111
|
||
|
00000111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00111100
|
||
|
00000000
|
||
|
00111010
|
||
|
00000010
|
||
|
00111010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 25
|
||
|
11111000
|
||
|
11111000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00001111
|
||
|
10100000
|
||
|
10101011
|
||
|
10101000
|
||
|
10101011
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 26
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
>
|
||
|
00111100
|
||
|
00000000
|
||
|
00111100
|
||
|
00000000
|
||
|
00111100
|
||
|
00000000
|
||
|
00111100
|
||
|
00000000
|
||
|
|
||
|
TIL 27
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
>
|
||
|
00001111
|
||
|
00000000
|
||
|
00001111
|
||
|
00000000
|
||
|
00001111
|
||
|
00000000
|
||
|
00001111
|
||
|
00000000
|
||
|
|
||
|
TIL 28
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 29
|
||
|
11111111
|
||
|
10001000
|
||
|
10001000
|
||
|
10001000
|
||
|
11111111
|
||
|
10001000
|
||
|
10001000
|
||
|
10001000
|
||
|
>
|
||
|
00000000
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 30
|
||
|
01100100
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01110110
|
||
|
00111100
|
||
|
00011000
|
||
|
|
||
|
TIL 31
|
||
|
01111100
|
||
|
01101110
|
||
|
01100110
|
||
|
01101100
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
NAME B
|
||
|
|
||
|
TIL 32
|
||
|
00000000
|
||
|
00011000
|
||
|
00110000
|
||
|
01111110
|
||
|
01111110
|
||
|
00110000
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00001100
|
||
|
00011000
|
||
|
00111111
|
||
|
00111111
|
||
|
00011000
|
||
|
00001100
|
||
|
00000000
|
||
|
|
||
|
TIL 33
|
||
|
00010000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
NAME !
|
||
|
|
||
|
TIL 34
|
||
|
00001000
|
||
|
00001000
|
||
|
00010000
|
||
|
00010000
|
||
|
00100000
|
||
|
00100000
|
||
|
01000000
|
||
|
01000000
|
||
|
|
||
|
TIL 35
|
||
|
01100110
|
||
|
01100110
|
||
|
01101110
|
||
|
01111100
|
||
|
01111000
|
||
|
01101100
|
||
|
01101110
|
||
|
01100110
|
||
|
|
||
|
TIL 36
|
||
|
11110111
|
||
|
11101011
|
||
|
11110111
|
||
|
11101011
|
||
|
11110111
|
||
|
11101011
|
||
|
11110111
|
||
|
11101011
|
||
|
|
||
|
TIL 37
|
||
|
11111111
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
|
||
|
TIL 38
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 39
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
|
||
|
TIL 40
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000001
|
||
|
|
||
|
TIL 41
|
||
|
11111111
|
||
|
11000111
|
||
|
11011111
|
||
|
11000111
|
||
|
11010111
|
||
|
11000111
|
||
|
11111111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11111111
|
||
|
11100011
|
||
|
11111011
|
||
|
11100011
|
||
|
11111011
|
||
|
11100011
|
||
|
11111111
|
||
|
|
||
|
TIL 42
|
||
|
11111111
|
||
|
11000111
|
||
|
11011111
|
||
|
11000111
|
||
|
11110111
|
||
|
11000111
|
||
|
11111111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11111111
|
||
|
11100011
|
||
|
11111011
|
||
|
11100011
|
||
|
11101111
|
||
|
11100011
|
||
|
11111111
|
||
|
|
||
|
TIL 43
|
||
|
11111111
|
||
|
11000111
|
||
|
11010111
|
||
|
11000111
|
||
|
11110111
|
||
|
11000111
|
||
|
11111111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11101111
|
||
|
11101111
|
||
|
11101111
|
||
|
11101111
|
||
|
11101111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 44
|
||
|
11111111
|
||
|
11000111
|
||
|
11010111
|
||
|
11000111
|
||
|
11010111
|
||
|
11000111
|
||
|
11111111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11000111
|
||
|
11010111
|
||
|
11010111
|
||
|
11010111
|
||
|
11000111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 46
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 47
|
||
|
11111110
|
||
|
11000110
|
||
|
10000010
|
||
|
10010010
|
||
|
10000010
|
||
|
11000110
|
||
|
11111110
|
||
|
11111110
|
||
|
|
||
|
TIL 48
|
||
|
01111111
|
||
|
01100011
|
||
|
01000001
|
||
|
01001001
|
||
|
01000001
|
||
|
01100011
|
||
|
01111111
|
||
|
01111111
|
||
|
|
||
|
TIL 49
|
||
|
11111111
|
||
|
00000001
|
||
|
11111101
|
||
|
11111101
|
||
|
11111101
|
||
|
00000001
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 50
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 51
|
||
|
00011111
|
||
|
00000111
|
||
|
00000111
|
||
|
00000111
|
||
|
00000111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 52
|
||
|
00000101
|
||
|
00000101
|
||
|
00000101
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 53
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
|
||
|
TIL 54
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111000
|
||
|
01010000
|
||
|
11111111
|
||
|
|
||
|
TIL 55
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
10111111
|
||
|
11111111
|
||
|
|
||
|
TIL 56
|
||
|
11111101
|
||
|
11111111
|
||
|
11111101
|
||
|
11111111
|
||
|
11111101
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 57
|
||
|
11110100
|
||
|
11110100
|
||
|
11111100
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 58
|
||
|
10100111
|
||
|
10100111
|
||
|
10100111
|
||
|
11100111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 59
|
||
|
11111111
|
||
|
11111111
|
||
|
10101111
|
||
|
11111111
|
||
|
01111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 60
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 61
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01100000
|
||
|
01100000
|
||
|
00000000
|
||
|
|
||
|
TIL 62
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000110
|
||
|
00000011
|
||
|
00000011
|
||
|
00000110
|
||
|
|
||
|
TIL 63
|
||
|
10000000
|
||
|
10000000
|
||
|
10000000
|
||
|
10000000
|
||
|
10000000
|
||
|
10000000
|
||
|
10000000
|
||
|
00000000
|
||
|
|
||
|
TIL 64
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
|
||
|
TIL 65
|
||
|
00000111
|
||
|
10100111
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
|
||
|
TIL 66
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100000
|
||
|
00100011
|
||
|
10100011
|
||
|
|
||
|
TIL 67
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 68
|
||
|
00000010
|
||
|
00000010
|
||
|
00000010
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 69
|
||
|
10000001
|
||
|
10000001
|
||
|
10000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL 70
|
||
|
10001001
|
||
|
10001001
|
||
|
10001001
|
||
|
11111111
|
||
|
11110101
|
||
|
11100000
|
||
|
11100000
|
||
|
11110101
|
||
|
|
||
|
TIL 71
|
||
|
11111111
|
||
|
11110000
|
||
|
11110000
|
||
|
11111111
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11111111
|
||
|
|
||
|
TIL 72
|
||
|
00000000
|
||
|
00000000
|
||
|
00011000
|
||
|
00111100
|
||
|
01111110
|
||
|
01011010
|
||
|
00011000
|
||
|
00011000
|
||
|
>
|
||
|
00000000
|
||
|
00011000
|
||
|
00111100
|
||
|
01111110
|
||
|
01011010
|
||
|
00011000
|
||
|
00011000
|
||
|
00000000
|
||
|
|
||
|
TIL 73
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME black wall
|
||
|
WAL true
|
||
|
|
||
|
TIL 74
|
||
|
00001111
|
||
|
00011111
|
||
|
00011100
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
11100000
|
||
|
11100000
|
||
|
NAME O-1
|
||
|
|
||
|
TIL 75
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME O-2
|
||
|
|
||
|
TIL 76
|
||
|
01110001
|
||
|
00111111
|
||
|
00011110
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME O-3
|
||
|
|
||
|
TIL 77
|
||
|
11110000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME O-4
|
||
|
|
||
|
TIL 78
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00111000
|
||
|
00111000
|
||
|
00110000
|
||
|
00110000
|
||
|
NAME O-5
|
||
|
|
||
|
TIL 79
|
||
|
11000000
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
NAME O-6
|
||
|
|
||
|
TIL 80
|
||
|
01010101
|
||
|
11111111
|
||
|
01010101
|
||
|
11111111
|
||
|
01010101
|
||
|
11111111
|
||
|
01010101
|
||
|
11111111
|
||
|
>
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
WAL true
|
||
|
|
||
|
TIL 81
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
11111111
|
||
|
01010101
|
||
|
11111111
|
||
|
>
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
WAL true
|
||
|
|
||
|
TIL 82
|
||
|
00011111
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
|
||
|
TIL 83
|
||
|
11100000
|
||
|
11100001
|
||
|
01111111
|
||
|
01111110
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
NAME P-1
|
||
|
|
||
|
TIL 84
|
||
|
01100000
|
||
|
11100000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME P-2
|
||
|
|
||
|
TIL 85
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME P-3
|
||
|
|
||
|
TIL 86
|
||
|
01111111
|
||
|
01111111
|
||
|
11100111
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
NAME P-4
|
||
|
|
||
|
TIL 87
|
||
|
00000000
|
||
|
11000000
|
||
|
11110000
|
||
|
11110000
|
||
|
00110000
|
||
|
00110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME P-5
|
||
|
|
||
|
TIL 88
|
||
|
01110000
|
||
|
01110000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
NAME L-1
|
||
|
|
||
|
TIL 89
|
||
|
11100000
|
||
|
11100000
|
||
|
01111000
|
||
|
01111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME L-2
|
||
|
|
||
|
TIL 90
|
||
|
00110000
|
||
|
00110001
|
||
|
00111111
|
||
|
00111110
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
NAME E-2
|
||
|
|
||
|
TIL 91
|
||
|
00111000
|
||
|
00111000
|
||
|
00111111
|
||
|
00011111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME E-3
|
||
|
|
||
|
TIL 92
|
||
|
00110000
|
||
|
01110000
|
||
|
11110000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME E-4
|
||
|
|
||
|
TIL 93
|
||
|
00000000
|
||
|
11100000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME E-5
|
||
|
|
||
|
TIL 94
|
||
|
11100000
|
||
|
11110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME E-6
|
||
|
|
||
|
TIL 95
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
NAME I-1
|
||
|
|
||
|
TIL 96
|
||
|
00011100
|
||
|
00011100
|
||
|
00011110
|
||
|
00011110
|
||
|
00001110
|
||
|
00001110
|
||
|
00001110
|
||
|
00011100
|
||
|
NAME I-2
|
||
|
|
||
|
TIL 97
|
||
|
00111000
|
||
|
00111100
|
||
|
00111100
|
||
|
00011100
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME I-3
|
||
|
|
||
|
TIL 98
|
||
|
00000011
|
||
|
00000011
|
||
|
00000110
|
||
|
00000110
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
NAME S-1
|
||
|
|
||
|
TIL 99
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00000011
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME S-2
|
||
|
|
||
|
TIL a
|
||
|
10011001
|
||
|
10100000
|
||
|
00000110
|
||
|
10010001
|
||
|
00100110
|
||
|
10001001
|
||
|
00100000
|
||
|
10010101
|
||
|
>
|
||
|
10011001
|
||
|
10100000
|
||
|
00000110
|
||
|
10010001
|
||
|
00100110
|
||
|
10001001
|
||
|
00100000
|
||
|
10010101
|
||
|
WAL true
|
||
|
|
||
|
TIL b
|
||
|
11110111
|
||
|
10101011
|
||
|
11111111
|
||
|
10101101
|
||
|
11110111
|
||
|
01011101
|
||
|
11110111
|
||
|
10111111
|
||
|
NAME tile 3
|
||
|
WAL true
|
||
|
|
||
|
TIL c
|
||
|
11100111
|
||
|
00011011
|
||
|
10100001
|
||
|
11110100
|
||
|
01100111
|
||
|
11011100
|
||
|
01010111
|
||
|
01101101
|
||
|
NAME tile 2
|
||
|
WAL true
|
||
|
|
||
|
TIL d
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME black
|
||
|
WAL false
|
||
|
|
||
|
TIL e
|
||
|
11111110
|
||
|
01101111
|
||
|
11111111
|
||
|
11111101
|
||
|
11111111
|
||
|
11011101
|
||
|
11110111
|
||
|
11111111
|
||
|
NAME tile 4
|
||
|
WAL true
|
||
|
|
||
|
TIL f
|
||
|
00000111
|
||
|
00000011
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000001
|
||
|
00000011
|
||
|
00000111
|
||
|
NAME door right
|
||
|
|
||
|
TIL g
|
||
|
11100111
|
||
|
11000011
|
||
|
10000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME door top
|
||
|
|
||
|
TIL h
|
||
|
11100000
|
||
|
11000000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
10000000
|
||
|
11000000
|
||
|
11100000
|
||
|
NAME door left
|
||
|
|
||
|
TIL i
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
NAME door bottom
|
||
|
|
||
|
TIL j
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME question mark
|
||
|
|
||
|
TIL k
|
||
|
00111110
|
||
|
01100110
|
||
|
01100110
|
||
|
00001110
|
||
|
00111100
|
||
|
01110000
|
||
|
01100110
|
||
|
01111110
|
||
|
NAME 2
|
||
|
|
||
|
TIL l
|
||
|
00111100
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
00111100
|
||
|
NAME 0
|
||
|
|
||
|
TIL m
|
||
|
01111110
|
||
|
01111110
|
||
|
01100000
|
||
|
01111100
|
||
|
00001110
|
||
|
00000110
|
||
|
01111110
|
||
|
01111100
|
||
|
NAME 5
|
||
|
|
||
|
TIL n
|
||
|
01111110
|
||
|
01111110
|
||
|
00001110
|
||
|
00011100
|
||
|
00111000
|
||
|
00110000
|
||
|
00110000
|
||
|
00110000
|
||
|
NAME 7
|
||
|
|
||
|
TIL o
|
||
|
00011100
|
||
|
00111100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
NAME 1
|
||
|
|
||
|
TIL p
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
00111100
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
NAME 8
|
||
|
|
||
|
TIL q
|
||
|
01111110
|
||
|
01111110
|
||
|
00000110
|
||
|
00011100
|
||
|
00011100
|
||
|
00000110
|
||
|
01111110
|
||
|
01111110
|
||
|
NAME 3
|
||
|
|
||
|
TIL r
|
||
|
00000000
|
||
|
00011000
|
||
|
00001100
|
||
|
01111110
|
||
|
01111110
|
||
|
00001100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00110000
|
||
|
00011000
|
||
|
11111100
|
||
|
11111100
|
||
|
00011000
|
||
|
00110000
|
||
|
00000000
|
||
|
NAME arrow
|
||
|
|
||
|
TIL s
|
||
|
01111110
|
||
|
01100110
|
||
|
01100000
|
||
|
01111110
|
||
|
00000110
|
||
|
00000110
|
||
|
01101110
|
||
|
01111110
|
||
|
NAME S
|
||
|
|
||
|
TIL t
|
||
|
01111110
|
||
|
01111100
|
||
|
01100000
|
||
|
01111000
|
||
|
01110000
|
||
|
01100000
|
||
|
01111110
|
||
|
01111110
|
||
|
NAME E
|
||
|
|
||
|
TIL u
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100010
|
||
|
01100110
|
||
|
01111110
|
||
|
NAME L
|
||
|
|
||
|
TIL v
|
||
|
01111110
|
||
|
01000110
|
||
|
01000000
|
||
|
01100000
|
||
|
01111000
|
||
|
01111010
|
||
|
01111010
|
||
|
01111110
|
||
|
NAME C
|
||
|
|
||
|
TIL w
|
||
|
01111110
|
||
|
01111110
|
||
|
01011010
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
NAME T
|
||
|
|
||
|
TIL x
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
00111100
|
||
|
00011000
|
||
|
01111000
|
||
|
01110000
|
||
|
NAME Y
|
||
|
|
||
|
TIL y
|
||
|
00111100
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
00111100
|
||
|
NAME O
|
||
|
|
||
|
TIL z
|
||
|
01100100
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
00111100
|
||
|
NAME U
|
||
|
|
||
|
TIL 1a
|
||
|
01100110
|
||
|
01100110
|
||
|
01110110
|
||
|
01110110
|
||
|
01111110
|
||
|
01101110
|
||
|
01101110
|
||
|
01100110
|
||
|
NAME N
|
||
|
|
||
|
TIL 1b
|
||
|
01100010
|
||
|
01100010
|
||
|
01100010
|
||
|
01100010
|
||
|
01101010
|
||
|
01101010
|
||
|
01111110
|
||
|
01111110
|
||
|
NAME W
|
||
|
|
||
|
TIL 1c
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01101110
|
||
|
01111100
|
||
|
01110000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME P
|
||
|
|
||
|
TIL 1d
|
||
|
00111100
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00111100
|
||
|
NAME i
|
||
|
|
||
|
TIL 1e
|
||
|
00000000
|
||
|
00100000
|
||
|
01110000
|
||
|
00100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
01110000
|
||
|
01000000
|
||
|
01000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 1f
|
||
|
00000000
|
||
|
00000100
|
||
|
00001110
|
||
|
00000100
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00001110
|
||
|
00000010
|
||
|
00000010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 1g
|
||
|
00000000
|
||
|
00000000
|
||
|
00010000
|
||
|
00111000
|
||
|
00010000
|
||
|
00000100
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00001000
|
||
|
00011100
|
||
|
00001000
|
||
|
01000000
|
||
|
00000000
|
||
|
|
||
|
TIL 1h
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00100000
|
||
|
01110000
|
||
|
00100000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01110000
|
||
|
00000000
|
||
|
|
||
|
TIL 1i
|
||
|
00000000
|
||
|
10101010
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 1j
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01101101
|
||
|
01101101
|
||
|
|
||
|
TIL 1k
|
||
|
01100100
|
||
|
01100110
|
||
|
01100110
|
||
|
01111110
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
NAME H
|
||
|
|
||
|
TIL 1l
|
||
|
01111110
|
||
|
01111110
|
||
|
01101010
|
||
|
01101010
|
||
|
01101010
|
||
|
01101010
|
||
|
01101010
|
||
|
01101010
|
||
|
NAME M
|
||
|
|
||
|
TIL 1m
|
||
|
01111100
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01101110
|
||
|
01111100
|
||
|
01111000
|
||
|
NAME D
|
||
|
|
||
|
TIL 1n
|
||
|
01111100
|
||
|
01111100
|
||
|
00001100
|
||
|
00111100
|
||
|
00110000
|
||
|
00000000
|
||
|
00110000
|
||
|
00110000
|
||
|
NAME ?
|
||
|
|
||
|
TIL 1o
|
||
|
10101011
|
||
|
01010101
|
||
|
10101010
|
||
|
01010111
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
>
|
||
|
10101011
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
11101010
|
||
|
01010101
|
||
|
|
||
|
TIL 1p
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
|
||
|
TIL 1q
|
||
|
00000000
|
||
|
01010000
|
||
|
00100000
|
||
|
01010000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 1r
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
NAME green
|
||
|
|
||
|
TIL 1s
|
||
|
10011001
|
||
|
11000011
|
||
|
10000001
|
||
|
01011010
|
||
|
00100100
|
||
|
10100101
|
||
|
10011001
|
||
|
11000011
|
||
|
NAME raspberry
|
||
|
|
||
|
TIL 1t
|
||
|
00000000
|
||
|
01100110
|
||
|
01100110
|
||
|
00000000
|
||
|
01100110
|
||
|
01100110
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME GPIO pins
|
||
|
|
||
|
TIL 1u
|
||
|
00000000
|
||
|
00100010
|
||
|
01110000
|
||
|
00100100
|
||
|
00001110
|
||
|
00000100
|
||
|
01000000
|
||
|
00010000
|
||
|
>
|
||
|
00010000
|
||
|
01000000
|
||
|
11100010
|
||
|
01000000
|
||
|
00001000
|
||
|
00011100
|
||
|
00001000
|
||
|
00000000
|
||
|
|
||
|
TIL 1v
|
||
|
11111100
|
||
|
10001100
|
||
|
10000100
|
||
|
10000100
|
||
|
10000100
|
||
|
10000100
|
||
|
10000100
|
||
|
11111100
|
||
|
|
||
|
TIL 1w
|
||
|
01111100
|
||
|
00000011
|
||
|
01111001
|
||
|
10000101
|
||
|
10000101
|
||
|
10011001
|
||
|
11000010
|
||
|
00111110
|
||
|
>
|
||
|
00111110
|
||
|
00000010
|
||
|
11111001
|
||
|
10000101
|
||
|
10100101
|
||
|
10011001
|
||
|
01000011
|
||
|
01111100
|
||
|
NAME spiral
|
||
|
|
||
|
TIL 1x
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
|
||
|
TIL 1y
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 1z
|
||
|
00001000
|
||
|
00001000
|
||
|
11111111
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
|
||
|
TIL 2a
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00000000
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 2b
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
>
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
|
||
|
TIL 2c
|
||
|
00001100
|
||
|
00001100
|
||
|
11111111
|
||
|
11111111
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
>
|
||
|
00001100
|
||
|
00000000
|
||
|
10100001
|
||
|
10100001
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
|
||
|
TIL 2d
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00111000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00111000
|
||
|
00000000
|
||
|
|
||
|
TIL 2e
|
||
|
11110000
|
||
|
00011000
|
||
|
00010100
|
||
|
00010010
|
||
|
00011111
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
|
||
|
TIL 2f
|
||
|
00011111
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
|
||
|
TIL 2g
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00011111
|
||
|
|
||
|
TIL 2h
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
11111111
|
||
|
|
||
|
TIL 2i
|
||
|
00000000
|
||
|
00000000
|
||
|
10101010
|
||
|
01010111
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
>
|
||
|
00000000
|
||
|
00000000
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
11101010
|
||
|
01010101
|
||
|
|
||
|
TIL 2j
|
||
|
00001011
|
||
|
00010101
|
||
|
00001010
|
||
|
00010111
|
||
|
00001010
|
||
|
00010101
|
||
|
00001010
|
||
|
00010101
|
||
|
>
|
||
|
00001011
|
||
|
00010101
|
||
|
00001010
|
||
|
00010101
|
||
|
00001010
|
||
|
00010101
|
||
|
00001010
|
||
|
00010101
|
||
|
|
||
|
TIL 2k
|
||
|
00001011
|
||
|
00010101
|
||
|
10101010
|
||
|
01010111
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
>
|
||
|
00001011
|
||
|
00010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
11101010
|
||
|
01010101
|
||
|
|
||
|
TIL 2l
|
||
|
10101011
|
||
|
01010101
|
||
|
10101010
|
||
|
01010111
|
||
|
10101010
|
||
|
01010101
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
10101011
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 2m
|
||
|
10101011
|
||
|
01010101
|
||
|
10101010
|
||
|
01010111
|
||
|
10101010
|
||
|
01010101
|
||
|
00101010
|
||
|
00010101
|
||
|
>
|
||
|
10101011
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
10101010
|
||
|
01010101
|
||
|
00101010
|
||
|
00010101
|
||
|
|
||
|
TIL 2n
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
|
||
|
TIL 2o
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 2p
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 2q
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 2r
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 2s
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
10111111
|
||
|
10111111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 2t
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
00000011
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 2u
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111110
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
|
||
|
TIL 2v
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 2w
|
||
|
11000000
|
||
|
11100000
|
||
|
11110000
|
||
|
11111000
|
||
|
11111100
|
||
|
11111110
|
||
|
01111111
|
||
|
00111111
|
||
|
|
||
|
TIL 2x
|
||
|
00011111
|
||
|
00001111
|
||
|
00000111
|
||
|
00000011
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 2y
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
10000000
|
||
|
|
||
|
TIL 2z
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01111110
|
||
|
01111110
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 3a
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
|
||
|
TIL 3b
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
|
||
|
TIL 3e
|
||
|
11110111
|
||
|
11111111
|
||
|
11111111
|
||
|
10101101
|
||
|
11111111
|
||
|
01111111
|
||
|
11110111
|
||
|
10111111
|
||
|
>
|
||
|
11111111
|
||
|
10111101
|
||
|
11111111
|
||
|
11111111
|
||
|
10111111
|
||
|
11101111
|
||
|
11111101
|
||
|
11111111
|
||
|
WAL true
|
||
|
|
||
|
TIL 3f
|
||
|
11111111
|
||
|
01111111
|
||
|
11111111
|
||
|
11111101
|
||
|
11111111
|
||
|
11111111
|
||
|
11011111
|
||
|
11111111
|
||
|
>
|
||
|
11111110
|
||
|
11111111
|
||
|
11110111
|
||
|
11111111
|
||
|
11111111
|
||
|
11101111
|
||
|
11111101
|
||
|
11110111
|
||
|
WAL true
|
||
|
|
||
|
TIL 3g
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11011111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111101
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
WAL true
|
||
|
|
||
|
TIL 3h
|
||
|
11111111
|
||
|
11111101
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
10111111
|
||
|
11111111
|
||
|
WAL true
|
||
|
|
||
|
TIL 3j
|
||
|
00000000
|
||
|
01000000
|
||
|
01011100
|
||
|
01010100
|
||
|
01011100
|
||
|
01000100
|
||
|
01011100
|
||
|
01000000
|
||
|
|
||
|
TIL 3k
|
||
|
00000000
|
||
|
00000000
|
||
|
00000011
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000000
|
||
|
|
||
|
TIL 3l
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000001
|
||
|
00000111
|
||
|
00000100
|
||
|
00000111
|
||
|
00000000
|
||
|
|
||
|
TIL 3m
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000001
|
||
|
00000111
|
||
|
00000001
|
||
|
00000111
|
||
|
00000000
|
||
|
|
||
|
TIL 3n
|
||
|
00000000
|
||
|
00000000
|
||
|
00000100
|
||
|
00000101
|
||
|
00000111
|
||
|
00000001
|
||
|
00000001
|
||
|
00000000
|
||
|
|
||
|
TIL 3o
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000100
|
||
|
00000111
|
||
|
00000001
|
||
|
00000111
|
||
|
00000000
|
||
|
|
||
|
TIL 3p
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000100
|
||
|
00000111
|
||
|
00000101
|
||
|
00000111
|
||
|
00000000
|
||
|
|
||
|
TIL 3q
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000001
|
||
|
00000011
|
||
|
00000010
|
||
|
00000010
|
||
|
00000000
|
||
|
|
||
|
TIL 3r
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000101
|
||
|
00000111
|
||
|
00000101
|
||
|
00000111
|
||
|
00000000
|
||
|
|
||
|
TIL 3s
|
||
|
00000000
|
||
|
00000000
|
||
|
00000111
|
||
|
00000101
|
||
|
00000111
|
||
|
00000001
|
||
|
00000111
|
||
|
00000000
|
||
|
|
||
|
TIL 3t
|
||
|
00000000
|
||
|
00000000
|
||
|
01100000
|
||
|
01100000
|
||
|
00000000
|
||
|
01100000
|
||
|
01100000
|
||
|
00000000
|
||
|
NAME :
|
||
|
|
||
|
TIL 3u
|
||
|
00110000
|
||
|
01111000
|
||
|
11111100
|
||
|
11111100
|
||
|
01111000
|
||
|
00110000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00000000
|
||
|
00001100
|
||
|
00011110
|
||
|
00111111
|
||
|
00111111
|
||
|
00011110
|
||
|
00001100
|
||
|
NAME ball
|
||
|
|
||
|
TIL 3v
|
||
|
00000111
|
||
|
00000111
|
||
|
00011100
|
||
|
11111000
|
||
|
11110000
|
||
|
11110000
|
||
|
11100000
|
||
|
10000000
|
||
|
|
||
|
TIL 3w
|
||
|
00110000
|
||
|
00110000
|
||
|
01100000
|
||
|
01111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
01111111
|
||
|
|
||
|
TIL 3x
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
|
||
|
TIL 3y
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
10000000
|
||
|
10000000
|
||
|
|
||
|
TIL 3z
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01100000
|
||
|
11100000
|
||
|
11100000
|
||
|
10110000
|
||
|
|
||
|
TIL 4a
|
||
|
11111111
|
||
|
10101100
|
||
|
11111101
|
||
|
10101101
|
||
|
11111101
|
||
|
11111100
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 4b
|
||
|
11111111
|
||
|
00000000
|
||
|
00110110
|
||
|
00110110
|
||
|
00000000
|
||
|
00110110
|
||
|
00110110
|
||
|
00000000
|
||
|
|
||
|
TIL 4c
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100000
|
||
|
11100000
|
||
|
|
||
|
TIL 4d
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11010101
|
||
|
10000000
|
||
|
11000101
|
||
|
10000101
|
||
|
11000001
|
||
|
|
||
|
TIL 4e
|
||
|
11111111
|
||
|
11111111
|
||
|
11111011
|
||
|
01011001
|
||
|
00001100
|
||
|
00011110
|
||
|
00001011
|
||
|
00011001
|
||
|
|
||
|
TIL 4f
|
||
|
10000101
|
||
|
11000101
|
||
|
10000101
|
||
|
11010101
|
||
|
10000000
|
||
|
11010101
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 4g
|
||
|
00001100
|
||
|
00011110
|
||
|
00001111
|
||
|
00011111
|
||
|
00001011
|
||
|
01011111
|
||
|
11110101
|
||
|
11111111
|
||
|
|
||
|
TIL 4h
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 4i
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
01010111
|
||
|
00000011
|
||
|
00000111
|
||
|
00000011
|
||
|
11100111
|
||
|
|
||
|
TIL 4j
|
||
|
10000000
|
||
|
11001111
|
||
|
10000000
|
||
|
11001110
|
||
|
10010010
|
||
|
11010010
|
||
|
10000000
|
||
|
11010101
|
||
|
|
||
|
TIL 4k
|
||
|
00000011
|
||
|
11100111
|
||
|
00000011
|
||
|
01100111
|
||
|
11100011
|
||
|
10100111
|
||
|
00000011
|
||
|
01010111
|
||
|
|
||
|
TIL 4l
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00000111
|
||
|
00000111
|
||
|
00010111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 4m
|
||
|
00000011
|
||
|
11110011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
|
||
|
TIL 4n
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
|
||
|
TIL 4o
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
00001011
|
||
|
11110011
|
||
|
00000011
|
||
|
|
||
|
TIL 4p
|
||
|
01010000
|
||
|
01010000
|
||
|
01010000
|
||
|
01010000
|
||
|
01010000
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
|
||
|
TIL 4q
|
||
|
01000001
|
||
|
01000001
|
||
|
01000001
|
||
|
01000001
|
||
|
01010001
|
||
|
01000000
|
||
|
00111111
|
||
|
00000000
|
||
|
|
||
|
TIL 4r
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000001
|
||
|
01000001
|
||
|
01000001
|
||
|
01000001
|
||
|
01000001
|
||
|
|
||
|
TIL 4s
|
||
|
00000000
|
||
|
00111111
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
|
||
|
TIL 4t
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01000000
|
||
|
01000000
|
||
|
01000000
|
||
|
|
||
|
TIL 4u
|
||
|
01000000
|
||
|
01010000
|
||
|
01010000
|
||
|
01010000
|
||
|
01000000
|
||
|
01010000
|
||
|
01010000
|
||
|
01010000
|
||
|
|
||
|
TIL 4v
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 4w
|
||
|
01000000
|
||
|
01000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 4x
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00110100
|
||
|
00101000
|
||
|
00010100
|
||
|
00101100
|
||
|
00000000
|
||
|
|
||
|
TIL 4y
|
||
|
00100000
|
||
|
00100000
|
||
|
00100000
|
||
|
00100000
|
||
|
00100101
|
||
|
00100101
|
||
|
00100101
|
||
|
00100101
|
||
|
|
||
|
TIL 4z
|
||
|
00000000
|
||
|
00000000
|
||
|
00100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 5a
|
||
|
01100110
|
||
|
00111100
|
||
|
01111110
|
||
|
10100101
|
||
|
11011011
|
||
|
01011010
|
||
|
01100110
|
||
|
00111100
|
||
|
|
||
|
TIL 5f
|
||
|
00010110
|
||
|
00100011
|
||
|
00100100
|
||
|
00011010
|
||
|
00010001
|
||
|
00001010
|
||
|
00000110
|
||
|
00000001
|
||
|
|
||
|
TIL 5g
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00111000
|
||
|
01010100
|
||
|
10100010
|
||
|
11011100
|
||
|
|
||
|
TIL 5h
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00011100
|
||
|
00101010
|
||
|
01000101
|
||
|
00111011
|
||
|
|
||
|
TIL 5i
|
||
|
01101000
|
||
|
01000100
|
||
|
00100100
|
||
|
01011000
|
||
|
10001000
|
||
|
01010000
|
||
|
01100000
|
||
|
10000000
|
||
|
|
||
|
TIL 5j
|
||
|
01011111
|
||
|
11101111
|
||
|
01101111
|
||
|
10011111
|
||
|
11011111
|
||
|
10111111
|
||
|
01111111
|
||
|
11111111
|
||
|
|
||
|
TIL 5k
|
||
|
10100110
|
||
|
01110010
|
||
|
01101111
|
||
|
10010110
|
||
|
10111001
|
||
|
11010110
|
||
|
11100110
|
||
|
11111001
|
||
|
|
||
|
TIL 5l
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
10001111
|
||
|
01010110
|
||
|
11101001
|
||
|
00010000
|
||
|
|
||
|
TIL 5m
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
00011111
|
||
|
10101111
|
||
|
01110111
|
||
|
10001111
|
||
|
|
||
|
TIL 5n
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111110
|
||
|
11111111
|
||
|
|
||
|
TIL 5o
|
||
|
00110100
|
||
|
00110100
|
||
|
01111110
|
||
|
01111110
|
||
|
00111100
|
||
|
01111110
|
||
|
01111110
|
||
|
00110100
|
||
|
NAME hash
|
||
|
|
||
|
TIL 5p
|
||
|
00111100
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
00111100
|
||
|
NAME O filled
|
||
|
|
||
|
TIL 5q
|
||
|
01111100
|
||
|
01111110
|
||
|
01111110
|
||
|
01111100
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
NAME B filled
|
||
|
|
||
|
TIL 5r
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111100
|
||
|
01110000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME P filled
|
||
|
|
||
|
TIL 5s
|
||
|
00111100
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
NAME A filled
|
||
|
|
||
|
TIL 5t
|
||
|
00000000
|
||
|
00011000
|
||
|
00001100
|
||
|
01111110
|
||
|
01111110
|
||
|
00001100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00110000
|
||
|
00011000
|
||
|
11111100
|
||
|
11111100
|
||
|
00011000
|
||
|
00110000
|
||
|
00000000
|
||
|
|
||
|
TIL 5u
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
|
||
|
TIL 5v
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
11100010
|
||
|
|
||
|
TIL 5w
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
|
||
|
TIL 5x
|
||
|
01001001
|
||
|
01001001
|
||
|
01001001
|
||
|
01001001
|
||
|
01001001
|
||
|
01001001
|
||
|
01001001
|
||
|
01001001
|
||
|
|
||
|
TIL 5y
|
||
|
00000000
|
||
|
00000000
|
||
|
01000000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
01001000
|
||
|
|
||
|
TIL 5z
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 6a
|
||
|
00010001
|
||
|
00010001
|
||
|
00010001
|
||
|
11100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL 6b
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
11100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL 6c
|
||
|
00001000
|
||
|
00001000
|
||
|
00001100
|
||
|
00000010
|
||
|
00000010
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL 6d
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000001
|
||
|
00000001
|
||
|
11111110
|
||
|
00000000
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL 6e
|
||
|
01000000
|
||
|
01000000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL 6f
|
||
|
00111100
|
||
|
01111110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01100110
|
||
|
01111100
|
||
|
00111110
|
||
|
|
||
|
TIL 6g
|
||
|
01111110
|
||
|
01100110
|
||
|
00000110
|
||
|
00001100
|
||
|
00111000
|
||
|
01110000
|
||
|
01110110
|
||
|
01111110
|
||
|
|
||
|
TIL 6h
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01111110
|
||
|
01111110
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME -
|
||
|
|
||
|
TIL 6i
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME .
|
||
|
|
||
|
TIL 6j
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01100000
|
||
|
01100000
|
||
|
00100000
|
||
|
|
||
|
TIL 6k
|
||
|
00110000
|
||
|
00110000
|
||
|
00000001
|
||
|
00000011
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 6l
|
||
|
00011000
|
||
|
00011000
|
||
|
00000000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 6m
|
||
|
10010010
|
||
|
11110010
|
||
|
10010010
|
||
|
10011111
|
||
|
10011110
|
||
|
10011110
|
||
|
10011110
|
||
|
11111110
|
||
|
|
||
|
TIL 6n
|
||
|
11100111
|
||
|
11111111
|
||
|
11000111
|
||
|
11000101
|
||
|
11111111
|
||
|
01000111
|
||
|
01000101
|
||
|
01111111
|
||
|
|
||
|
TIL 6o
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 6p
|
||
|
00110001
|
||
|
00110001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00010001
|
||
|
|
||
|
TIL 6q
|
||
|
10011111
|
||
|
10011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
|
||
|
TIL 6r
|
||
|
11111111
|
||
|
11111000
|
||
|
11111000
|
||
|
01011000
|
||
|
00001000
|
||
|
00011000
|
||
|
00001111
|
||
|
00011000
|
||
|
|
||
|
TIL 6s
|
||
|
00001000
|
||
|
00011111
|
||
|
00001000
|
||
|
00011000
|
||
|
00001111
|
||
|
01010010
|
||
|
11110010
|
||
|
11110011
|
||
|
|
||
|
TIL 6t
|
||
|
11111111
|
||
|
01111111
|
||
|
00100100
|
||
|
00100100
|
||
|
00100100
|
||
|
00100100
|
||
|
11111111
|
||
|
11111111
|
||
|
|
||
|
TIL 6u
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
00000000
|
||
|
11111110
|
||
|
10010010
|
||
|
11111110
|
||
|
00000000
|
||
|
|
||
|
TIL 6v
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11110000
|
||
|
11110111
|
||
|
11110100
|
||
|
11110111
|
||
|
11110000
|
||
|
|
||
|
TIL 6w
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
10011111
|
||
|
10011111
|
||
|
10010011
|
||
|
10010010
|
||
|
|
||
|
TIL 6x
|
||
|
00111111
|
||
|
00111111
|
||
|
00110110
|
||
|
11111111
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 6y
|
||
|
00000011
|
||
|
00000011
|
||
|
01010111
|
||
|
11111100
|
||
|
11111111
|
||
|
11100100
|
||
|
11100111
|
||
|
11100111
|
||
|
|
||
|
TIL 6z
|
||
|
11111111
|
||
|
11010101
|
||
|
11000001
|
||
|
11000001
|
||
|
11000001
|
||
|
11000001
|
||
|
11000001
|
||
|
11010101
|
||
|
|
||
|
TIL 7a
|
||
|
11100000
|
||
|
11100000
|
||
|
11100111
|
||
|
11111111
|
||
|
11111111
|
||
|
01100110
|
||
|
01100111
|
||
|
01100011
|
||
|
NAME R-1
|
||
|
|
||
|
TIL 7b
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME R-2
|
||
|
|
||
|
TIL 7c
|
||
|
00001110
|
||
|
01111111
|
||
|
01111111
|
||
|
01110000
|
||
|
01100000
|
||
|
01100000
|
||
|
11100000
|
||
|
11100000
|
||
|
NAME R-3
|
||
|
|
||
|
TIL 7d
|
||
|
01100000
|
||
|
01100000
|
||
|
11000000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
10000000
|
||
|
11000000
|
||
|
NAME R-4
|
||
|
|
||
|
TIL 7e
|
||
|
00000000
|
||
|
10000000
|
||
|
11110000
|
||
|
11110000
|
||
|
00110000
|
||
|
00110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME R-5
|
||
|
|
||
|
TIL 7f
|
||
|
11000000
|
||
|
11100000
|
||
|
11100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME R-6
|
||
|
|
||
|
TIL 7g
|
||
|
11100011
|
||
|
11100011
|
||
|
11101110
|
||
|
11111110
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
11100000
|
||
|
NAME K-1
|
||
|
|
||
|
TIL 7h
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME K-2
|
||
|
|
||
|
TIL 7i
|
||
|
00000000
|
||
|
01100000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME K-3
|
||
|
|
||
|
TIL 7j
|
||
|
00000000
|
||
|
00110000
|
||
|
01110000
|
||
|
01110000
|
||
|
11100000
|
||
|
11100000
|
||
|
11000000
|
||
|
11000000
|
||
|
NAME K-4
|
||
|
|
||
|
TIL 7k
|
||
|
11100000
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME K-5
|
||
|
|
||
|
TIL 7l
|
||
|
11000000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
10000000
|
||
|
10000000
|
||
|
11000000
|
||
|
11000000
|
||
|
NAME K-6
|
||
|
|
||
|
TIL 7m
|
||
|
00000011
|
||
|
00000011
|
||
|
00000011
|
||
|
00000110
|
||
|
00001110
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
NAME W-7
|
||
|
|
||
|
TIL 7n
|
||
|
00001100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
00011000
|
||
|
NAME W-6
|
||
|
|
||
|
TIL 7o
|
||
|
11011000
|
||
|
11111000
|
||
|
00110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME W-3
|
||
|
|
||
|
TIL 7p
|
||
|
11110011
|
||
|
01110000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME W-3
|
||
|
|
||
|
TIL 7q
|
||
|
10001100
|
||
|
10001110
|
||
|
10001110
|
||
|
10001110
|
||
|
10001110
|
||
|
10011110
|
||
|
10011011
|
||
|
10010011
|
||
|
NAME W-5
|
||
|
|
||
|
TIL 7r
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
NAME W-2
|
||
|
|
||
|
TIL 7s
|
||
|
00000001
|
||
|
00000011
|
||
|
00000011
|
||
|
00000011
|
||
|
00000011
|
||
|
00000011
|
||
|
00000011
|
||
|
00000011
|
||
|
NAME W-1
|
||
|
|
||
|
TIL 7t
|
||
|
11111000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
|
||
|
TIL 7u
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
|
||
|
TIL 7v
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
00010000
|
||
|
|
||
|
TIL 7w
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL 7x
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
00001000
|
||
|
11111000
|
||
|
|
||
|
TIL 7y
|
||
|
11111111
|
||
|
11011101
|
||
|
10001111
|
||
|
11011011
|
||
|
11110001
|
||
|
11111011
|
||
|
10111111
|
||
|
11101111
|
||
|
>
|
||
|
11101111
|
||
|
10111111
|
||
|
00011101
|
||
|
10111111
|
||
|
11110111
|
||
|
11100011
|
||
|
11110111
|
||
|
11111111
|
||
|
|
||
|
TIL 7z
|
||
|
11111111
|
||
|
11111111
|
||
|
11101111
|
||
|
11000111
|
||
|
11101111
|
||
|
11111011
|
||
|
11111111
|
||
|
11111111
|
||
|
>
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11110111
|
||
|
11100011
|
||
|
11110111
|
||
|
10111111
|
||
|
11111111
|
||
|
|
||
|
TIL 8a
|
||
|
01111000
|
||
|
01111000
|
||
|
01111000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME L-3
|
||
|
|
||
|
TIL 8b
|
||
|
00110000
|
||
|
11110000
|
||
|
11110000
|
||
|
11110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME L-4
|
||
|
|
||
|
TIL 8c
|
||
|
01000001
|
||
|
01111111
|
||
|
01111000
|
||
|
11100000
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME A-1
|
||
|
|
||
|
TIL 8d
|
||
|
11100000
|
||
|
11100000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME A-2
|
||
|
|
||
|
TIL 8e
|
||
|
00011111
|
||
|
00111111
|
||
|
00110000
|
||
|
11110000
|
||
|
11110000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
NAME A-3
|
||
|
|
||
|
TIL 8f
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME A-4
|
||
|
|
||
|
TIL 8g
|
||
|
11111000
|
||
|
11111000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00110000
|
||
|
NAME A-5
|
||
|
|
||
|
TIL 8h
|
||
|
00110000
|
||
|
00110000
|
||
|
00110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME A-6
|
||
|
|
||
|
TIL 8i
|
||
|
11100000
|
||
|
11100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01111000
|
||
|
01111000
|
||
|
00011100
|
||
|
00011100
|
||
|
NAME Y-1
|
||
|
|
||
|
TIL 8j
|
||
|
00011100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001111
|
||
|
00000011
|
||
|
00000011
|
||
|
00001110
|
||
|
00001110
|
||
|
NAME Y-2
|
||
|
|
||
|
TIL 8k
|
||
|
00011110
|
||
|
00011110
|
||
|
00011110
|
||
|
00001110
|
||
|
00001100
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME Y-3
|
||
|
|
||
|
TIL 8l
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00111000
|
||
|
00111000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME Y-4
|
||
|
|
||
|
TIL 8m
|
||
|
01110000
|
||
|
01110000
|
||
|
01100000
|
||
|
11100000
|
||
|
10000000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME Y-5
|
||
|
|
||
|
TIL 8n
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME G-1
|
||
|
|
||
|
TIL 8o
|
||
|
00111000
|
||
|
00111000
|
||
|
00111111
|
||
|
00001111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME G-2
|
||
|
|
||
|
TIL 8p
|
||
|
00000111
|
||
|
00000111
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME G-3
|
||
|
|
||
|
TIL 8q
|
||
|
11110000
|
||
|
11111100
|
||
|
00001100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME G-4
|
||
|
|
||
|
TIL 8r
|
||
|
00111000
|
||
|
01100000
|
||
|
11100000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME G-5
|
||
|
|
||
|
TIL 8s
|
||
|
00000000
|
||
|
00000000
|
||
|
11111100
|
||
|
01111100
|
||
|
00001100
|
||
|
00001100
|
||
|
00111000
|
||
|
00111000
|
||
|
NAME G-6
|
||
|
|
||
|
TIL 8t
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
00111111
|
||
|
00111111
|
||
|
01110011
|
||
|
01110011
|
||
|
01110011
|
||
|
NAME M-1
|
||
|
|
||
|
TIL 8u
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
00111000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME M-2
|
||
|
|
||
|
TIL 8v
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME M-3
|
||
|
|
||
|
TIL 8w
|
||
|
00001110
|
||
|
00001110
|
||
|
00111110
|
||
|
00111110
|
||
|
00110110
|
||
|
00110110
|
||
|
11100110
|
||
|
11100110
|
||
|
NAME M-4
|
||
|
|
||
|
TIL 8x
|
||
|
11101110
|
||
|
11001110
|
||
|
11001110
|
||
|
00001110
|
||
|
00001110
|
||
|
00000110
|
||
|
00000110
|
||
|
00000110
|
||
|
NAME M-5
|
||
|
|
||
|
TIL 8y
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00000100
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME M-6
|
||
|
|
||
|
TIL 8z
|
||
|
00001111
|
||
|
00001111
|
||
|
00111110
|
||
|
00110000
|
||
|
00110000
|
||
|
00110000
|
||
|
00110000
|
||
|
00110000
|
||
|
NAME E-1
|
||
|
|
||
|
TIL 9a
|
||
|
00000000
|
||
|
00110000
|
||
|
00110001
|
||
|
00011111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME S-3
|
||
|
|
||
|
TIL 9b
|
||
|
11111000
|
||
|
11111110
|
||
|
00000110
|
||
|
00000010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME S-4
|
||
|
|
||
|
TIL 9c
|
||
|
00000000
|
||
|
00000000
|
||
|
11111000
|
||
|
11111000
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00011100
|
||
|
NAME S-5
|
||
|
|
||
|
TIL 9d
|
||
|
00011000
|
||
|
00111000
|
||
|
11100000
|
||
|
11100000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME S-6
|
||
|
|
||
|
TIL 9e
|
||
|
00111000
|
||
|
00110000
|
||
|
00110000
|
||
|
00110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME U-1
|
||
|
|
||
|
TIL 9f
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00110000
|
||
|
00110000
|
||
|
NAME U-2
|
||
|
|
||
|
TIL 9g
|
||
|
00110001
|
||
|
00111111
|
||
|
00001110
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME U-3
|
||
|
|
||
|
TIL 9h
|
||
|
11111000
|
||
|
11000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME U-4
|
||
|
|
||
|
TIL 9i
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00011100
|
||
|
00111000
|
||
|
00111000
|
||
|
NAME U-5
|
||
|
|
||
|
TIL 9j
|
||
|
00000100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
NAME U-6
|
||
|
|
||
|
TIL 9k
|
||
|
01110001
|
||
|
01111111
|
||
|
01111110
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME B-1
|
||
|
|
||
|
TIL 9l
|
||
|
00111111
|
||
|
00111111
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME B-2
|
||
|
|
||
|
TIL 9m
|
||
|
01100000
|
||
|
01100011
|
||
|
01111111
|
||
|
01111100
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME B-3
|
||
|
|
||
|
TIL 9n
|
||
|
11100000
|
||
|
11100000
|
||
|
00011000
|
||
|
00011000
|
||
|
00001100
|
||
|
00001100
|
||
|
00111000
|
||
|
00111000
|
||
|
NAME B-4
|
||
|
|
||
|
TIL 9o
|
||
|
11100000
|
||
|
11111000
|
||
|
00011000
|
||
|
00011100
|
||
|
00001100
|
||
|
00001100
|
||
|
00111000
|
||
|
00111000
|
||
|
NAME B-5
|
||
|
|
||
|
TIL 9p
|
||
|
11110000
|
||
|
10000000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME B-6
|
||
|
|
||
|
TIL 9q
|
||
|
00111111
|
||
|
00111111
|
||
|
00110000
|
||
|
00110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
NAME F-1
|
||
|
|
||
|
TIL 9r
|
||
|
01110011
|
||
|
00111111
|
||
|
00111100
|
||
|
00110000
|
||
|
00110000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME F-2
|
||
|
|
||
|
TIL 9s
|
||
|
01110000
|
||
|
01110000
|
||
|
01110000
|
||
|
00110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME F-3
|
||
|
|
||
|
TIL 9t
|
||
|
11000000
|
||
|
11111000
|
||
|
00111000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME F-4
|
||
|
|
||
|
TIL 9u
|
||
|
11000000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME F-5
|
||
|
|
||
|
TIL 9v
|
||
|
00001111
|
||
|
00011000
|
||
|
00110000
|
||
|
00110000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
01100000
|
||
|
NAME C-1
|
||
|
|
||
|
TIL 9w
|
||
|
11100000
|
||
|
01110000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME C-2
|
||
|
|
||
|
TIL 9x
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
11000000
|
||
|
NAME C-3
|
||
|
|
||
|
TIL 9y
|
||
|
01100011
|
||
|
00111111
|
||
|
00111110
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME C-4
|
||
|
|
||
|
TIL 9z
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
01100000
|
||
|
11100000
|
||
|
NAME C-5
|
||
|
|
||
|
TIL a0
|
||
|
11100000
|
||
|
10000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME C-6
|
||
|
|
||
|
TIL a1
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
00000001
|
||
|
>
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME door
|
||
|
WAL false
|
||
|
|
||
|
TIL a2
|
||
|
01010101
|
||
|
00000000
|
||
|
00000001
|
||
|
00000000
|
||
|
01010101
|
||
|
11111111
|
||
|
01010101
|
||
|
11111111
|
||
|
>
|
||
|
10101010
|
||
|
00000001
|
||
|
00000000
|
||
|
00000001
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
NAME tunnel
|
||
|
WAL false
|
||
|
|
||
|
TIL a3
|
||
|
00000000
|
||
|
00000000
|
||
|
00011110
|
||
|
11111111
|
||
|
11111000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME dash
|
||
|
|
||
|
TIL a4
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
NAME ghost files
|
||
|
|
||
|
TIL a5
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
00011111
|
||
|
00011111
|
||
|
00011111
|
||
|
NAME ghost files
|
||
|
|
||
|
TIL a6
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111111
|
||
|
11111000
|
||
|
11111000
|
||
|
11111000
|
||
|
NAME ghost files
|
||
|
|
||
|
TIL a7
|
||
|
01110111
|
||
|
01000111
|
||
|
01110000
|
||
|
01000000
|
||
|
01110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL a8
|
||
|
01111101
|
||
|
01000101
|
||
|
01101100
|
||
|
01000100
|
||
|
01101100
|
||
|
01000100
|
||
|
01111100
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL a9
|
||
|
10111110
|
||
|
10100010
|
||
|
00101110
|
||
|
00100010
|
||
|
00101010
|
||
|
00100010
|
||
|
00111110
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
10101010
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL aa
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
00001100
|
||
|
>
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
00000000
|
||
|
00001100
|
||
|
|
||
|
TIL ab
|
||
|
00011111
|
||
|
00001111
|
||
|
00000111
|
||
|
00000011
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00011111
|
||
|
00001111
|
||
|
01000111
|
||
|
01000011
|
||
|
00000001
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL ac
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
10101010
|
||
|
00000000
|
||
|
WAL true
|
||
|
|
||
|
TIL ad
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
WAL false
|
||
|
|
||
|
TIL ae
|
||
|
11111100
|
||
|
00000100
|
||
|
11111100
|
||
|
00000100
|
||
|
11111100
|
||
|
00000100
|
||
|
11111100
|
||
|
00000100
|
||
|
WAL false
|
||
|
|
||
|
TIL af
|
||
|
00111111
|
||
|
00100000
|
||
|
00111111
|
||
|
00100000
|
||
|
00111111
|
||
|
00100000
|
||
|
00111111
|
||
|
00100000
|
||
|
WAL false
|
||
|
|
||
|
TIL ag
|
||
|
00000011
|
||
|
01010000
|
||
|
00100011
|
||
|
01010000
|
||
|
00000011
|
||
|
00000000
|
||
|
11111111
|
||
|
00000100
|
||
|
|
||
|
TIL ah
|
||
|
00000000
|
||
|
00000000
|
||
|
11110000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
|
||
|
TIL ai
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000100
|
||
|
WAL false
|
||
|
|
||
|
TIL aj
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00000000
|
||
|
11111111
|
||
|
00100000
|
||
|
WAL false
|
||
|
|
||
|
SPR A
|
||
|
00000000
|
||
|
00111100
|
||
|
00100100
|
||
|
00111100
|
||
|
00010000
|
||
|
00011000
|
||
|
00010000
|
||
|
00011000
|
||
|
POS w 12,10
|
||
|
|
||
|
SPR a
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
00000000
|
||
|
>
|
||
|
00000000
|
||
|
00111100
|
||
|
00000100
|
||
|
00011100
|
||
|
00010000
|
||
|
00000000
|
||
|
00010000
|
||
|
00000000
|
||
|
NAME friend
|
||
|
|
||
|
ITM 9
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME CPU
|
||
|
DLG z
|
||
|
|
||
|
ITM a
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME RAM
|
||
|
DLG y
|
||
|
|
||
|
ITM b
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME WIFI BLE
|
||
|
DLG x
|
||
|
|
||
|
ITM c
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME GPIO
|
||
|
DLG w
|
||
|
|
||
|
ITM d
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME ETHERNET
|
||
|
DLG v
|
||
|
|
||
|
ITM e
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME USB 2
|
||
|
DLG 18
|
||
|
|
||
|
ITM f
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME AUDIO
|
||
|
DLG t
|
||
|
|
||
|
ITM g
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME CAMERA
|
||
|
DLG s
|
||
|
|
||
|
ITM h
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME MICRO HDMI
|
||
|
DLG r
|
||
|
|
||
|
ITM i
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME POWER
|
||
|
DLG q
|
||
|
|
||
|
ITM j
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME MICRO SD
|
||
|
DLG p
|
||
|
|
||
|
ITM k
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME USB 3
|
||
|
DLG 10
|
||
|
|
||
|
ITM l
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME POE Pins
|
||
|
DLG 11
|
||
|
|
||
|
ITM m
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME DISPLAY
|
||
|
DLG 12
|
||
|
|
||
|
ITM n
|
||
|
00000000
|
||
|
00011000
|
||
|
00011000
|
||
|
01011010
|
||
|
01111110
|
||
|
00111100
|
||
|
00011000
|
||
|
00000000
|
||
|
>
|
||
|
11111111
|
||
|
11100111
|
||
|
11100111
|
||
|
10100101
|
||
|
10000001
|
||
|
11000011
|
||
|
11100111
|
||
|
11111111
|
||
|
NAME MOTHERBOARD
|
||
|
DLG 17
|
||
|
|
||
|
DLG 8
|
||
|
"""
|
||
|
{
|
||
|
- {item "4"} < 82 ?
|
||
|
Clear your Thoughts!{property locked true}
|
||
|
- {item "4"} == 82 ?
|
||
|
Scattered Thoughts, they feel like Ghosts haunting me.{property locked false}
|
||
|
}
|
||
|
"""
|
||
|
NAME Fog Room Exit
|
||
|
|
||
|
DLG 10
|
||
|
USB 3{pg}The USB (Universal Serial Bus) port enables a connection between the Raspberry Pi and other external devices.{pg}Via the USB port data from an input device (e.g. keyboard, mouse ...) can be sent to the computer or information from the computer can be sent to an output device (e.g. printer).
|
||
|
NAME USB 3 dialog
|
||
|
|
||
|
DLG 11
|
||
|
POE Pins{pg}The Power over Ethernet (PoE) pins allow the Ethernet network cable to carry not only data, but also electric power.{pg}With a separate PoE HAT the Ethernet connection becomes the new lifeline of the Raspberry Pi. The traditional POWER supply is no longer needed.
|
||
|
NAME POE Pins dialog
|
||
|
|
||
|
DLG 12
|
||
|
MIPI DSI{pg}The MIPI DSI (Mobile Industry Processor Interface - Display Serial Interface) is a display port that enables the connection from the Raspberry Pi to a display.
|
||
|
NAME MIPI DSI dialog
|
||
|
|
||
|
DLG 13
|
||
|
... Here is a little fun fact before you leave ...{pg}This game you are playing right now is stored on a Raspberry Pi.{pg}In this very moment the components of the Raspberry Pi communicate with each other to run the game.{pg}Whenever you give an input, for example by moving the avatar, the Raspberry Pi processes this information and sends back the output that you see on this screen.
|
||
|
NAME ending Raspberry Pi
|
||
|
|
||
|
DLG 14
|
||
|
This is a Raspberry Pi 4B.{pg}A Raspberry Pi is a tiny and low-cost single-board computer that enables people to explore computing and to learn how to program in languages like Python.{pg}A computer receives data through an input unit and after it processes the data, it sends it back through output devices.{pg}The Raspberry Pi runs Linux and provides a set of GPIO (general purpose input/output) pins, allowing you to control electronic components for physical computing and explore the Internet of Things (IoT).{pg}Welcome inside the Raspberry Pi!
|
||
|
NAME exit 2D enter pi3D
|
||
|
|
||
|
DLG 15
|
||
|
|
||
|
NAME ending 1
|
||
|
|
||
|
DLG 17
|
||
|
MOTHERBOARD{pg}The Motherboard acts as the home for all other components of the computer. It provides the physical connection that allows them to communicate with each other and gives them power in order to function. Without a Motherboard, there can't be a computer.
|
||
|
NAME MOTHERBOARD dialog
|
||
|
|
||
|
DLG 18
|
||
|
USB 2{pg}The USB (Universal Serial Bus) port enables a connection between the Raspberry Pi and other external devices.{pg}Via the USB port data from an input device (e.g. keyboard, mouse ...) can be sent to the computer or information from the computer can be sent to an output device (e.g. printer).
|
||
|
NAME USB 2 dialog
|
||
|
|
||
|
DLG 19
|
||
|
The end
|
||
|
NAME ending 2
|
||
|
|
||
|
DLG c
|
||
|
You walk through the doorway
|
||
|
NAME exit narration 1
|
||
|
|
||
|
DLG d
|
||
|
"""
|
||
|
{
|
||
|
- {item "5"} >= 1 ?
|
||
|
{property locked false}Lets try to find a way out!
|
||
|
- else ?
|
||
|
{property locked true}...
|
||
|
}
|
||
|
"""
|
||
|
NAME locked exit 1
|
||
|
|
||
|
DLG h
|
||
|
"""
|
||
|
{
|
||
|
- {item "6"} >= 1 ?
|
||
|
{property locked false}You chose the past ...
|
||
|
- else ?
|
||
|
{property locked true}...
|
||
|
}
|
||
|
"""
|
||
|
NAME locked exit to past
|
||
|
|
||
|
DLG j
|
||
|
"""
|
||
|
{
|
||
|
- {item "6"} >= 1 ?
|
||
|
{property locked false}You chose the future ...
|
||
|
- else ?
|
||
|
{property locked true}...
|
||
|
}
|
||
|
"""
|
||
|
NAME locked exit to future
|
||
|
|
||
|
DLG k
|
||
|
"""
|
||
|
{
|
||
|
- {item "4"} >= 90 ?
|
||
|
{property locked false}
|
||
|
- else ?
|
||
|
{property locked true}What does the future hold?
|
||
|
}
|
||
|
"""
|
||
|
NAME locked exit from foggy future
|
||
|
|
||
|
DLG m
|
||
|
"""
|
||
|
{
|
||
|
- {item "6"} >= 1 ?
|
||
|
{property locked false}You chose the present ...
|
||
|
- else ?
|
||
|
{property locked true}...
|
||
|
}
|
||
|
"""
|
||
|
NAME locked exit to present
|
||
|
|
||
|
DLG n
|
||
|
"""
|
||
|
{
|
||
|
- {item "7"} >= 1 ?
|
||
|
{property locked false}
|
||
|
- else ?
|
||
|
{property locked true}...
|
||
|
}
|
||
|
"""
|
||
|
NAME locked exit from present
|
||
|
|
||
|
DLG o
|
||
|
In this room you only encounter information and opinions that reflect and reinforce their own. Your thoughts are amplified inside this closed system. Is history repeating itself?{pg}This is the center of the echo chamber. {pg}You are the center of the echo chamber.{pg}This is the only way out ...
|
||
|
NAME exit narration from past
|
||
|
|
||
|
DLG p
|
||
|
MICRO SD{pg}The MICRO SD is the long term memory of the Raspberry Pi. This is where the Operating System (OS), software and data are stored permanently.{pg}The MICRO SD slot sits on the bottom side of the Motherboard and the card can be changed manually.
|
||
|
NAME MICRO SD dialog
|
||
|
|
||
|
DLG q
|
||
|
POWER{pg}The Raspberry Pi is an electronic device that requires a power supply to work. It is the lifeline of this computer.
|
||
|
NAME POWER dialog
|
||
|
|
||
|
DLG r
|
||
|
MICRO HDMI{pg}The MICRO HDMI (High Definition Multimedia Interface) port enables the connection from the Raspberry Pi to external devices such as SmartPhones and Action Cameras.
|
||
|
NAME MICRO HDMI dialog
|
||
|
|
||
|
DLG s
|
||
|
MIPI CSI{pg}The MIPI CSI (Mobile Industry Processor Interface - Camera Serial Interface) is a camera port that enables the connection from the Raspberry Pi to a camera.
|
||
|
NAME MIPI CSI dialog
|
||
|
|
||
|
DLG t
|
||
|
AUDIO / VIDEO{pg}The AUDIO and VIDEO (A/V) Output Jack enables the connection from the Raspberry Pi to an audio or video output device.
|
||
|
NAME AUDIO dialog
|
||
|
|
||
|
DLG v
|
||
|
ETHERNET{pg}The ETHERNET network adapter is the connection to the outside world as it provides access to the internet or other local networks.
|
||
|
NAME ETHERNET dialog
|
||
|
|
||
|
DLG w
|
||
|
GPIO{pg}A general-purpose input/output (GPIO) is a digital signal pin that can be used as an input or output, or both.{pg}The 40 GPIO pins on the Raspberry Pi can be used to connect the computer to other electronic input and output devices (e.g. sensors, motors, lights, buttons and other peripherals).
|
||
|
NAME GPIO dialog
|
||
|
|
||
|
DLG x
|
||
|
WIFI / BLE{pg}The WIFI / BLE (Bluetooth Low Energy) component enables a wireless connection to the outside world as it provides access to the internet or other local networks and devices.
|
||
|
NAME WIFI BLE dialog
|
||
|
|
||
|
DLG y
|
||
|
RAM{pg}The RAM (Random-Access Memory) is a short term memory and together with the CPU builds the brain of the Raspberry Pi.{pg}It stores data that is used by the Operating System (OS) and software so that the CPU can process them quickly.{pg}Every time the computer is shut off, all information stored on RAM is lost.
|
||
|
NAME RAM dialog
|
||
|
|
||
|
DLG z
|
||
|
CPU{pg}The CPU (Central Processing Unit) is the processor and together with the RAM builds the brain of the Raspberry Pi.{pg}It is considered the most important component in a computer since it handles most operations that make it function:{pg}Receiving data from an input unit, processing the information and then sending it back through an output device.
|
||
|
NAME CPU dialog
|
||
|
|
||
|
DLG 1b
|
||
|
The end
|
||
|
NAME ending 3
|
||
|
|
||
|
DLG DATA3D
|
||
|
"""
|
||
|
{
|
||
|
"camera": "orbiting follower",
|
||
|
"settings": {
|
||
|
"engineSize": "512x512",
|
||
|
"canvasSize": "auto",
|
||
|
"clearColor": 0,
|
||
|
"enableFog": false,
|
||
|
"fogColor": 0,
|
||
|
"fogStart": 5,
|
||
|
"fogEnd": 20,
|
||
|
"positionDialogBoxAtTheTop": false,
|
||
|
"tweenDistance": 1.5,
|
||
|
"tweenDuration": 150,
|
||
|
"tweenFunction": "linear",
|
||
|
"movementHoldInterval": 150,
|
||
|
"movementSecondStepInterval": 150
|
||
|
},
|
||
|
"mesh": {
|
||
|
"SPR_A": {
|
||
|
"type": "floor",
|
||
|
"transparency": false,
|
||
|
"alpha": 0.99
|
||
|
},
|
||
|
"ITM_9": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_a": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_b": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_c": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_d": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_e": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_f": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_g": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_h": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_i": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_j": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_k": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_l": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_m": {
|
||
|
"transparency": false
|
||
|
},
|
||
|
"ITM_n": {
|
||
|
"transparency": false
|
||
|
}
|
||
|
},
|
||
|
"stack": {}
|
||
|
}
|
||
|
"""
|
||
|
|
||
|
VAR a
|
||
|
42
|
||
|
|
||
|
|
||
|
</script>
|
||
|
|
||
|
<style>
|
||
|
html {
|
||
|
margin:0px;
|
||
|
padding:0px;
|
||
|
}
|
||
|
|
||
|
body {
|
||
|
margin:0px;
|
||
|
padding:0px;
|
||
|
overflow:hidden;
|
||
|
background:#ffffff;
|
||
|
}
|
||
|
|
||
|
#game {
|
||
|
background:black;
|
||
|
width:100vw;
|
||
|
max-width:100vh;
|
||
|
margin:auto;
|
||
|
display:block;
|
||
|
}
|
||
|
</style>
|
||
|
|
||
|
<!-- SCRIPTS -->
|
||
|
<script>
|
||
|
function startExportedGame() {
|
||
|
attachCanvas( document.getElementById("game") );
|
||
|
load_game( document.getElementById("exportedGameData").text.slice(1) );
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
//hex-to-rgb method borrowed from stack overflow
|
||
|
function hexToRgb(hex) {
|
||
|
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
||
|
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||
|
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
|
||
|
return r + r + g + g + b + b;
|
||
|
});
|
||
|
|
||
|
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||
|
return result ? {
|
||
|
r: parseInt(result[1], 16),
|
||
|
g: parseInt(result[2], 16),
|
||
|
b: parseInt(result[3], 16)
|
||
|
} : null;
|
||
|
}
|
||
|
function componentToHex(c) {
|
||
|
var hex = c.toString(16);
|
||
|
return hex.length == 1 ? "0" + hex : hex;
|
||
|
}
|
||
|
function rgbToHex(r, g, b) {
|
||
|
return "#" + componentToHex(Math.floor(r)) + componentToHex(Math.floor(g)) + componentToHex(Math.floor(b));
|
||
|
}
|
||
|
|
||
|
function hslToHex(h,s,l) {
|
||
|
var rgbArr = hslToRgb(h,s,l);
|
||
|
return rgbToHex( Math.floor(rgbArr[0]), Math.floor(rgbArr[1]), Math.floor(rgbArr[2]) );
|
||
|
}
|
||
|
|
||
|
function hexToHsl(hex) {
|
||
|
var rgb = hexToRgb(hex);
|
||
|
return rgbToHsl(rgb.r, rgb.g, rgb.b);
|
||
|
}
|
||
|
|
||
|
// really just a vector distance
|
||
|
function colorDistance(a1,b1,c1,a2,b2,c2) {
|
||
|
return Math.sqrt( Math.pow(a1 - a2, 2) + Math.pow(b1 - b2, 2) + Math.pow(c1 - c2, 2) );
|
||
|
}
|
||
|
|
||
|
function hexColorDistance(hex1,hex2) {
|
||
|
var color1 = hexToRgb(hex1);
|
||
|
var color2 = hexToRgb(hex2);
|
||
|
return rgbColorDistance(color1.r, color1.g, color1.b, color2.r, color2.g, color2.b);
|
||
|
}
|
||
|
|
||
|
|
||
|
// source : http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
||
|
/* accepts parameters
|
||
|
* h Object = {h:x, s:y, v:z}
|
||
|
* OR
|
||
|
* h, s, v
|
||
|
*/
|
||
|
function HSVtoRGB(h, s, v) {
|
||
|
var r, g, b, i, f, p, q, t;
|
||
|
if (arguments.length === 1) {
|
||
|
s = h.s, v = h.v, h = h.h;
|
||
|
}
|
||
|
i = Math.floor(h * 6);
|
||
|
f = h * 6 - i;
|
||
|
p = v * (1 - s);
|
||
|
q = v * (1 - f * s);
|
||
|
t = v * (1 - (1 - f) * s);
|
||
|
switch (i % 6) {
|
||
|
case 0: r = v, g = t, b = p; break;
|
||
|
case 1: r = q, g = v, b = p; break;
|
||
|
case 2: r = p, g = v, b = t; break;
|
||
|
case 3: r = p, g = q, b = v; break;
|
||
|
case 4: r = t, g = p, b = v; break;
|
||
|
case 5: r = v, g = p, b = q; break;
|
||
|
}
|
||
|
return {
|
||
|
r: Math.round(r * 255),
|
||
|
g: Math.round(g * 255),
|
||
|
b: Math.round(b * 255)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
/* accepts parameters
|
||
|
* r Object = {r:x, g:y, b:z}
|
||
|
* OR
|
||
|
* r, g, b
|
||
|
*/
|
||
|
function RGBtoHSV(r, g, b) {
|
||
|
if (arguments.length === 1) {
|
||
|
g = r.g, b = r.b, r = r.r;
|
||
|
}
|
||
|
var max = Math.max(r, g, b), min = Math.min(r, g, b),
|
||
|
d = max - min,
|
||
|
h,
|
||
|
s = (max === 0 ? 0 : d / max),
|
||
|
v = max / 255;
|
||
|
|
||
|
switch (max) {
|
||
|
case min: h = 0; break;
|
||
|
case r: h = (g - b) + d * (g < b ? 6: 0); h /= 6 * d; break;
|
||
|
case g: h = (b - r) + d * 2; h /= 6 * d; break;
|
||
|
case b: h = (r - g) + d * 4; h /= 6 * d; break;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
h: h,
|
||
|
s: s,
|
||
|
v: v
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// source : https://gist.github.com/mjackson/5311256
|
||
|
/**
|
||
|
* Converts an HSL color value to RGB. Conversion formula
|
||
|
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||
|
* Assumes h, s, and l are contained in the set [0, 1] and
|
||
|
* returns r, g, and b in the set [0, 255].
|
||
|
*
|
||
|
* @param Number h The hue
|
||
|
* @param Number s The saturation
|
||
|
* @param Number l The lightness
|
||
|
* @return Array The RGB representation
|
||
|
*/
|
||
|
function hslToRgb(h, s, l) {
|
||
|
var r, g, b;
|
||
|
|
||
|
if (s == 0) {
|
||
|
r = g = b = l; // achromatic
|
||
|
} else {
|
||
|
function hue2rgb(p, q, t) {
|
||
|
if (t < 0) t += 1;
|
||
|
if (t > 1) t -= 1;
|
||
|
if (t < 1/6) return p + (q - p) * 6 * t;
|
||
|
if (t < 1/2) return q;
|
||
|
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||
|
var p = 2 * l - q;
|
||
|
|
||
|
r = hue2rgb(p, q, h + 1/3);
|
||
|
g = hue2rgb(p, q, h);
|
||
|
b = hue2rgb(p, q, h - 1/3);
|
||
|
}
|
||
|
|
||
|
return [ Math.floor(r * 255), Math.floor(g * 255), Math.floor(b * 255) ];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* From: http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
|
||
|
*
|
||
|
* Converts an RGB color value to HSL. Conversion formula
|
||
|
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||
|
* Assumes r, g, and b are contained in the set [0, 255] and
|
||
|
* returns h, s, and l in the set [0, 1].
|
||
|
*
|
||
|
* @param {number} r The red color value
|
||
|
* @param {number} g The green color value
|
||
|
* @param {number} b The blue color value
|
||
|
* @return {Array} The HSL representation
|
||
|
*/
|
||
|
function rgbToHsl(r, g, b){
|
||
|
r /= 255, g /= 255, b /= 255;
|
||
|
var max = Math.max(r, g, b), min = Math.min(r, g, b);
|
||
|
var h, s, l = (max + min) / 2;
|
||
|
|
||
|
if(max == min){
|
||
|
h = s = 0; // achromatic
|
||
|
}else{
|
||
|
var d = max - min;
|
||
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||
|
switch(max){
|
||
|
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
||
|
case g: h = (b - r) / d + 2; break;
|
||
|
case b: h = (r - g) / d + 4; break;
|
||
|
}
|
||
|
h /= 6;
|
||
|
}
|
||
|
|
||
|
return [h, s, l];
|
||
|
}
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
var TransitionManager = function() {
|
||
|
var transitionStart = null;
|
||
|
var transitionEnd = null;
|
||
|
var effectImage = null;
|
||
|
|
||
|
var isTransitioning = false;
|
||
|
var transitionTime = 0; // milliseconds
|
||
|
var frameRate = 8; // cap the FPS
|
||
|
var prevStep = -1; // used to avoid running post-process effect constantly
|
||
|
|
||
|
this.BeginTransition = function(startRoom,startX,startY,endRoom,endX,endY,effectName) {
|
||
|
// console.log("--- START ROOM TRANSITION ---");
|
||
|
|
||
|
curEffect = effectName;
|
||
|
|
||
|
var tmpRoom = player().room;
|
||
|
var tmpX = player().x;
|
||
|
var tmpY = player().y;
|
||
|
|
||
|
if (transitionEffects[curEffect].showPlayerStart) {
|
||
|
player().room = startRoom;
|
||
|
player().x = startX;
|
||
|
player().y = startY;
|
||
|
}
|
||
|
else {
|
||
|
player().room = "_transition_none"; // kind of hacky!!
|
||
|
}
|
||
|
|
||
|
drawRoom(room[startRoom]);
|
||
|
var startPalette = getPal( room[startRoom].pal );
|
||
|
var startImage = new PostProcessImage( ctx.getImageData(0,0,canvas.width,canvas.height) ); // TODO : don't use global ctx?
|
||
|
transitionStart = new TransitionInfo(startImage, startPalette, startX, startY);
|
||
|
|
||
|
if (transitionEffects[curEffect].showPlayerEnd) {
|
||
|
player().room = endRoom;
|
||
|
player().x = endX;
|
||
|
player().y = endY;
|
||
|
}
|
||
|
else {
|
||
|
player().room = "_transition_none";
|
||
|
}
|
||
|
|
||
|
drawRoom(room[endRoom]);
|
||
|
var endPalette = getPal( room[endRoom].pal );
|
||
|
var endImage = new PostProcessImage( ctx.getImageData(0,0,canvas.width,canvas.height) );
|
||
|
transitionEnd = new TransitionInfo(endImage, endPalette, endX, endY);
|
||
|
|
||
|
effectImage = new PostProcessImage( ctx.createImageData(canvas.width,canvas.height) );
|
||
|
|
||
|
isTransitioning = true;
|
||
|
transitionTime = 0;
|
||
|
prevStep = -1;
|
||
|
|
||
|
player().room = tmpRoom;
|
||
|
player().x = tmpX;
|
||
|
player().y = tmpY;
|
||
|
}
|
||
|
|
||
|
this.UpdateTransition = function(dt) {
|
||
|
if (!isTransitioning) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
transitionTime += dt;
|
||
|
|
||
|
var transitionDelta = transitionTime / transitionEffects[curEffect].duration;
|
||
|
var maxStep = Math.floor(frameRate * (transitionEffects[curEffect].duration / 1000));
|
||
|
var step = Math.floor(transitionDelta * maxStep);
|
||
|
|
||
|
if (step != prevStep) {
|
||
|
// console.log("step! " + step + " " + transitionDelta);
|
||
|
for (var y = 0; y < effectImage.Height; y++) {
|
||
|
for (var x = 0; x < effectImage.Width; x++) {
|
||
|
var color = transitionEffects[curEffect].pixelEffectFunc(transitionStart,transitionEnd,x,y,(step / maxStep));
|
||
|
effectImage.SetPixel(x,y,color);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
prevStep = step;
|
||
|
|
||
|
ctx.putImageData(effectImage.GetData(), 0, 0);
|
||
|
|
||
|
if (transitionTime >= transitionEffects[curEffect].duration) {
|
||
|
isTransitioning = false;
|
||
|
transitionTime = 0;
|
||
|
transitionStart = null;
|
||
|
transitionEnd = null;
|
||
|
effectImage = null;
|
||
|
prevStep = -1;
|
||
|
|
||
|
if (transitionCompleteCallback != null) {
|
||
|
transitionCompleteCallback();
|
||
|
}
|
||
|
transitionCompleteCallback = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.IsTransitionActive = function() {
|
||
|
return isTransitioning;
|
||
|
}
|
||
|
|
||
|
// todo : should this be part of the constructor?
|
||
|
var transitionCompleteCallback = null;
|
||
|
this.OnTransitionComplete = function(callback) {
|
||
|
if (isTransitioning) { // TODO : safety check necessary?
|
||
|
transitionCompleteCallback = callback;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var transitionEffects = {};
|
||
|
var curEffect = "none";
|
||
|
this.RegisterTransitionEffect = function(name, effect) {
|
||
|
transitionEffects[name] = effect;
|
||
|
}
|
||
|
|
||
|
this.RegisterTransitionEffect("none", {
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : false,
|
||
|
pixelEffectFunc : function() {},
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("fade_w", { // TODO : have it linger on full white briefly?
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 750,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var pixelColorA = delta < 0.5 ? start.Image.GetPixel(pixelX,pixelY) : {r:255,g:255,b:255,a:255};
|
||
|
var pixelColorB = delta < 0.5 ? {r:255,g:255,b:255,a:255} : end.Image.GetPixel(pixelX,pixelY);
|
||
|
|
||
|
delta = delta < 0.5 ? (delta / 0.5) : ((delta - 0.5) / 0.5); // hacky
|
||
|
|
||
|
return PostProcessUtilities.LerpColor(pixelColorA, pixelColorB, delta);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("fade_b", {
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 750,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var pixelColorA = delta < 0.5 ? start.Image.GetPixel(pixelX,pixelY) : {r:0,g:0,b:0,a:255};
|
||
|
var pixelColorB = delta < 0.5 ? {r:0,g:0,b:0,a:255} : end.Image.GetPixel(pixelX,pixelY);
|
||
|
|
||
|
delta = delta < 0.5 ? (delta / 0.5) : ((delta - 0.5) / 0.5); // hacky
|
||
|
|
||
|
return PostProcessUtilities.LerpColor(pixelColorA, pixelColorB, delta);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("wave", {
|
||
|
showPlayerStart : true,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 1500,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var waveDelta = delta < 0.5 ? delta / 0.5 : 1 - ((delta - 0.5) / 0.5);
|
||
|
|
||
|
var offset = (pixelY + (waveDelta * waveDelta * 0.2 * start.Image.Height));
|
||
|
var freq = 4;
|
||
|
var size = 2 + (14 * waveDelta);
|
||
|
pixelX += Math.floor(Math.sin(offset / freq) * size);
|
||
|
|
||
|
if (pixelX < 0) {
|
||
|
pixelX += start.Image.Width;
|
||
|
}
|
||
|
else if (pixelX >= start.Image.Width) {
|
||
|
pixelX -= start.Image.Width;
|
||
|
}
|
||
|
|
||
|
var curImage = delta < 0.5 ? start.Image : end.Image;
|
||
|
return curImage.GetPixel(pixelX,pixelY);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("tunnel", {
|
||
|
showPlayerStart : true,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 1500,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
if (delta <= 0.4) {
|
||
|
var tunnelDelta = 1 - (delta / 0.4);
|
||
|
|
||
|
var xDist = start.PlayerCenter.x - pixelX;
|
||
|
var yDist = start.PlayerCenter.y - pixelY;
|
||
|
var dist = Math.sqrt((xDist * xDist) + (yDist * yDist));
|
||
|
|
||
|
if (dist > start.Image.Width * tunnelDelta) {
|
||
|
return {r:0,g:0,b:0,a:255};
|
||
|
}
|
||
|
else {
|
||
|
return start.Image.GetPixel(pixelX,pixelY);
|
||
|
}
|
||
|
}
|
||
|
else if (delta <= 0.6)
|
||
|
{
|
||
|
return {r:0,g:0,b:0,a:255};
|
||
|
}
|
||
|
else {
|
||
|
var tunnelDelta = (delta - 0.6) / 0.4;
|
||
|
|
||
|
var xDist = end.PlayerCenter.x - pixelX;
|
||
|
var yDist = end.PlayerCenter.y - pixelY;
|
||
|
var dist = Math.sqrt((xDist * xDist) + (yDist * yDist));
|
||
|
|
||
|
if (dist > end.Image.Width * tunnelDelta) {
|
||
|
return {r:0,g:0,b:0,a:255};
|
||
|
}
|
||
|
else {
|
||
|
return end.Image.GetPixel(pixelX,pixelY);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("slide_u", {
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 1000,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var pixelOffset = -1 * Math.floor(start.Image.Height * delta);
|
||
|
var slidePixelY = pixelY + pixelOffset;
|
||
|
|
||
|
var colorDelta = clampLerp(delta, 0.4);
|
||
|
|
||
|
if (slidePixelY >= 0) {
|
||
|
var colorA = start.Image.GetPixel(pixelX,slidePixelY);
|
||
|
var colorB = PostProcessUtilities.GetCorrespondingColorFromPal(colorA,start.Palette,end.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
else {
|
||
|
slidePixelY += start.Image.Height;
|
||
|
var colorB = end.Image.GetPixel(pixelX,slidePixelY);
|
||
|
var colorA = PostProcessUtilities.GetCorrespondingColorFromPal(colorB,end.Palette,start.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("slide_d", {
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 1000,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var pixelOffset = Math.floor(start.Image.Height * delta);
|
||
|
var slidePixelY = pixelY + pixelOffset;
|
||
|
|
||
|
var colorDelta = clampLerp(delta, 0.4);
|
||
|
|
||
|
if (slidePixelY < start.Image.Height) {
|
||
|
var colorA = start.Image.GetPixel(pixelX,slidePixelY);
|
||
|
var colorB = PostProcessUtilities.GetCorrespondingColorFromPal(colorA,start.Palette,end.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
else {
|
||
|
slidePixelY -= start.Image.Height;
|
||
|
var colorB = end.Image.GetPixel(pixelX,slidePixelY);
|
||
|
var colorA = PostProcessUtilities.GetCorrespondingColorFromPal(colorB,end.Palette,start.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("slide_l", {
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 1000,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var pixelOffset = -1 * Math.floor(start.Image.Width * delta);
|
||
|
var slidePixelX = pixelX + pixelOffset;
|
||
|
|
||
|
var colorDelta = clampLerp(delta, 0.4);
|
||
|
|
||
|
if (slidePixelX >= 0) {
|
||
|
var colorA = start.Image.GetPixel(slidePixelX,pixelY);
|
||
|
var colorB = PostProcessUtilities.GetCorrespondingColorFromPal(colorA,start.Palette,end.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
else {
|
||
|
slidePixelX += start.Image.Width;
|
||
|
var colorB = end.Image.GetPixel(slidePixelX,pixelY);
|
||
|
var colorA = PostProcessUtilities.GetCorrespondingColorFromPal(colorB,end.Palette,start.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.RegisterTransitionEffect("slide_r", {
|
||
|
showPlayerStart : false,
|
||
|
showPlayerEnd : true,
|
||
|
duration : 1000,
|
||
|
pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
var pixelOffset = Math.floor(start.Image.Width * delta);
|
||
|
var slidePixelX = pixelX + pixelOffset;
|
||
|
|
||
|
var colorDelta = clampLerp(delta, 0.4);
|
||
|
|
||
|
if (slidePixelX < start.Image.Width) {
|
||
|
var colorA = start.Image.GetPixel(slidePixelX,pixelY);
|
||
|
var colorB = PostProcessUtilities.GetCorrespondingColorFromPal(colorA,start.Palette,end.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
else {
|
||
|
slidePixelX -= start.Image.Width;
|
||
|
var colorB = end.Image.GetPixel(slidePixelX,pixelY);
|
||
|
var colorA = PostProcessUtilities.GetCorrespondingColorFromPal(colorB,end.Palette,start.Palette);
|
||
|
var colorLerped = PostProcessUtilities.LerpColor(colorA, colorB, colorDelta);
|
||
|
return colorLerped;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function clampLerp(deltaIn, clampDuration) {
|
||
|
var clampOffset = (1.0 - clampDuration) / 2;
|
||
|
var deltaOut = Math.min(clampDuration, Math.max(0.0, deltaIn - clampOffset)) / clampDuration;
|
||
|
return deltaOut;
|
||
|
}
|
||
|
|
||
|
// TODO : WIP
|
||
|
// this.RegisterTransitionEffect("fuzz", {
|
||
|
// showPlayerStart : true,
|
||
|
// showPlayerEnd : true,
|
||
|
// duration : 1500,
|
||
|
// pixelEffectFunc : function(start,end,pixelX,pixelY,delta) {
|
||
|
// var curImage = delta <= 0.5 ? start : end;
|
||
|
// var sampleSize = delta <= 0.5 ? (2 + Math.floor(14 * (delta/0.5))) : (16 - Math.floor(14 * ((delta-0.5)/0.5)));
|
||
|
|
||
|
// var palIndex = 0;
|
||
|
|
||
|
// var sampleX = Math.floor(pixelX / sampleSize) * sampleSize;
|
||
|
// var sampleY = Math.floor(pixelY / sampleSize) * sampleSize;
|
||
|
|
||
|
// var frameState = transitionEffects["fuzz"].frameState;
|
||
|
|
||
|
// if (frameState.time != delta) {
|
||
|
// frameState.time = delta;
|
||
|
// frameState.preCalcSampleValues = {};
|
||
|
// }
|
||
|
|
||
|
// if (frameState.preCalcSampleValues[[sampleX,sampleY]]) {
|
||
|
// palIndex = frameState.preCalcSampleValues[[sampleX,sampleY]];
|
||
|
// }
|
||
|
// else {
|
||
|
// var paletteCount = {};
|
||
|
// var foregroundValue = 1.0;
|
||
|
// var backgroundValue = 0.4;
|
||
|
// for (var y = sampleY; y < sampleY + sampleSize; y++) {
|
||
|
// for (var x = sampleX; x < sampleX + sampleSize; x++) {
|
||
|
// var color = curImage.Image.GetPixel(x,y)
|
||
|
// var palIndex = PostProcessUtilities.GetColorPalIndex(color,curImage.Palette);
|
||
|
// if (palIndex != -1) {
|
||
|
// if (paletteCount[palIndex]) {
|
||
|
// paletteCount[palIndex] += (palIndex != 0) ? foregroundValue : backgroundValue;
|
||
|
// }
|
||
|
// else {
|
||
|
// paletteCount[palIndex] = (palIndex != 0) ? foregroundValue : backgroundValue;
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
// var maxCount = 0;
|
||
|
// for (var i in paletteCount) {
|
||
|
// if (paletteCount[i] > maxCount) {
|
||
|
// palIndex = i;
|
||
|
// maxCount = paletteCount[i];
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
// frameState.preCalcSampleValues[[sampleX,sampleY]] = palIndex;
|
||
|
// }
|
||
|
|
||
|
// return PostProcessUtilities.GetPalColor(curImage.Palette,palIndex);
|
||
|
// },
|
||
|
// frameState : { // ok this is hacky but it's for performance ok
|
||
|
// time : -1,
|
||
|
// preCalcSampleValues : {}
|
||
|
// }
|
||
|
// });
|
||
|
}; // TransitionManager()
|
||
|
|
||
|
|
||
|
// TODO : extract the scale variable so it can be changed?
|
||
|
var PostProcessUtilities = {
|
||
|
SamplePixelColor : function(image,x,y) {
|
||
|
var pixelIndex = (y * scale * image.width * 4) + (x * scale * 4);
|
||
|
var r = image.data[pixelIndex + 0];
|
||
|
var g = image.data[pixelIndex + 1];
|
||
|
var b = image.data[pixelIndex + 2];
|
||
|
var a = image.data[pixelIndex + 3];
|
||
|
return { r:r, g:g, b:b, a:a };
|
||
|
},
|
||
|
SetPixelColor : function(image,x,y,colorRgba) {
|
||
|
for (var yDelta = 0; yDelta < scale; yDelta++) {
|
||
|
for (var xDelta = 0; xDelta < scale; xDelta++) {
|
||
|
var pixelIndex = (((y * scale) + yDelta) * image.width * 4) + (((x * scale) + xDelta) * 4);
|
||
|
image.data[pixelIndex + 0] = colorRgba.r;
|
||
|
image.data[pixelIndex + 1] = colorRgba.g;
|
||
|
image.data[pixelIndex + 2] = colorRgba.b;
|
||
|
image.data[pixelIndex + 3] = colorRgba.a;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
LerpColor : function(colorA,colorB,t) {
|
||
|
// TODO: move to color_util.js?
|
||
|
return {
|
||
|
r : colorA.r + ((colorB.r - colorA.r) * t),
|
||
|
g : colorA.g + ((colorB.g - colorA.g) * t),
|
||
|
b : colorA.b + ((colorB.b - colorA.b) * t),
|
||
|
a : colorA.a + ((colorB.a - colorA.a) * t),
|
||
|
};
|
||
|
},
|
||
|
GetColorPalIndex : function(colorIn,curPal) {
|
||
|
var colorIndex = -1;
|
||
|
|
||
|
for (var i = 0; i < curPal.length; i++) {
|
||
|
if (colorIn.r == curPal[i][0] && colorIn.g == curPal[i][1] && colorIn.b == curPal[i][2]) {
|
||
|
colorIndex = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return colorIndex;
|
||
|
},
|
||
|
GetPalColor : function(palette,index) {
|
||
|
return { r: palette[index][0], g: palette[index][1], b: palette[index][2], a: 255 }
|
||
|
},
|
||
|
GetCorrespondingColorFromPal : function(colorIn,curPal,otherPal) { // this is kind of hacky!
|
||
|
var colorIndex = PostProcessUtilities.GetColorPalIndex(colorIn,curPal);
|
||
|
|
||
|
if (colorIndex >= 0 && colorIndex <= otherPal.length) {
|
||
|
return PostProcessUtilities.GetPalColor(otherPal,colorIndex);
|
||
|
}
|
||
|
else {
|
||
|
return colorIn;
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
|
||
|
var PostProcessImage = function(imageData) {
|
||
|
this.Width = imageData.width / scale;
|
||
|
this.Height = imageData.height / scale;
|
||
|
|
||
|
this.GetPixel = function(x,y) {
|
||
|
return PostProcessUtilities.SamplePixelColor(imageData,x,y);
|
||
|
};
|
||
|
|
||
|
this.SetPixel = function(x,y,colorRgba) {
|
||
|
PostProcessUtilities.SetPixelColor(imageData,x,y,colorRgba);
|
||
|
};
|
||
|
|
||
|
this.GetData = function() {
|
||
|
return imageData;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var TransitionInfo = function(image, palette, playerX, playerY) {
|
||
|
this.Image = image;
|
||
|
this.Palette = palette;
|
||
|
this.PlayerTilePos = { x: playerX, y: playerY };
|
||
|
this.PlayerCenter = { x: Math.floor((playerX * tilesize) + (tilesize / 2)), y: Math.floor((playerY * tilesize) + (tilesize / 2)) };
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
/*
|
||
|
TODO:
|
||
|
- can I simplify this more now that I've removed the external resources stuff?
|
||
|
*/
|
||
|
|
||
|
function FontManager(packagedFontNames) {
|
||
|
|
||
|
var self = this;
|
||
|
|
||
|
var fontExtension = ".bitsyfont";
|
||
|
this.GetExtension = function() {
|
||
|
return fontExtension;
|
||
|
}
|
||
|
|
||
|
// place to store font data
|
||
|
var fontResources = {};
|
||
|
|
||
|
// load fonts from the editor
|
||
|
if (packagedFontNames != undefined && packagedFontNames != null && packagedFontNames.length > 0
|
||
|
&& Resources != undefined && Resources != null) {
|
||
|
|
||
|
for (var i = 0; i < packagedFontNames.length; i++) {
|
||
|
var filename = packagedFontNames[i];
|
||
|
fontResources[filename] = Resources[filename];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// manually add resource
|
||
|
this.AddResource = function(filename, fontdata) {
|
||
|
fontResources[filename] = fontdata;
|
||
|
}
|
||
|
|
||
|
this.ContainsResource = function(filename) {
|
||
|
return fontResources[filename] != null;
|
||
|
}
|
||
|
|
||
|
function GetData(fontName) {
|
||
|
return fontResources[fontName + fontExtension];
|
||
|
}
|
||
|
this.GetData = GetData;
|
||
|
|
||
|
function Create(fontData) {
|
||
|
return new Font(fontData);
|
||
|
}
|
||
|
this.Create = Create;
|
||
|
|
||
|
this.Get = function(fontName) {
|
||
|
var fontData = self.GetData(fontName);
|
||
|
return self.Create(fontData);
|
||
|
}
|
||
|
|
||
|
function Font(fontData) {
|
||
|
var name = "unknown";
|
||
|
var width = 6; // default size so if you have NO font or an invalid font it displays boxes
|
||
|
var height = 8;
|
||
|
var chardata = {};
|
||
|
|
||
|
// create invalid char data at default size in case the font is missing
|
||
|
var invalidCharData = {};
|
||
|
updateInvalidCharData();
|
||
|
|
||
|
this.getName = function() {
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
this.getData = function() {
|
||
|
return chardata;
|
||
|
}
|
||
|
|
||
|
this.getWidth = function() {
|
||
|
return width;
|
||
|
}
|
||
|
|
||
|
this.getHeight = function() {
|
||
|
return height;
|
||
|
}
|
||
|
|
||
|
this.hasChar = function(char) {
|
||
|
var codepoint = char.charCodeAt(0);
|
||
|
return chardata[codepoint] != null;
|
||
|
}
|
||
|
|
||
|
this.getChar = function(char) {
|
||
|
|
||
|
var codepoint = char.charCodeAt(0);
|
||
|
|
||
|
if (chardata[codepoint] != null) {
|
||
|
return chardata[codepoint];
|
||
|
}
|
||
|
else {
|
||
|
return invalidCharData;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.allCharCodes = function() {
|
||
|
var codeList = [];
|
||
|
for (var code in chardata) {
|
||
|
codeList.push(code);
|
||
|
}
|
||
|
return codeList;
|
||
|
}
|
||
|
|
||
|
function createCharData() {
|
||
|
return {
|
||
|
width: width,
|
||
|
height: height,
|
||
|
offset: {
|
||
|
x: 0,
|
||
|
y: 0
|
||
|
},
|
||
|
spacing: width,
|
||
|
data: [],
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function updateInvalidCharData() {
|
||
|
invalidCharData = createCharData();
|
||
|
for (var y = 0; y < height; y++) {
|
||
|
for (var x = 0; x < width; x++) {
|
||
|
if (x < width-1 && y < height-1) {
|
||
|
invalidCharData.data.push(1);
|
||
|
}
|
||
|
else {
|
||
|
invalidCharData.data.push(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function parseFont(fontData) {
|
||
|
if (fontData == null) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var lines = fontData.split("\n");
|
||
|
|
||
|
var isReadingChar = false;
|
||
|
var isReadingCharProperties = false;
|
||
|
var curCharLineCount = 0;
|
||
|
var curCharCode = 0;
|
||
|
|
||
|
for (var i = 0; i < lines.length; i++) {
|
||
|
var line = lines[i];
|
||
|
|
||
|
if (line[0] === "#") {
|
||
|
continue; // skip comment lines
|
||
|
}
|
||
|
|
||
|
if (!isReadingChar) {
|
||
|
// READING NON CHARACTER DATA LINE
|
||
|
var args = line.split(" ");
|
||
|
if (args[0] == "FONT") {
|
||
|
name = args[1];
|
||
|
}
|
||
|
else if (args[0] == "SIZE") {
|
||
|
width = parseInt(args[1]);
|
||
|
height = parseInt(args[2]);
|
||
|
}
|
||
|
else if (args[0] == "CHAR") {
|
||
|
isReadingChar = true;
|
||
|
isReadingCharProperties = true;
|
||
|
|
||
|
curCharLineCount = 0;
|
||
|
curCharCode = parseInt(args[1]);
|
||
|
chardata[curCharCode] = createCharData();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// CHAR PROPERTIES
|
||
|
if (isReadingCharProperties) {
|
||
|
var args = line.split(" ");
|
||
|
if (args[0].indexOf("CHAR_") == 0) { // Sub-properties start with "CHAR_"
|
||
|
if (args[0] == "CHAR_SIZE") {
|
||
|
// Custom character size - overrides the default character size for the font
|
||
|
chardata[curCharCode].width = parseInt(args[1]);
|
||
|
chardata[curCharCode].height = parseInt(args[2]);
|
||
|
chardata[curCharCode].spacing = parseInt(args[1]); // HACK : assumes CHAR_SIZE is always declared first
|
||
|
}
|
||
|
else if (args[0] == "CHAR_OFFSET") {
|
||
|
// Character offset - shift the origin of the character on the X or Y axis
|
||
|
chardata[curCharCode].offset.x = parseInt(args[1]);
|
||
|
chardata[curCharCode].offset.y = parseInt(args[2]);
|
||
|
}
|
||
|
else if (args[0] == "CHAR_SPACING") {
|
||
|
// Character spacing:
|
||
|
// specify total horizontal space taken up by the character
|
||
|
// lets chars take up more or less space on a line than its bitmap does
|
||
|
chardata[curCharCode].spacing = parseInt(args[1]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
isReadingCharProperties = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// CHAR DATA
|
||
|
if (!isReadingCharProperties) {
|
||
|
// READING CHARACTER DATA LINE
|
||
|
for (var j = 0; j < chardata[curCharCode].width; j++)
|
||
|
{
|
||
|
chardata[curCharCode].data.push( parseInt(line[j]) );
|
||
|
}
|
||
|
|
||
|
curCharLineCount++;
|
||
|
if (curCharLineCount >= height) {
|
||
|
isReadingChar = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// re-init invalid character box at the actual font size once it's loaded
|
||
|
updateInvalidCharData();
|
||
|
}
|
||
|
|
||
|
parseFont(fontData);
|
||
|
}
|
||
|
|
||
|
} // FontManager
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
function Script() {
|
||
|
|
||
|
this.CreateInterpreter = function() {
|
||
|
return new Interpreter();
|
||
|
};
|
||
|
|
||
|
this.CreateUtils = function() {
|
||
|
return new Utils();
|
||
|
};
|
||
|
|
||
|
var Interpreter = function() {
|
||
|
var env = new Environment();
|
||
|
var parser = new Parser( env );
|
||
|
|
||
|
this.SetDialogBuffer = function(buffer) { env.SetDialogBuffer( buffer ); };
|
||
|
|
||
|
// TODO -- maybe this should return a string instead othe actual script??
|
||
|
this.Compile = function(scriptName, scriptStr) {
|
||
|
// console.log("COMPILE");
|
||
|
var script = parser.Parse(scriptStr, scriptName);
|
||
|
env.SetScript(scriptName, script);
|
||
|
}
|
||
|
this.Run = function(scriptName, exitHandler, objectContext) { // Runs pre-compiled script
|
||
|
var localEnv = new LocalEnvironment(env);
|
||
|
|
||
|
if (objectContext) {
|
||
|
localEnv.SetObject(objectContext); // PROTO : should this be folded into the constructor?
|
||
|
}
|
||
|
|
||
|
var script = env.GetScript(scriptName);
|
||
|
|
||
|
script.Eval( localEnv, function(result) { OnScriptReturn(localEnv, exitHandler); } );
|
||
|
}
|
||
|
this.Interpret = function(scriptStr, exitHandler, objectContext) { // Compiles and runs code immediately
|
||
|
// console.log("INTERPRET");
|
||
|
var localEnv = new LocalEnvironment(env);
|
||
|
|
||
|
if (objectContext) {
|
||
|
localEnv.SetObject(objectContext); // PROTO : should this be folded into the constructor?
|
||
|
}
|
||
|
|
||
|
var script = parser.Parse(scriptStr, "anonymous");
|
||
|
script.Eval( localEnv, function(result) { OnScriptReturn(localEnv, exitHandler); } );
|
||
|
}
|
||
|
this.HasScript = function(name) { return env.HasScript(name); };
|
||
|
|
||
|
this.ResetEnvironment = function() {
|
||
|
env = new Environment();
|
||
|
parser = new Parser( env );
|
||
|
}
|
||
|
|
||
|
this.Parse = function(scriptStr, rootId) { // parses a script but doesn't save it
|
||
|
return parser.Parse(scriptStr, rootId);
|
||
|
}
|
||
|
|
||
|
// TODO : add back in if needed later...
|
||
|
// this.CompatibilityParse = function(scriptStr, compatibilityFlags) {
|
||
|
// env.compatibilityFlags = compatibilityFlags;
|
||
|
|
||
|
// var result = parser.Parse(scriptStr);
|
||
|
|
||
|
// delete env.compatibilityFlags;
|
||
|
|
||
|
// return result;
|
||
|
// }
|
||
|
|
||
|
this.Eval = function(scriptTree, exitHandler) { // runs a script stored externally
|
||
|
var localEnv = new LocalEnvironment(env); // TODO : does this need an object context?
|
||
|
scriptTree.Eval(
|
||
|
localEnv,
|
||
|
function(result) {
|
||
|
OnScriptReturn(result, exitHandler);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function OnScriptReturn(result, exitHandler) {
|
||
|
if (exitHandler != null) {
|
||
|
exitHandler(result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.CreateExpression = function(expStr) {
|
||
|
return parser.CreateExpression(expStr);
|
||
|
}
|
||
|
|
||
|
this.SetVariable = function(name,value,useHandler) {
|
||
|
env.SetVariable(name,value,useHandler);
|
||
|
}
|
||
|
|
||
|
this.DeleteVariable = function(name,useHandler) {
|
||
|
env.DeleteVariable(name,useHandler);
|
||
|
}
|
||
|
this.HasVariable = function(name) {
|
||
|
return env.HasVariable(name);
|
||
|
}
|
||
|
|
||
|
this.SetOnVariableChangeHandler = function(onVariableChange) {
|
||
|
env.SetOnVariableChangeHandler(onVariableChange);
|
||
|
}
|
||
|
this.GetVariableNames = function() {
|
||
|
return env.GetVariableNames();
|
||
|
}
|
||
|
this.GetVariable = function(name) {
|
||
|
return env.GetVariable(name);
|
||
|
}
|
||
|
|
||
|
function DebugVisualizeScriptTree(scriptTree) {
|
||
|
var printVisitor = {
|
||
|
Visit : function(node,depth) {
|
||
|
console.log("-".repeat(depth) + "- " + node.ToString());
|
||
|
},
|
||
|
};
|
||
|
|
||
|
scriptTree.VisitAll( printVisitor );
|
||
|
}
|
||
|
|
||
|
this.DebugVisualizeScriptTree = DebugVisualizeScriptTree;
|
||
|
|
||
|
this.DebugVisualizeScript = function(scriptName) {
|
||
|
DebugVisualizeScriptTree(env.GetScript(scriptName));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
var Utils = function() {
|
||
|
// for editor ui
|
||
|
this.CreateDialogBlock = function(children,doIndentFirstLine) {
|
||
|
if (doIndentFirstLine === undefined) {
|
||
|
doIndentFirstLine = true;
|
||
|
}
|
||
|
|
||
|
var block = new DialogBlockNode(doIndentFirstLine);
|
||
|
|
||
|
for (var i = 0; i < children.length; i++) {
|
||
|
block.AddChild(children[i]);
|
||
|
}
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.CreateOptionBlock = function() {
|
||
|
var block = new DialogBlockNode(false);
|
||
|
block.AddChild(new FuncNode("print", [new LiteralNode(" ")]));
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.CreateItemConditionPair = function() {
|
||
|
var itemFunc = this.CreateFunctionBlock("item", ["0"]);
|
||
|
var condition = new ExpNode("==", itemFunc, new LiteralNode(1));
|
||
|
var result = new DialogBlockNode(true);
|
||
|
result.AddChild(new FuncNode("print", [new LiteralNode(" ")]));
|
||
|
var conditionPair = new ConditionPairNode(condition, result);
|
||
|
return conditionPair;
|
||
|
}
|
||
|
|
||
|
this.CreateVariableConditionPair = function() {
|
||
|
var varNode = this.CreateVariableNode("a");
|
||
|
var condition = new ExpNode("==", varNode, new LiteralNode(1));
|
||
|
var result = new DialogBlockNode(true);
|
||
|
result.AddChild(new FuncNode("print", [new LiteralNode(" ")]));
|
||
|
var conditionPair = new ConditionPairNode(condition, result);
|
||
|
return conditionPair;
|
||
|
}
|
||
|
|
||
|
this.CreateDefaultConditionPair = function() {
|
||
|
var condition = this.CreateElseNode();
|
||
|
var result = new DialogBlockNode(true);
|
||
|
result.AddChild(new FuncNode("print", [new LiteralNode(" ")]));
|
||
|
var conditionPair = new ConditionPairNode(condition, result);
|
||
|
return conditionPair;
|
||
|
}
|
||
|
|
||
|
this.CreateEmptyPrintFunc = function() {
|
||
|
return new FuncNode("print", [new LiteralNode("...")]);
|
||
|
}
|
||
|
|
||
|
this.CreateFunctionBlock = function(name, initParamValues) {
|
||
|
var parameters = [];
|
||
|
for (var i = 0; i < initParamValues.length; i++) {
|
||
|
parameters.push(new LiteralNode(initParamValues[i]));
|
||
|
}
|
||
|
|
||
|
var node = new FuncNode(name, parameters);
|
||
|
var block = new CodeBlockNode();
|
||
|
block.AddChild(node);
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
// TODO : rename ParseStringToLiteralNode?
|
||
|
this.CreateLiteralNode = function(str) {
|
||
|
if (str === "true") {
|
||
|
return new LiteralNode(true);
|
||
|
}
|
||
|
else if (str === "false") {
|
||
|
return new LiteralNode(false);
|
||
|
}
|
||
|
else if (!isNaN(parseFloat(str))) {
|
||
|
return new LiteralNode(parseFloat(str));
|
||
|
}
|
||
|
else {
|
||
|
return new LiteralNode(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.CreateVariableNode = function(variableName) {
|
||
|
return new VarNode(variableName);
|
||
|
}
|
||
|
|
||
|
this.CreatePropertyNode = function(propertyName, literalValue) {
|
||
|
var varNode = new VarNode(propertyName);
|
||
|
var valNode = new LiteralNode(literalValue);
|
||
|
var node = new FuncNode("property", [varNode, valNode]);
|
||
|
var block = new CodeBlockNode();
|
||
|
block.AddChild(node);
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.CreateElseNode = function() {
|
||
|
return new ElseNode();
|
||
|
}
|
||
|
|
||
|
this.CreateStringLiteralNode = function(str) {
|
||
|
return new LiteralNode(str);
|
||
|
}
|
||
|
|
||
|
// TODO : need to split up code & dialog blocks :|
|
||
|
this.CreateCodeBlock = function() {
|
||
|
return new CodeBlockNode();
|
||
|
}
|
||
|
|
||
|
this.ChangeSequenceType = function(oldSequence, type) {
|
||
|
if(type === "sequence") {
|
||
|
return new SequenceNode(oldSequence.children);
|
||
|
}
|
||
|
else if(type === "cycle") {
|
||
|
return new CycleNode(oldSequence.children);
|
||
|
}
|
||
|
else if(type === "shuffle") {
|
||
|
return new ShuffleNode(oldSequence.children);
|
||
|
}
|
||
|
return oldSequence;
|
||
|
}
|
||
|
|
||
|
this.CreateSequenceBlock = function() {
|
||
|
var option1 = new DialogBlockNode( false /*doIndentFirstLine*/ );
|
||
|
option1.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var option2 = new DialogBlockNode( false /*doIndentFirstLine*/ );
|
||
|
option2.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var sequence = new SequenceNode( [ option1, option2 ] );
|
||
|
var block = new CodeBlockNode();
|
||
|
block.AddChild( sequence );
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.CreateCycleBlock = function() {
|
||
|
var option1 = new DialogBlockNode( false /*doIndentFirstLine*/ );
|
||
|
option1.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var option2 = new DialogBlockNode( false /*doIndentFirstLine*/ );
|
||
|
option2.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var sequence = new CycleNode( [ option1, option2 ] );
|
||
|
var block = new CodeBlockNode();
|
||
|
block.AddChild( sequence );
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.CreateShuffleBlock = function() {
|
||
|
var option1 = new DialogBlockNode( false /*doIndentFirstLine*/ );
|
||
|
option1.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var option2 = new DialogBlockNode( false /*doIndentFirstLine*/ );
|
||
|
option2.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var sequence = new ShuffleNode( [ option1, option2 ] );
|
||
|
var block = new CodeBlockNode();
|
||
|
block.AddChild( sequence );
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.CreateIfBlock = function() {
|
||
|
var leftNode = new CodeBlockNode();
|
||
|
leftNode.AddChild( new FuncNode("item", [new LiteralNode("0")] ) );
|
||
|
var rightNode = new LiteralNode( 1 );
|
||
|
var condition1 = new ExpNode("==", leftNode, rightNode );
|
||
|
|
||
|
var condition2 = new ElseNode();
|
||
|
|
||
|
var result1 = new DialogBlockNode();
|
||
|
result1.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var result2 = new DialogBlockNode();
|
||
|
result2.AddChild(new FuncNode("print", [new LiteralNode("...")]));
|
||
|
|
||
|
var ifNode = new IfNode( [ condition1, condition2 ], [ result1, result2 ] );
|
||
|
var block = new CodeBlockNode();
|
||
|
block.AddChild( ifNode );
|
||
|
return block;
|
||
|
}
|
||
|
|
||
|
this.ReadDialogScript = function(lines, i) {
|
||
|
var scriptStr = "";
|
||
|
if (lines[i] === Sym.DialogOpen) {
|
||
|
scriptStr += lines[i] + "\n";
|
||
|
i++;
|
||
|
while(lines[i] != Sym.DialogClose) {
|
||
|
scriptStr += lines[i] + "\n";
|
||
|
i++;
|
||
|
}
|
||
|
scriptStr += lines[i];
|
||
|
i++;
|
||
|
}
|
||
|
else {
|
||
|
scriptStr += lines[i];
|
||
|
i++;
|
||
|
}
|
||
|
return { script:scriptStr, index:i };
|
||
|
}
|
||
|
|
||
|
// TODO this.ReadCodeScript (reads through code open and close symbols), and this.ReadScript
|
||
|
|
||
|
this.EnsureDialogBlockFormat = function(dialogStr) {
|
||
|
// TODO -- what if it's already enclosed in dialog symbols??
|
||
|
if(dialogStr.indexOf('\n') > -1) {
|
||
|
dialogStr = Sym.DialogOpen + "\n" + dialogStr + "\n" + Sym.DialogClose;
|
||
|
}
|
||
|
return dialogStr;
|
||
|
}
|
||
|
|
||
|
this.RemoveDialogBlockFormat = function(source) {
|
||
|
var sourceLines = source.split("\n");
|
||
|
var dialogStr = "";
|
||
|
if(sourceLines[0] === Sym.DialogOpen) {
|
||
|
// multi line
|
||
|
var i = 1;
|
||
|
while (i < sourceLines.length && sourceLines[i] != Sym.DialogClose) {
|
||
|
dialogStr += sourceLines[i] + (sourceLines[i+1] != Sym.DialogClose ? '\n' : '');
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// single line
|
||
|
dialogStr = source;
|
||
|
}
|
||
|
return dialogStr;
|
||
|
}
|
||
|
|
||
|
this.SerializeDialogNodeList = function(nodeList) {
|
||
|
var tempBlock = new DialogBlockNode(false);
|
||
|
// set children directly to avoid breaking the parenting chain for this temp operation
|
||
|
tempBlock.children = nodeList;
|
||
|
return tempBlock.Serialize();
|
||
|
}
|
||
|
|
||
|
this.GetOperatorList = function() {
|
||
|
return [Sym.Set].concat(Sym.Operators);
|
||
|
}
|
||
|
|
||
|
this.IsInlineCode = function(node) {
|
||
|
return isInlineCode(node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* BUILT-IN FUNCTIONS */ // TODO: better way to encapsulate these?
|
||
|
function deprecatedFunc(environment,parameters,onReturn) {
|
||
|
console.log("BITSY SCRIPT WARNING: Tried to use deprecated function");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function printFunc(environment, parameters, onReturn) {
|
||
|
if (parameters[0] != undefined && parameters[0] != null) {
|
||
|
var textStr = "" + parameters[0];
|
||
|
environment.GetDialogBuffer().AddText(textStr);
|
||
|
environment.GetDialogBuffer().AddScriptReturn(function() { onReturn(null); });
|
||
|
}
|
||
|
else {
|
||
|
onReturn(null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function linebreakFunc(environment, parameters, onReturn) {
|
||
|
// console.log("LINEBREAK FUNC");
|
||
|
environment.GetDialogBuffer().AddLinebreak();
|
||
|
environment.GetDialogBuffer().AddScriptReturn(function() { onReturn(null); });
|
||
|
}
|
||
|
|
||
|
function pagebreakFunc(environment, parameters, onReturn) {
|
||
|
environment.GetDialogBuffer().AddPagebreak(function() { onReturn(null); });
|
||
|
}
|
||
|
|
||
|
function printDrawingFunc(environment, parameters, onReturn) {
|
||
|
var drawingId = parameters[0];
|
||
|
environment.GetDialogBuffer().AddDrawing(drawingId);
|
||
|
environment.GetDialogBuffer().AddScriptReturn(function() { onReturn(null); });
|
||
|
}
|
||
|
|
||
|
function printSpriteFunc(environment,parameters,onReturn) {
|
||
|
var spriteId = parameters[0];
|
||
|
if(names.sprite.has(spriteId)) spriteId = names.sprite.get(spriteId); // id is actually a name
|
||
|
var drawingId = sprite[spriteId].drw;
|
||
|
printDrawingFunc(environment, [drawingId], onReturn);
|
||
|
}
|
||
|
|
||
|
function printTileFunc(environment,parameters,onReturn) {
|
||
|
var tileId = parameters[0];
|
||
|
if(names.tile.has(tileId)) tileId = names.tile.get(tileId); // id is actually a name
|
||
|
var drawingId = tile[tileId].drw;
|
||
|
printDrawingFunc(environment, [drawingId], onReturn);
|
||
|
}
|
||
|
|
||
|
function printItemFunc(environment,parameters,onReturn) {
|
||
|
var itemId = parameters[0];
|
||
|
if(names.item.has(itemId)) itemId = names.item.get(itemId); // id is actually a name
|
||
|
var drawingId = item[itemId].drw;
|
||
|
printDrawingFunc(environment, [drawingId], onReturn);
|
||
|
}
|
||
|
|
||
|
function printFontFunc(environment, parameters, onReturn) {
|
||
|
var allCharacters = "";
|
||
|
var font = fontManager.Get( fontName );
|
||
|
var codeList = font.allCharCodes();
|
||
|
for (var i = 0; i < codeList.length; i++) {
|
||
|
allCharacters += String.fromCharCode(codeList[i]) + " ";
|
||
|
}
|
||
|
printFunc(environment, [allCharacters], onReturn);
|
||
|
}
|
||
|
|
||
|
function itemFunc(environment,parameters,onReturn) {
|
||
|
var itemId = parameters[0];
|
||
|
|
||
|
if (names.item.has(itemId)) {
|
||
|
// id is actually a name
|
||
|
itemId = names.item.get(itemId);
|
||
|
}
|
||
|
|
||
|
var curItemCount = player().inventory[itemId] ? player().inventory[itemId] : 0;
|
||
|
|
||
|
if (parameters.length > 1) {
|
||
|
// TODO : is it a good idea to force inventory to be >= 0?
|
||
|
player().inventory[itemId] = Math.max(0, parseInt(parameters[1]));
|
||
|
curItemCount = player().inventory[itemId];
|
||
|
|
||
|
if (onInventoryChanged != null) {
|
||
|
onInventoryChanged(itemId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onReturn(curItemCount);
|
||
|
}
|
||
|
|
||
|
function addOrRemoveTextEffect(environment,name) {
|
||
|
if( environment.GetDialogBuffer().HasTextEffect(name) )
|
||
|
environment.GetDialogBuffer().RemoveTextEffect(name);
|
||
|
else
|
||
|
environment.GetDialogBuffer().AddTextEffect(name);
|
||
|
}
|
||
|
|
||
|
function rainbowFunc(environment,parameters,onReturn) {
|
||
|
addOrRemoveTextEffect(environment,"rbw");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
// TODO : should the colors use a parameter instead of special names?
|
||
|
function color1Func(environment,parameters,onReturn) {
|
||
|
addOrRemoveTextEffect(environment,"clr1");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function color2Func(environment,parameters,onReturn) {
|
||
|
addOrRemoveTextEffect(environment,"clr2");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function color3Func(environment,parameters,onReturn) {
|
||
|
addOrRemoveTextEffect(environment,"clr3");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function wavyFunc(environment,parameters,onReturn) {
|
||
|
addOrRemoveTextEffect(environment,"wvy");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function shakyFunc(environment,parameters,onReturn) {
|
||
|
addOrRemoveTextEffect(environment,"shk");
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function propertyFunc(environment, parameters, onReturn) {
|
||
|
var outValue = null;
|
||
|
|
||
|
if (parameters.length > 0 && parameters[0]) {
|
||
|
var propertyName = parameters[0];
|
||
|
|
||
|
if (environment.HasProperty(propertyName)) {
|
||
|
// TODO : in a future update I can handle the case of initializing a new property
|
||
|
// after which we can move this block outside the HasProperty check
|
||
|
if (parameters.length > 1) {
|
||
|
var inValue = parameters[1];
|
||
|
environment.SetProperty(propertyName, inValue);
|
||
|
}
|
||
|
|
||
|
outValue = environment.GetProperty(propertyName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
console.log("PROPERTY! " + propertyName + " " + outValue);
|
||
|
|
||
|
onReturn(outValue);
|
||
|
}
|
||
|
|
||
|
function endFunc(environment,parameters,onReturn) {
|
||
|
isEnding = true;
|
||
|
isNarrating = true;
|
||
|
dialogRenderer.SetCentered(true);
|
||
|
onReturn(null);
|
||
|
}
|
||
|
|
||
|
function exitFunc(environment,parameters,onReturn) {
|
||
|
var destRoom = parameters[0];
|
||
|
|
||
|
if (names.room.has(destRoom)) {
|
||
|
// it's a name, not an id! (note: these could cause trouble if people names things weird)
|
||
|
destRoom = names.room.get(destRoom);
|
||
|
}
|
||
|
|
||
|
var destX = parseInt(parameters[1]);
|
||
|
var destY = parseInt(parameters[2]);
|
||
|
|
||
|
if (parameters.length >= 4) {
|
||
|
var transitionEffect = parameters[3];
|
||
|
|
||
|
transition.BeginTransition(
|
||
|
player().room,
|
||
|
player().x,
|
||
|
player().y,
|
||
|
destRoom,
|
||
|
destX,
|
||
|
destY,
|
||
|
transitionEffect);
|
||
|
transition.UpdateTransition(0);
|
||
|
}
|
||
|
|
||
|
player().room = destRoom;
|
||
|
player().x = destX;
|
||
|
player().y = destY;
|
||
|
curRoom = destRoom;
|
||
|
initRoom(curRoom);
|
||
|
|
||
|
// TODO : this doesn't play nice with pagebreak because it thinks the dialog is finished!
|
||
|
if (transition.IsTransitionActive()) {
|
||
|
transition.OnTransitionComplete(function() { onReturn(null); });
|
||
|
}
|
||
|
else {
|
||
|
onReturn(null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* BUILT-IN OPERATORS */
|
||
|
function setExp(environment,left,right,onReturn) {
|
||
|
// console.log("SET " + left.name);
|
||
|
|
||
|
if(left.type != "variable") {
|
||
|
// not a variable! return null and hope for the best D:
|
||
|
onReturn( null );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
right.Eval(environment,function(rVal) {
|
||
|
environment.SetVariable( left.name, rVal );
|
||
|
// console.log("VAL " + environment.GetVariable( left.name ) );
|
||
|
left.Eval(environment,function(lVal) {
|
||
|
onReturn( lVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function equalExp(environment,left,right,onReturn) {
|
||
|
// console.log("EVAL EQUAL");
|
||
|
// console.log(left);
|
||
|
// console.log(right);
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal === rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function greaterExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal > rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function lessExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal < rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function greaterEqExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal >= rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function lessEqExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal <= rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function multExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal * rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function divExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal / rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function addExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal + rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
function subExp(environment,left,right,onReturn) {
|
||
|
right.Eval(environment,function(rVal){
|
||
|
left.Eval(environment,function(lVal){
|
||
|
onReturn( lVal - rVal );
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/* ENVIRONMENT */
|
||
|
var Environment = function() {
|
||
|
var dialogBuffer = null;
|
||
|
this.SetDialogBuffer = function(buffer) { dialogBuffer = buffer; };
|
||
|
this.GetDialogBuffer = function() { return dialogBuffer; };
|
||
|
|
||
|
var functionMap = new Map();
|
||
|
functionMap.set("print", printFunc);
|
||
|
functionMap.set("say", printFunc);
|
||
|
functionMap.set("br", linebreakFunc);
|
||
|
functionMap.set("item", itemFunc);
|
||
|
functionMap.set("rbw", rainbowFunc);
|
||
|
functionMap.set("clr1", color1Func);
|
||
|
functionMap.set("clr2", color2Func);
|
||
|
functionMap.set("clr3", color3Func);
|
||
|
functionMap.set("wvy", wavyFunc);
|
||
|
functionMap.set("shk", shakyFunc);
|
||
|
functionMap.set("printSprite", printSpriteFunc);
|
||
|
functionMap.set("printTile", printTileFunc);
|
||
|
functionMap.set("printItem", printItemFunc);
|
||
|
functionMap.set("debugOnlyPrintFont", printFontFunc); // DEBUG ONLY
|
||
|
functionMap.set("end", endFunc);
|
||
|
functionMap.set("exit", exitFunc);
|
||
|
functionMap.set("pg", pagebreakFunc);
|
||
|
functionMap.set("property", propertyFunc);
|
||
|
|
||
|
this.HasFunction = function(name) { return functionMap.has(name); };
|
||
|
this.EvalFunction = function(name,parameters,onReturn,env) {
|
||
|
if (env == undefined || env == null) {
|
||
|
env = this;
|
||
|
}
|
||
|
|
||
|
functionMap.get(name)(env, parameters, onReturn);
|
||
|
}
|
||
|
|
||
|
var variableMap = new Map();
|
||
|
|
||
|
this.HasVariable = function(name) { return variableMap.has(name); };
|
||
|
this.GetVariable = function(name) { return variableMap.get(name); };
|
||
|
this.SetVariable = function(name,value,useHandler) {
|
||
|
// console.log("SET VARIABLE " + name + " = " + value);
|
||
|
if(useHandler === undefined) useHandler = true;
|
||
|
variableMap.set(name, value);
|
||
|
if(onVariableChangeHandler != null && useHandler){
|
||
|
onVariableChangeHandler(name);
|
||
|
}
|
||
|
};
|
||
|
this.DeleteVariable = function(name,useHandler) {
|
||
|
if(useHandler === undefined) useHandler = true;
|
||
|
if(variableMap.has(name)) {
|
||
|
variableMap.delete(name);
|
||
|
if(onVariableChangeHandler != null && useHandler) {
|
||
|
onVariableChangeHandler(name);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var operatorMap = new Map();
|
||
|
operatorMap.set("=", setExp);
|
||
|
operatorMap.set("==", equalExp);
|
||
|
operatorMap.set(">", greaterExp);
|
||
|
operatorMap.set("<", lessExp);
|
||
|
operatorMap.set(">=", greaterEqExp);
|
||
|
operatorMap.set("<=", lessEqExp);
|
||
|
operatorMap.set("*", multExp);
|
||
|
operatorMap.set("/", divExp);
|
||
|
operatorMap.set("+", addExp);
|
||
|
operatorMap.set("-", subExp);
|
||
|
|
||
|
this.HasOperator = function(sym) { return operatorMap.get(sym); };
|
||
|
this.EvalOperator = function(sym,left,right,onReturn) {
|
||
|
operatorMap.get( sym )( this, left, right, onReturn );
|
||
|
}
|
||
|
|
||
|
var scriptMap = new Map();
|
||
|
this.HasScript = function(name) { return scriptMap.has(name); };
|
||
|
this.GetScript = function(name) { return scriptMap.get(name); };
|
||
|
this.SetScript = function(name,script) { scriptMap.set(name, script); };
|
||
|
|
||
|
var onVariableChangeHandler = null;
|
||
|
this.SetOnVariableChangeHandler = function(onVariableChange) {
|
||
|
onVariableChangeHandler = onVariableChange;
|
||
|
}
|
||
|
this.GetVariableNames = function() {
|
||
|
return Array.from( variableMap.keys() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Local environment for a single run of a script: knows local context
|
||
|
var LocalEnvironment = function(parentEnvironment) {
|
||
|
// this.SetDialogBuffer // not allowed in local environment?
|
||
|
this.GetDialogBuffer = function() { return parentEnvironment.GetDialogBuffer(); };
|
||
|
|
||
|
this.HasFunction = function(name) { return parentEnvironment.HasFunction(name); };
|
||
|
this.EvalFunction = function(name,parameters,onReturn,env) {
|
||
|
if (env == undefined || env == null) {
|
||
|
env = this;
|
||
|
}
|
||
|
|
||
|
parentEnvironment.EvalFunction(name,parameters,onReturn,env);
|
||
|
}
|
||
|
|
||
|
this.HasVariable = function(name) { return parentEnvironment.HasVariable(name); };
|
||
|
this.GetVariable = function(name) { return parentEnvironment.GetVariable(name); };
|
||
|
this.SetVariable = function(name,value,useHandler) { parentEnvironment.SetVariable(name,value,useHandler); };
|
||
|
// this.DeleteVariable // not needed in local environment?
|
||
|
|
||
|
this.HasOperator = function(sym) { return parentEnvironment.HasOperator(sym); };
|
||
|
this.EvalOperator = function(sym,left,right,onReturn,env) {
|
||
|
if (env == undefined || env == null) {
|
||
|
env = this;
|
||
|
}
|
||
|
|
||
|
parentEnvironment.EvalOperator(sym,left,right,onReturn,env);
|
||
|
};
|
||
|
|
||
|
// TODO : I don't *think* any of this is required by the local environment
|
||
|
// this.HasScript
|
||
|
// this.GetScript
|
||
|
// this.SetScript
|
||
|
|
||
|
// TODO : pretty sure these debug methods aren't required by the local environment either
|
||
|
// this.SetOnVariableChangeHandler
|
||
|
// this.GetVariableNames
|
||
|
|
||
|
/* Here's where specific local context data goes:
|
||
|
* this includes access to the object running the script
|
||
|
* and any properties it may have (so far only "locked")
|
||
|
*/
|
||
|
|
||
|
// The local environment knows what object called it -- currently only used to access properties
|
||
|
var curObject = null;
|
||
|
this.HasObject = function() { return curObject != undefined && curObject != null; }
|
||
|
this.SetObject = function(object) { curObject = object; }
|
||
|
this.GetObject = function() { return curObject; }
|
||
|
|
||
|
// accessors for properties of the object that's running the script
|
||
|
this.HasProperty = function(name) {
|
||
|
if (curObject && curObject.property && curObject.property.hasOwnProperty(name)) {
|
||
|
return true;
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
this.GetProperty = function(name) {
|
||
|
if (curObject && curObject.property && curObject.property.hasOwnProperty(name)) {
|
||
|
return curObject.property[name]; // TODO : should these be getters and setters instead?
|
||
|
}
|
||
|
else {
|
||
|
return null;
|
||
|
}
|
||
|
};
|
||
|
this.SetProperty = function(name, value) {
|
||
|
// NOTE : for now, we need to gaurd against creating new properties
|
||
|
if (curObject && curObject.property && curObject.property.hasOwnProperty(name)) {
|
||
|
curObject.property[name] = value;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function leadingWhitespace(depth) {
|
||
|
var str = "";
|
||
|
for(var i = 0; i < depth; i++) {
|
||
|
str += " "; // two spaces per indent
|
||
|
}
|
||
|
// console.log("WHITESPACE " + depth + " ::" + str + "::");
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
/* NODES */
|
||
|
var TreeRelationship = function() {
|
||
|
this.parent = null;
|
||
|
this.children = [];
|
||
|
|
||
|
this.AddChild = function(node) {
|
||
|
this.children.push(node);
|
||
|
node.parent = this;
|
||
|
};
|
||
|
|
||
|
this.AddChildren = function(nodeList) {
|
||
|
for (var i = 0; i < nodeList.length; i++) {
|
||
|
this.AddChild(nodeList[i]);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.SetChildren = function(nodeList) {
|
||
|
this.children = [];
|
||
|
this.AddChildren(nodeList);
|
||
|
};
|
||
|
|
||
|
this.VisitAll = function(visitor, depth) {
|
||
|
if (depth == undefined || depth == null) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
visitor.Visit(this, depth);
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
this.children[i].VisitAll( visitor, depth + 1 );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.rootId = null; // for debugging
|
||
|
this.GetId = function() {
|
||
|
// console.log(this);
|
||
|
if (this.rootId != null) {
|
||
|
return this.rootId;
|
||
|
}
|
||
|
else if (this.parent != null) {
|
||
|
var parentId = this.parent.GetId();
|
||
|
if (parentId != null) {
|
||
|
return parentId + "_" + this.parent.children.indexOf(this);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var DialogBlockNode = function(doIndentFirstLine) {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
// Object.assign( this, new Runnable() );
|
||
|
this.type = "dialog_block";
|
||
|
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
// console.log("EVAL BLOCK " + this.children.length);
|
||
|
|
||
|
if (isPlayerEmbeddedInEditor && events != undefined && events != null) {
|
||
|
events.Raise("script_node_enter", { id: this.GetId() });
|
||
|
}
|
||
|
|
||
|
var lastVal = null;
|
||
|
var i = 0;
|
||
|
|
||
|
function evalChildren(children, done) {
|
||
|
if (i < children.length) {
|
||
|
// console.log(">> CHILD " + i);
|
||
|
children[i].Eval(environment, function(val) {
|
||
|
// console.log("<< CHILD " + i);
|
||
|
lastVal = val;
|
||
|
i++;
|
||
|
evalChildren(children,done);
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
done();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var self = this;
|
||
|
evalChildren(this.children, function() {
|
||
|
if (isPlayerEmbeddedInEditor && events != undefined && events != null) {
|
||
|
events.Raise("script_node_exit", { id: self.GetId() });
|
||
|
}
|
||
|
|
||
|
onReturn(lastVal);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (doIndentFirstLine === undefined) {
|
||
|
doIndentFirstLine = true; // This is just for serialization
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
if (depth === undefined) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
var str = "";
|
||
|
var lastNode = null;
|
||
|
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
|
||
|
var curNode = this.children[i];
|
||
|
|
||
|
var curNodeIsNonInlineCode = curNode.type === "code_block" && !isInlineCode(curNode);
|
||
|
var prevNodeIsNonInlineCode = lastNode && lastNode.type === "code_block" && !isInlineCode(lastNode);
|
||
|
|
||
|
var shouldIndentFirstLine = (i == 0 && doIndentFirstLine);
|
||
|
var shouldIndentAfterLinebreak = (lastNode && lastNode.type === "function" && lastNode.name === "br");
|
||
|
var shouldIndentCodeBlock = i > 0 && curNodeIsNonInlineCode;
|
||
|
var shouldIndentAfterCodeBlock = prevNodeIsNonInlineCode;
|
||
|
|
||
|
if (shouldIndentFirstLine || shouldIndentAfterLinebreak || shouldIndentCodeBlock || shouldIndentAfterCodeBlock) {
|
||
|
str += leadingWhitespace(depth);
|
||
|
}
|
||
|
|
||
|
str += curNode.Serialize(depth);
|
||
|
|
||
|
lastNode = curNode;
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var CodeBlockNode = function() {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
this.type = "code_block";
|
||
|
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
// console.log("EVAL BLOCK " + this.children.length);
|
||
|
|
||
|
if (isPlayerEmbeddedInEditor && events != undefined && events != null) {
|
||
|
events.Raise("script_node_enter", { id: this.GetId() });
|
||
|
}
|
||
|
|
||
|
var lastVal = null;
|
||
|
var i = 0;
|
||
|
|
||
|
function evalChildren(children, done) {
|
||
|
if (i < children.length) {
|
||
|
// console.log(">> CHILD " + i);
|
||
|
children[i].Eval(environment, function(val) {
|
||
|
// console.log("<< CHILD " + i);
|
||
|
lastVal = val;
|
||
|
i++;
|
||
|
evalChildren(children,done);
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
done();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var self = this;
|
||
|
evalChildren(this.children, function() {
|
||
|
if (isPlayerEmbeddedInEditor && events != undefined && events != null) {
|
||
|
events.Raise("script_node_exit", { id: self.GetId() });
|
||
|
}
|
||
|
|
||
|
onReturn(lastVal);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
if(depth === undefined) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
// console.log("SERIALIZE BLOCK!!!");
|
||
|
// console.log(depth);
|
||
|
// console.log(doIndentFirstLine);
|
||
|
|
||
|
var str = "{"; // todo: increase scope of Sym?
|
||
|
|
||
|
// TODO : do code blocks ever have more than one child anymore????
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
var curNode = this.children[i];
|
||
|
str += curNode.Serialize(depth);
|
||
|
}
|
||
|
|
||
|
str += "}";
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function isInlineCode(node) {
|
||
|
return isTextEffectBlock(node) || isUndefinedBlock(node) || isMultilineListBlock(node);
|
||
|
}
|
||
|
|
||
|
function isUndefinedBlock(node) {
|
||
|
return node.type === "code_block" && node.children.length > 0 && node.children[0].type === "undefined";
|
||
|
}
|
||
|
|
||
|
var textEffectBlockNames = ["clr1", "clr2", "clr3", "wvy", "shk", "rbw", "printSprite", "printItem", "printTile", "print", "say", "br"];
|
||
|
function isTextEffectBlock(node) {
|
||
|
if (node.type === "code_block") {
|
||
|
if (node.children.length > 0 && node.children[0].type === "function") {
|
||
|
var func = node.children[0];
|
||
|
return textEffectBlockNames.indexOf(func.name) != -1;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
var listBlockTypes = ["sequence", "cycle", "shuffle", "if"];
|
||
|
function isMultilineListBlock(node) {
|
||
|
if (node.type === "code_block") {
|
||
|
if (node.children.length > 0) {
|
||
|
var child = node.children[0];
|
||
|
return listBlockTypes.indexOf(child.type) != -1;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// for round-tripping undefined code through the parser (useful for hacks!)
|
||
|
var UndefinedNode = function(sourceStr) {
|
||
|
Object.assign(this, new TreeRelationship());
|
||
|
this.type = "undefined";
|
||
|
this.source = sourceStr;
|
||
|
|
||
|
this.Eval = function(environment,onReturn) {
|
||
|
addOrRemoveTextEffect(environment, "_debug_highlight");
|
||
|
printFunc(environment, ["{" + sourceStr + "}"], function() {
|
||
|
onReturn(null);
|
||
|
});
|
||
|
addOrRemoveTextEffect(environment, "_debug_highlight");
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
return this.source;
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return "undefined" + " " + this.GetId();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var FuncNode = function(name,args) {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
// Object.assign( this, new Runnable() );
|
||
|
this.type = "function";
|
||
|
this.name = name;
|
||
|
this.args = args;
|
||
|
|
||
|
this.Eval = function(environment,onReturn) {
|
||
|
if (isPlayerEmbeddedInEditor && events != undefined && events != null) {
|
||
|
events.Raise("script_node_enter", { id: this.GetId() });
|
||
|
}
|
||
|
|
||
|
var self = this; // hack to deal with scope (TODO : move up higher?)
|
||
|
|
||
|
var argumentValues = [];
|
||
|
var i = 0;
|
||
|
|
||
|
function evalArgs(args, done) {
|
||
|
// TODO : really hacky way to make we get the first
|
||
|
// symbol's NAME instead of its variable value
|
||
|
// if we are trying to do something with a property
|
||
|
if (self.name === "property" && i === 0 && i < args.length) {
|
||
|
if (args[i].type === "variable") {
|
||
|
argumentValues.push(args[i].name);
|
||
|
i++;
|
||
|
}
|
||
|
else {
|
||
|
// first argument for a property MUST be a variable symbol
|
||
|
// -- so skip everything if it's not!
|
||
|
i = args.length;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (i < args.length) {
|
||
|
// Evaluate each argument
|
||
|
args[i].Eval(
|
||
|
environment,
|
||
|
function(val) {
|
||
|
argumentValues.push(val);
|
||
|
i++;
|
||
|
evalArgs(args, done);
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
done();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
evalArgs(
|
||
|
this.args,
|
||
|
function() {
|
||
|
if (isPlayerEmbeddedInEditor && events != undefined && events != null) {
|
||
|
events.Raise("script_node_exit", { id: self.GetId() });
|
||
|
}
|
||
|
|
||
|
environment.EvalFunction(self.name, argumentValues, onReturn);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
var isDialogBlock = this.parent.type === "dialog_block";
|
||
|
if (isDialogBlock && this.name === "print") {
|
||
|
// TODO this could cause problems with "real" print functions
|
||
|
return this.args[0].value; // first argument should be the text of the {print} func
|
||
|
}
|
||
|
else if (isDialogBlock && this.name === "br") {
|
||
|
return "\n";
|
||
|
}
|
||
|
else {
|
||
|
var str = "";
|
||
|
str += this.name;
|
||
|
for(var i = 0; i < this.args.length; i++) {
|
||
|
str += " ";
|
||
|
str += this.args[i].Serialize(depth);
|
||
|
}
|
||
|
return str;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.name + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var LiteralNode = function(value) {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
// Object.assign( this, new Runnable() );
|
||
|
this.type = "literal";
|
||
|
this.value = value;
|
||
|
|
||
|
this.Eval = function(environment,onReturn) {
|
||
|
onReturn(this.value);
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
var str = "";
|
||
|
|
||
|
if (this.value === null) {
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
if (typeof this.value === "string") {
|
||
|
str += '"';
|
||
|
}
|
||
|
|
||
|
str += this.value;
|
||
|
|
||
|
if (typeof this.value === "string") {
|
||
|
str += '"';
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.value + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var VarNode = function(name) {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
// Object.assign( this, new Runnable() );
|
||
|
this.type = "variable";
|
||
|
this.name = name;
|
||
|
|
||
|
this.Eval = function(environment,onReturn) {
|
||
|
// console.log("EVAL " + this.name + " " + environment.HasVariable(this.name) + " " + environment.GetVariable(this.name));
|
||
|
if( environment.HasVariable(this.name) )
|
||
|
onReturn( environment.GetVariable( this.name ) );
|
||
|
else
|
||
|
onReturn(null); // not a valid variable -- return null and hope that's ok
|
||
|
} // TODO: might want to store nodes in the variableMap instead of values???
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
var str = "" + this.name;
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.name + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var ExpNode = function(operator, left, right) {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
this.type = "operator";
|
||
|
this.operator = operator;
|
||
|
this.left = left;
|
||
|
this.right = right;
|
||
|
|
||
|
this.Eval = function(environment,onReturn) {
|
||
|
// console.log("EVAL " + this.operator);
|
||
|
var self = this; // hack to deal with scope
|
||
|
environment.EvalOperator( this.operator, this.left, this.right,
|
||
|
function(val){
|
||
|
// console.log("EVAL EXP " + self.operator + " " + val);
|
||
|
onReturn(val);
|
||
|
} );
|
||
|
// NOTE : sadly this pushes a lot of complexity down onto the actual operator methods
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
var isNegativeNumber = this.operator === "-" && this.left.type === "literal" && this.left.value === null;
|
||
|
|
||
|
if (!isNegativeNumber) {
|
||
|
var str = "";
|
||
|
|
||
|
if (this.left != undefined && this.left != null) {
|
||
|
str += this.left.Serialize(depth) + " ";
|
||
|
}
|
||
|
|
||
|
str += this.operator;
|
||
|
|
||
|
if (this.right != undefined && this.right != null) {
|
||
|
str += " " + this.right.Serialize(depth);
|
||
|
}
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
else {
|
||
|
return this.operator + this.right.Serialize(depth); // hacky but seems to work
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.VisitAll = function(visitor, depth) {
|
||
|
if (depth == undefined || depth == null) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
visitor.Visit( this, depth );
|
||
|
if(this.left != null)
|
||
|
this.left.VisitAll( visitor, depth + 1 );
|
||
|
if(this.right != null)
|
||
|
this.right.VisitAll( visitor, depth + 1 );
|
||
|
};
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.operator + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var SequenceBase = function() {
|
||
|
this.Serialize = function(depth) {
|
||
|
var str = "";
|
||
|
str += this.type + "\n";
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
str += leadingWhitespace(depth + 1) + Sym.List + " ";
|
||
|
str += this.children[i].Serialize(depth + 2);
|
||
|
str += "\n";
|
||
|
}
|
||
|
str += leadingWhitespace(depth);
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.VisitAll = function(visitor, depth) {
|
||
|
if (depth == undefined || depth == null) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
visitor.Visit(this, depth);
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
this.children[i].VisitAll( visitor, depth + 1 );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var SequenceNode = function(options) {
|
||
|
Object.assign(this, new TreeRelationship());
|
||
|
Object.assign(this, new SequenceBase());
|
||
|
this.type = "sequence";
|
||
|
this.AddChildren(options);
|
||
|
|
||
|
var index = 0;
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
// console.log("SEQUENCE " + index);
|
||
|
this.children[index].Eval(environment, onReturn);
|
||
|
|
||
|
var next = index + 1;
|
||
|
if (next < this.children.length) {
|
||
|
index = next;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var CycleNode = function(options) {
|
||
|
Object.assign(this, new TreeRelationship());
|
||
|
Object.assign(this, new SequenceBase());
|
||
|
this.type = "cycle";
|
||
|
this.AddChildren(options);
|
||
|
|
||
|
var index = 0;
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
// console.log("CYCLE " + index);
|
||
|
this.children[index].Eval(environment, onReturn);
|
||
|
|
||
|
var next = index + 1;
|
||
|
if (next < this.children.length) {
|
||
|
index = next;
|
||
|
}
|
||
|
else {
|
||
|
index = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var ShuffleNode = function(options) {
|
||
|
Object.assign(this, new TreeRelationship());
|
||
|
Object.assign(this, new SequenceBase());
|
||
|
this.type = "shuffle";
|
||
|
this.AddChildren(options);
|
||
|
|
||
|
var optionsShuffled = [];
|
||
|
function shuffle(options) {
|
||
|
optionsShuffled = [];
|
||
|
var optionsUnshuffled = options.slice();
|
||
|
while (optionsUnshuffled.length > 0) {
|
||
|
var i = Math.floor(Math.random() * optionsUnshuffled.length);
|
||
|
optionsShuffled.push(optionsUnshuffled.splice(i,1)[0]);
|
||
|
}
|
||
|
}
|
||
|
shuffle(this.children);
|
||
|
|
||
|
var index = 0;
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
optionsShuffled[index].Eval(environment, onReturn);
|
||
|
|
||
|
index++;
|
||
|
if (index >= this.children.length) {
|
||
|
shuffle(this.children);
|
||
|
index = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO : rename? ConditionalNode?
|
||
|
var IfNode = function(conditions, results, isSingleLine) {
|
||
|
Object.assign(this, new TreeRelationship());
|
||
|
this.type = "if";
|
||
|
|
||
|
for (var i = 0; i < conditions.length; i++) {
|
||
|
this.AddChild(new ConditionPairNode(conditions[i], results[i]));
|
||
|
}
|
||
|
|
||
|
var self = this;
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
// console.log("EVAL IF");
|
||
|
var i = 0;
|
||
|
function TestCondition() {
|
||
|
self.children[i].Eval(environment, function(result) {
|
||
|
if (result.conditionValue == true) {
|
||
|
onReturn(result.resultValue);
|
||
|
}
|
||
|
else if (i+1 < self.children.length) {
|
||
|
i++;
|
||
|
TestCondition();
|
||
|
}
|
||
|
else {
|
||
|
onReturn(null);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
TestCondition();
|
||
|
}
|
||
|
|
||
|
if (isSingleLine === undefined) {
|
||
|
isSingleLine = false; // This is just for serialization
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
var str = "";
|
||
|
if(isSingleLine) {
|
||
|
// HACKY - should I even keep this mode???
|
||
|
str += this.children[0].children[0].Serialize() + " ? " + this.children[0].children[1].Serialize();
|
||
|
if (this.children.length > 1 && this.children[1].children[0].type === Sym.Else) {
|
||
|
str += " " + Sym.ElseExp + " " + this.children[1].children[1].Serialize();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
str += "\n";
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
str += this.children[i].Serialize(depth);
|
||
|
}
|
||
|
str += leadingWhitespace(depth);
|
||
|
}
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.IsSingleLine = function() {
|
||
|
return isSingleLine;
|
||
|
}
|
||
|
|
||
|
this.VisitAll = function(visitor, depth) {
|
||
|
if (depth == undefined || depth == null) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
visitor.Visit(this, depth);
|
||
|
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
this.children[i].VisitAll(visitor, depth + 1);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.mode + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var ConditionPairNode = function(condition, result) {
|
||
|
Object.assign(this, new TreeRelationship());
|
||
|
|
||
|
this.type = "condition_pair";
|
||
|
|
||
|
this.AddChild(condition);
|
||
|
this.AddChild(result);
|
||
|
|
||
|
var self = this;
|
||
|
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
self.children[0].Eval(environment, function(conditionSuccess) {
|
||
|
if (conditionSuccess) {
|
||
|
self.children[1].Eval(environment, function(resultValue) {
|
||
|
onReturn({ conditionValue:true, resultValue:resultValue });
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
onReturn({ conditionValue:false });
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
this.Serialize = function(depth) {
|
||
|
var str = "";
|
||
|
str += leadingWhitespace(depth + 1);
|
||
|
str += Sym.List + " " + this.children[0].Serialize(depth) + " " + Sym.ConditionEnd + Sym.Linebreak;
|
||
|
str += this.children[1].Serialize(depth + 2) + Sym.Linebreak;
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
this.VisitAll = function(visitor, depth) {
|
||
|
if (depth == undefined || depth == null) {
|
||
|
depth = 0;
|
||
|
}
|
||
|
|
||
|
visitor.Visit(this, depth);
|
||
|
|
||
|
for (var i = 0; i < this.children.length; i++) {
|
||
|
this.children[i].VisitAll(visitor, depth + 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.GetId();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var ElseNode = function() {
|
||
|
Object.assign( this, new TreeRelationship() );
|
||
|
this.type = Sym.Else;
|
||
|
|
||
|
this.Eval = function(environment, onReturn) {
|
||
|
onReturn(true);
|
||
|
}
|
||
|
|
||
|
this.Serialize = function() {
|
||
|
return Sym.Else;
|
||
|
}
|
||
|
|
||
|
this.ToString = function() {
|
||
|
return this.type + " " + this.mode + " " + this.GetId();
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var Sym = {
|
||
|
DialogOpen : '"""',
|
||
|
DialogClose : '"""',
|
||
|
CodeOpen : "{",
|
||
|
CodeClose : "}",
|
||
|
Linebreak : "\n", // just call it "break" ?
|
||
|
Separator : ":",
|
||
|
List : "-",
|
||
|
String : '"',
|
||
|
ConditionEnd : "?",
|
||
|
Else : "else",
|
||
|
ElseExp : ":", // special shorthand for expressions (deprecate?)
|
||
|
Set : "=",
|
||
|
Operators : ["==", ">=", "<=", ">", "<", "-", "+", "/", "*"], // operators need to be in reverse order of precedence
|
||
|
};
|
||
|
|
||
|
var Parser = function(env) {
|
||
|
var environment = env;
|
||
|
|
||
|
this.Parse = function(scriptStr, rootId) {
|
||
|
var rootNode = new DialogBlockNode();
|
||
|
rootNode.rootId = rootId;
|
||
|
var state = new ParserState(rootNode, scriptStr);
|
||
|
|
||
|
console.log(scriptStr);
|
||
|
console.log(state.Source());
|
||
|
|
||
|
if (state.MatchAhead(Sym.DialogOpen)) {
|
||
|
// multi-line dialog block
|
||
|
var dialogStr = state.ConsumeBlock(Sym.DialogOpen + Sym.Linebreak, Sym.Linebreak + Sym.DialogClose);
|
||
|
rootNode = new DialogBlockNode();
|
||
|
rootNode.rootId = rootId; // hacky!!
|
||
|
state = new ParserState(rootNode, dialogStr);
|
||
|
state = ParseDialog(state);
|
||
|
}
|
||
|
else {
|
||
|
// single-line dialog block
|
||
|
state = ParseDialog(state);
|
||
|
}
|
||
|
|
||
|
return state.rootNode;
|
||
|
};
|
||
|
|
||
|
var ParserState = function( rootNode, str ) {
|
||
|
this.rootNode = rootNode;
|
||
|
this.curNode = this.rootNode;
|
||
|
|
||
|
var sourceStr = str;
|
||
|
var i = 0;
|
||
|
this.Index = function() { return i; };
|
||
|
this.Count = function() { return sourceStr.length; };
|
||
|
this.Done = function() { return i >= sourceStr.length; };
|
||
|
this.Char = function() { return sourceStr[i]; };
|
||
|
this.Step = function(n) { if(n===undefined) n=1; i += n; };
|
||
|
this.MatchAhead = function(str) {
|
||
|
// console.log(str);
|
||
|
str = "" + str; // hack to turn single chars into strings
|
||
|
// console.log(str);
|
||
|
// console.log(str.length);
|
||
|
for (var j = 0; j < str.length; j++) {
|
||
|
if (i + j >= sourceStr.length) {
|
||
|
return false;
|
||
|
}
|
||
|
else if (str[j] != sourceStr[i+j]) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
this.Peak = function(end) {
|
||
|
var str = "";
|
||
|
var j = i;
|
||
|
// console.log(j);
|
||
|
while (j < sourceStr.length && end.indexOf(sourceStr[j]) == -1) {
|
||
|
str += sourceStr[j];
|
||
|
j++;
|
||
|
}
|
||
|
// console.log("PEAK ::" + str + "::");
|
||
|
return str;
|
||
|
}
|
||
|
this.ConsumeBlock = function(open, close, includeSymbols) {
|
||
|
if (includeSymbols === undefined || includeSymbols === null) {
|
||
|
includeSymbols = false;
|
||
|
}
|
||
|
|
||
|
var startIndex = i;
|
||
|
|
||
|
var matchCount = 0;
|
||
|
if (this.MatchAhead(open)) {
|
||
|
matchCount++;
|
||
|
this.Step(open.length);
|
||
|
}
|
||
|
|
||
|
while (matchCount > 0 && !this.Done()) {
|
||
|
if (this.MatchAhead(close)) {
|
||
|
matchCount--;
|
||
|
this.Step( close.length );
|
||
|
}
|
||
|
else if (this.MatchAhead(open)) {
|
||
|
matchCount++;
|
||
|
this.Step(open.length);
|
||
|
}
|
||
|
else {
|
||
|
this.Step();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (includeSymbols) {
|
||
|
return sourceStr.slice(startIndex, i);
|
||
|
}
|
||
|
else {
|
||
|
return sourceStr.slice(startIndex + open.length, i - close.length);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.Print = function() { console.log(sourceStr); };
|
||
|
this.Source = function() { return sourceStr; };
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
ParseDialog():
|
||
|
This function adds {print} nodes and linebreak {br} nodes to display text,
|
||
|
interleaved with bracketed code nodes for functions and flow control,
|
||
|
such as text effects {shk} {wvy} or sequences like {cycle} and {shuffle}.
|
||
|
The parsing of those code blocks is handled by ParseCode.
|
||
|
|
||
|
Note on parsing newline characters:
|
||
|
- there should be an implicit linebreak {br} after each dialog line
|
||
|
- a "dialog line" is defined as any line that either:
|
||
|
- 1) contains dialog text (any text outside of a code block)
|
||
|
- 2) is entirely empty (no text, no code)
|
||
|
- *or* 3) contains a list block (sequence, cycle, shuffle, or conditional)
|
||
|
- lines *only* containing {code} blocks are not dialog lines
|
||
|
|
||
|
NOTE TO SELF: all the state I'm storing in here feels like
|
||
|
evidence that the parsing system kind of broke down at this point :(
|
||
|
Maybe it would feel better if I move into the "state" object
|
||
|
*/
|
||
|
function ParseDialog(state) {
|
||
|
var curLineNodeList = [];
|
||
|
var curText = "";
|
||
|
var curLineIsEmpty = true;
|
||
|
var curLineContainsDialogText = false;
|
||
|
var prevLineIsDialogLine = false;
|
||
|
|
||
|
var curLineIsDialogLine = function() {
|
||
|
return curLineContainsDialogText || curLineIsEmpty;
|
||
|
}
|
||
|
|
||
|
var resetLineStateForNewLine = function() {
|
||
|
prevLineIsDialogLine = curLineIsDialogLine();
|
||
|
curLineContainsDialogText = false;
|
||
|
curLineIsEmpty = true;
|
||
|
curText = "";
|
||
|
curLineNodeList = [];
|
||
|
}
|
||
|
|
||
|
var tryAddTextNodeToList = function() {
|
||
|
if (curText.length > 0) {
|
||
|
var printNode = new FuncNode("print", [new LiteralNode(curText)]);
|
||
|
curLineNodeList.push(printNode);
|
||
|
|
||
|
curText = "";
|
||
|
curLineIsEmpty = false;
|
||
|
curLineContainsDialogText = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var addCodeNodeToList = function() {
|
||
|
var codeSource = state.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose);
|
||
|
var codeState = new ParserState(new CodeBlockNode(), codeSource);
|
||
|
codeState = ParseCode(codeState);
|
||
|
var codeBlockNode = codeState.rootNode;
|
||
|
curLineNodeList.push(codeBlockNode);
|
||
|
|
||
|
curLineIsEmpty = false;
|
||
|
|
||
|
// lists count as dialog text, because they can contain it
|
||
|
if (isMultilineListBlock(codeBlockNode)) {
|
||
|
curLineContainsDialogText = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var tryAddLinebreakNodeToList = function() {
|
||
|
if (prevLineIsDialogLine) {
|
||
|
var linebreakNode = new FuncNode("br", []);
|
||
|
curLineNodeList.unshift(linebreakNode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var addLineNodesToParent = function() {
|
||
|
for (var i = 0; i < curLineNodeList.length; i++) {
|
||
|
state.curNode.AddChild(curLineNodeList[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (!state.Done()) {
|
||
|
if (state.MatchAhead(Sym.CodeOpen)) { // process code block
|
||
|
// add any buffered text to a print node, and parse the code
|
||
|
tryAddTextNodeToList();
|
||
|
addCodeNodeToList();
|
||
|
}
|
||
|
else if (state.MatchAhead(Sym.Linebreak)) { // process new line
|
||
|
// add any buffered text to a print node,
|
||
|
// and add a linebreak if we are between two dialog lines
|
||
|
tryAddTextNodeToList();
|
||
|
tryAddLinebreakNodeToList();
|
||
|
|
||
|
// since we've reached the end of a line
|
||
|
// add stored nodes for this line to the parent node we are building,
|
||
|
// and reset state for the next line
|
||
|
addLineNodesToParent();
|
||
|
resetLineStateForNewLine();
|
||
|
|
||
|
state.Step();
|
||
|
}
|
||
|
else {
|
||
|
// continue adding text to the current text buffer
|
||
|
curText += state.Char();
|
||
|
state.Step();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// to make sure we don't leave anything behind:
|
||
|
// add buffered text to a print node and add all nodes
|
||
|
// to the current parent node
|
||
|
tryAddTextNodeToList();
|
||
|
tryAddLinebreakNodeToList();
|
||
|
addLineNodesToParent();
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
function ParseDialogBlock(state) {
|
||
|
var dialogStr = state.ConsumeBlock( Sym.DialogOpen, Sym.DialogClose );
|
||
|
|
||
|
var dialogState = new ParserState(new DialogBlockNode(), dialogStr);
|
||
|
dialogState = ParseDialog( dialogState );
|
||
|
|
||
|
state.curNode.AddChild( dialogState.rootNode );
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
ParseConditional():
|
||
|
A conditional contains a list of conditions that can be
|
||
|
evaluated to true or false, followed by more dialog
|
||
|
that will be evaluated if the condition is true. The first
|
||
|
true condition is the one that gets evaluated.
|
||
|
*/
|
||
|
function ParseConditional(state) {
|
||
|
var conditionStrings = [];
|
||
|
var resultStrings = [];
|
||
|
var curIndex = -1;
|
||
|
var requiredLeadingWhitespace = -1;
|
||
|
|
||
|
// TODO : very similar to sequence parsing - can we share anything?
|
||
|
function parseConditionalItemLine(state) {
|
||
|
var lineText = "";
|
||
|
var whitespaceCount = 0;
|
||
|
var isNewCondition = false;
|
||
|
var encounteredNonWhitespace = false;
|
||
|
var encounteredConditionEnd = false;
|
||
|
|
||
|
while (!state.Done() && !(state.Char() === Sym.Linebreak)) {
|
||
|
// count whitespace until we hit the first non-whitespace character
|
||
|
if (!encounteredNonWhitespace) {
|
||
|
if (state.Char() === " " || state.Char() === "\t") {
|
||
|
whitespaceCount++;
|
||
|
}
|
||
|
else {
|
||
|
encounteredNonWhitespace = true;
|
||
|
|
||
|
if (state.Char() === Sym.List) {
|
||
|
isNewCondition = true;
|
||
|
whitespaceCount += 2; // count the list seperator AND the following extra space
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if this is the condition, we need to track whether we've
|
||
|
// reached the end of the condition
|
||
|
if (isNewCondition && !encounteredConditionEnd) {
|
||
|
if (state.Char() === Sym.ConditionEnd) {
|
||
|
encounteredConditionEnd = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add characters one at a time, unless it's a code block
|
||
|
// since code blocks can contain additional sequences inside
|
||
|
// them that will mess up our list item detection
|
||
|
if (state.Char() === Sym.CodeOpen) {
|
||
|
lineText += state.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose, true /*includeSymbols*/);
|
||
|
}
|
||
|
else {
|
||
|
if (!encounteredConditionEnd) { // skip all characters including & after the condition end
|
||
|
lineText += state.Char();
|
||
|
}
|
||
|
state.Step();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (state.Char() === Sym.Linebreak) {
|
||
|
state.Step();
|
||
|
}
|
||
|
|
||
|
return { text:lineText, whitespace:whitespaceCount, isNewCondition:isNewCondition };
|
||
|
}
|
||
|
|
||
|
// TODO : this is copied from sequence parsing; share?
|
||
|
function trimLeadingWhitespace(text, trimLength) {
|
||
|
var textSplit = text.split(Sym.linebreak);
|
||
|
textSplit = textSplit.map(function(line) { return line.slice(trimLength) });
|
||
|
return textSplit.join(Sym.linebreak);
|
||
|
}
|
||
|
|
||
|
while (!state.Done()) {
|
||
|
var lineResults = parseConditionalItemLine(state);
|
||
|
|
||
|
if (lineResults.isNewCondition) {
|
||
|
requiredLeadingWhitespace = lineResults.whitespace;
|
||
|
curIndex++;
|
||
|
conditionStrings[curIndex] = "";
|
||
|
resultStrings[curIndex] = "";
|
||
|
}
|
||
|
|
||
|
// to avoid extra newlines in nested conditionals, only count lines
|
||
|
// that at least match the whitespace count of the initial line
|
||
|
// NOTE: see the comment in sequence parsing for more details
|
||
|
if (lineResults.whitespace >= requiredLeadingWhitespace) {
|
||
|
var trimmedText = trimLeadingWhitespace(lineResults.text, requiredLeadingWhitespace);
|
||
|
|
||
|
if (lineResults.isNewCondition) {
|
||
|
conditionStrings[curIndex] += trimmedText;
|
||
|
}
|
||
|
else {
|
||
|
resultStrings[curIndex] += trimmedText + Sym.Linebreak;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// hack: cut off the trailing newlines from all the result strings
|
||
|
resultStrings = resultStrings.map(function(result) { return result.slice(0,-1); });
|
||
|
|
||
|
var conditions = [];
|
||
|
for (var i = 0; i < conditionStrings.length; i++) {
|
||
|
var str = conditionStrings[i].trim();
|
||
|
if (str === Sym.Else) {
|
||
|
conditions.push(new ElseNode());
|
||
|
}
|
||
|
else {
|
||
|
var exp = CreateExpression(str);
|
||
|
conditions.push(exp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var results = [];
|
||
|
for (var i = 0; i < resultStrings.length; i++) {
|
||
|
var str = resultStrings[i];
|
||
|
var dialogBlockState = new ParserState(new DialogBlockNode(), str);
|
||
|
dialogBlockState = ParseDialog(dialogBlockState);
|
||
|
var dialogBlock = dialogBlockState.rootNode;
|
||
|
results.push(dialogBlock);
|
||
|
}
|
||
|
|
||
|
state.curNode.AddChild(new IfNode(conditions, results));
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
function IsSequence(str) {
|
||
|
// console.log("IsSequence? " + str);
|
||
|
return str === "sequence" || str === "cycle" || str === "shuffle";
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
ParseSequence():
|
||
|
Sequence nodes contain a list of dialog block nodes. The order those
|
||
|
nodes are evaluated is determined by the type of sequence:
|
||
|
- sequence: each child node evaluated once in order
|
||
|
- cycle: repeats from the beginning after all nodes evaluate
|
||
|
- shuffle: evaluate in a random order
|
||
|
|
||
|
Each item in a sequence is sepearated by a "-" character.
|
||
|
The seperator must come at the beginning of the line,
|
||
|
but may be preceded by whitespace (in any amount).
|
||
|
|
||
|
About whitespace: Whitespace at the start of a line
|
||
|
is ignored if it less than or equal to the count of
|
||
|
whitespace that preceded the list separator ("-") at
|
||
|
the start of that item. (The count also includes the
|
||
|
seperator and the extra space after the seperator.)
|
||
|
*/
|
||
|
function ParseSequence(state, sequenceType) {
|
||
|
var itemStrings = [];
|
||
|
var curItemIndex = -1; // -1 indicates not reading an item yet
|
||
|
var requiredLeadingWhitespace = -1;
|
||
|
|
||
|
function parseSequenceItemLine(state) {
|
||
|
var lineText = "";
|
||
|
var whitespaceCount = 0;
|
||
|
var isNewListItem = false;
|
||
|
var encounteredNonWhitespace = false;
|
||
|
|
||
|
while (!state.Done() && !(state.Char() === Sym.Linebreak)) {
|
||
|
// count whitespace until we hit the first non-whitespace character
|
||
|
if (!encounteredNonWhitespace) {
|
||
|
if (state.Char() === " " || state.Char() === "\t") {
|
||
|
whitespaceCount++;
|
||
|
}
|
||
|
else {
|
||
|
encounteredNonWhitespace = true;
|
||
|
|
||
|
if (state.Char() === Sym.List) {
|
||
|
isNewListItem = true;
|
||
|
whitespaceCount += 2; // count the list seperator AND the following extra space
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add characters one at a time, unless it's a code block
|
||
|
// since code blocks can contain additional sequences inside
|
||
|
// them that will mess up our list item detection
|
||
|
if (state.Char() === Sym.CodeOpen) {
|
||
|
lineText += state.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose, true /*includeSymbols*/);
|
||
|
}
|
||
|
else {
|
||
|
lineText += state.Char();
|
||
|
state.Step();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (state.Char() === Sym.Linebreak) {
|
||
|
state.Step();
|
||
|
}
|
||
|
|
||
|
return { text:lineText, whitespace:whitespaceCount, isNewListItem:isNewListItem };
|
||
|
}
|
||
|
|
||
|
function trimLeadingWhitespace(text, trimLength) {
|
||
|
// the split and join is necessary because a single "line"
|
||
|
// can contain sequences that may contain newlines of their own
|
||
|
// (we treat them all as one "line" for sequence parsing purposes)
|
||
|
var textSplit = text.split(Sym.linebreak);
|
||
|
textSplit = textSplit.map(function(line) { return line.slice(trimLength) });
|
||
|
return textSplit.join(Sym.linebreak);
|
||
|
}
|
||
|
|
||
|
while (!state.Done()) {
|
||
|
var lineResults = parseSequenceItemLine(state);
|
||
|
|
||
|
if (lineResults.isNewListItem) {
|
||
|
requiredLeadingWhitespace = lineResults.whitespace;
|
||
|
curItemIndex++;
|
||
|
itemStrings[curItemIndex] = "";
|
||
|
}
|
||
|
|
||
|
// to avoid double counting closing lines (empty ones ending in a curly brace)
|
||
|
// we only allow lines that have at least as much whitespace as the start of the list item
|
||
|
// TODO : I think right now this leads to a bug if the list item's indentation is less than
|
||
|
// its parent code block... hopefully that won't be a big deal for now
|
||
|
// (NOTE: I think the bug could be fixed by only applying this to the FINAL line of an item, but
|
||
|
// that would require more consideration and testing)
|
||
|
if (lineResults.whitespace >= requiredLeadingWhitespace) {
|
||
|
var trimmedText = trimLeadingWhitespace(lineResults.text, requiredLeadingWhitespace);
|
||
|
itemStrings[curItemIndex] += trimmedText + Sym.Linebreak;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// a bit hacky: cut off the trailing newlines from all the items
|
||
|
itemStrings = itemStrings.map(function(item) { return item.slice(0,-1); });
|
||
|
|
||
|
var options = [];
|
||
|
for (var i = 0; i < itemStrings.length; i++) {
|
||
|
var str = itemStrings[i];
|
||
|
var dialogBlockState = new ParserState(new DialogBlockNode(false /* doIndentFirstLine */), str);
|
||
|
dialogBlockState = ParseDialog(dialogBlockState);
|
||
|
var dialogBlock = dialogBlockState.rootNode;
|
||
|
options.push(dialogBlock);
|
||
|
}
|
||
|
|
||
|
if (sequenceType === "sequence") {
|
||
|
state.curNode.AddChild(new SequenceNode(options));
|
||
|
}
|
||
|
else if (sequenceType === "cycle") {
|
||
|
state.curNode.AddChild(new CycleNode(options));
|
||
|
}
|
||
|
else if (sequenceType === "shuffle") {
|
||
|
state.curNode.AddChild(new ShuffleNode(options));
|
||
|
}
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
function ParseFunction(state, funcName) {
|
||
|
console.log("~~~ PARSE FUNCTION " + funcName);
|
||
|
|
||
|
var args = [];
|
||
|
|
||
|
var curSymbol = "";
|
||
|
function OnSymbolEnd() {
|
||
|
curSymbol = curSymbol.trim();
|
||
|
// console.log("PARAMTER " + curSymbol);
|
||
|
args.push( StringToValue(curSymbol) );
|
||
|
// console.log(args);
|
||
|
curSymbol = "";
|
||
|
}
|
||
|
|
||
|
while( !( state.Char() === "\n" || state.Done() ) ) {
|
||
|
if( state.MatchAhead(Sym.CodeOpen) ) {
|
||
|
var codeBlockState = new ParserState(new CodeBlockNode(), state.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose));
|
||
|
codeBlockState = ParseCode( codeBlockState );
|
||
|
var codeBlock = codeBlockState.rootNode;
|
||
|
args.push( codeBlock );
|
||
|
curSymbol = "";
|
||
|
}
|
||
|
else if( state.MatchAhead(Sym.String) ) {
|
||
|
/* STRING LITERAL */
|
||
|
var str = state.ConsumeBlock(Sym.String, Sym.String);
|
||
|
// console.log("STRING " + str);
|
||
|
args.push( new LiteralNode(str) );
|
||
|
curSymbol = "";
|
||
|
}
|
||
|
else if(state.Char() === " " && curSymbol.length > 0) {
|
||
|
OnSymbolEnd();
|
||
|
}
|
||
|
else {
|
||
|
curSymbol += state.Char();
|
||
|
}
|
||
|
state.Step();
|
||
|
}
|
||
|
|
||
|
if(curSymbol.length > 0) {
|
||
|
OnSymbolEnd();
|
||
|
}
|
||
|
|
||
|
state.curNode.AddChild( new FuncNode( funcName, args ) );
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
function IsValidVariableName(str) {
|
||
|
var reg = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
|
||
|
var isValid = reg.test(str);
|
||
|
// console.log("VALID variable??? " + isValid);
|
||
|
return isValid;
|
||
|
}
|
||
|
|
||
|
function StringToValue(valStr) {
|
||
|
if(valStr[0] === Sym.CodeOpen) {
|
||
|
// CODE BLOCK!!!
|
||
|
var codeStr = (new ParserState( null, valStr )).ConsumeBlock(Sym.CodeOpen, Sym.CodeClose); //hacky
|
||
|
var codeBlockState = new ParserState(new CodeBlockNode(), codeStr);
|
||
|
codeBlockState = ParseCode( codeBlockState );
|
||
|
return codeBlockState.rootNode;
|
||
|
}
|
||
|
else if(valStr[0] === Sym.String) {
|
||
|
// STRING!!
|
||
|
// console.log("STRING");
|
||
|
var str = "";
|
||
|
var i = 1;
|
||
|
while (i < valStr.length && valStr[i] != Sym.String) {
|
||
|
str += valStr[i];
|
||
|
i++;
|
||
|
}
|
||
|
// console.log(str);
|
||
|
return new LiteralNode( str );
|
||
|
}
|
||
|
else if(valStr === "true") {
|
||
|
// BOOL
|
||
|
return new LiteralNode( true );
|
||
|
}
|
||
|
else if(valStr === "false") {
|
||
|
// BOOL
|
||
|
return new LiteralNode( false );
|
||
|
}
|
||
|
else if( !isNaN(parseFloat(valStr)) ) {
|
||
|
// NUMBER!!
|
||
|
// console.log("NUMBER!!! " + valStr);
|
||
|
return new LiteralNode( parseFloat(valStr) );
|
||
|
}
|
||
|
else if(IsValidVariableName(valStr)) {
|
||
|
// VARIABLE!!
|
||
|
// console.log("VARIABLE");
|
||
|
return new VarNode(valStr); // TODO : check for valid potential variables
|
||
|
}
|
||
|
else {
|
||
|
// uh oh
|
||
|
return new LiteralNode(null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function CreateExpression(expStr) {
|
||
|
expStr = expStr.trim();
|
||
|
|
||
|
function IsInsideString(index) {
|
||
|
var inString = false;
|
||
|
for(var i = 0; i < expStr.length; i++) {
|
||
|
if(expStr[i] === Sym.String)
|
||
|
inString = !inString;
|
||
|
|
||
|
if(index === i)
|
||
|
return inString;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function IsInsideCode(index) {
|
||
|
var count = 0;
|
||
|
for(var i = 0; i < expStr.length; i++) {
|
||
|
if(expStr[i] === Sym.CodeOpen)
|
||
|
count++;
|
||
|
else if(expStr[i] === Sym.CodeClose)
|
||
|
count--;
|
||
|
|
||
|
if(index === i)
|
||
|
return count > 0;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
var operator = null;
|
||
|
|
||
|
// set is special because other operator can look like it, and it has to go first in the order of operations
|
||
|
var setIndex = expStr.indexOf(Sym.Set);
|
||
|
if( setIndex > -1 && !IsInsideString(setIndex) && !IsInsideCode(setIndex) ) { // it might be a set operator
|
||
|
if( expStr[setIndex+1] != "=" && expStr[setIndex-1] != ">" && expStr[setIndex-1] != "<" ) {
|
||
|
// ok it actually IS a set operator and not ==, >=, or <=
|
||
|
operator = Sym.Set;
|
||
|
var variableName = expStr.substring(0,setIndex).trim(); // TODO : valid variable name testing
|
||
|
var left = IsValidVariableName(variableName) ? new VarNode( variableName ) : new LiteralNode(null);
|
||
|
var right = CreateExpression( expStr.substring(setIndex+Sym.Set.length) );
|
||
|
var exp = new ExpNode( operator, left, right );
|
||
|
return exp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// special if "expression" for single-line if statements
|
||
|
var ifIndex = expStr.indexOf(Sym.ConditionEnd);
|
||
|
if( ifIndex > -1 && !IsInsideString(ifIndex) && !IsInsideCode(ifIndex) ) {
|
||
|
operator = Sym.ConditionEnd;
|
||
|
var conditionStr = expStr.substring(0,ifIndex).trim();
|
||
|
var conditions = [ CreateExpression(conditionStr) ];
|
||
|
|
||
|
var resultStr = expStr.substring(ifIndex+Sym.ConditionEnd.length);
|
||
|
var results = [];
|
||
|
function AddResult(str) {
|
||
|
var dialogBlockState = new ParserState(new DialogBlockNode(), str);
|
||
|
dialogBlockState = ParseDialog( dialogBlockState );
|
||
|
var dialogBlock = dialogBlockState.rootNode;
|
||
|
results.push( dialogBlock );
|
||
|
}
|
||
|
|
||
|
var elseIndex = resultStr.indexOf(Sym.ElseExp); // does this need to test for strings?
|
||
|
if(elseIndex > -1) {
|
||
|
conditions.push( new ElseNode() );
|
||
|
|
||
|
var elseStr = resultStr.substring(elseIndex+Sym.ElseExp.length);
|
||
|
var resultStr = resultStr.substring(0,elseIndex);
|
||
|
|
||
|
AddResult( resultStr.trim() );
|
||
|
AddResult( elseStr.trim() );
|
||
|
}
|
||
|
else {
|
||
|
AddResult( resultStr.trim() );
|
||
|
}
|
||
|
|
||
|
return new IfNode( conditions, results, true /*isSingleLine*/ );
|
||
|
}
|
||
|
|
||
|
for( var i = 0; (operator == null) && (i < Sym.Operators.length); i++ ) {
|
||
|
var opSym = Sym.Operators[i];
|
||
|
var opIndex = expStr.indexOf( opSym );
|
||
|
if( opIndex > -1 && !IsInsideString(opIndex) && !IsInsideCode(opIndex) ) {
|
||
|
operator = opSym;
|
||
|
var left = CreateExpression( expStr.substring(0,opIndex) );
|
||
|
var right = CreateExpression( expStr.substring(opIndex+opSym.length) );
|
||
|
var exp = new ExpNode( operator, left, right );
|
||
|
return exp;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( operator == null ) {
|
||
|
return StringToValue(expStr);
|
||
|
}
|
||
|
}
|
||
|
this.CreateExpression = CreateExpression;
|
||
|
|
||
|
function IsWhitespace(str) {
|
||
|
return ( str === " " || str === "\t" || str === "\n" );
|
||
|
}
|
||
|
|
||
|
function IsExpression(str) {
|
||
|
var tempState = new ParserState(null, str); // hacky
|
||
|
var textOutsideCodeBlocks = "";
|
||
|
|
||
|
while (!tempState.Done()) {
|
||
|
if (tempState.MatchAhead(Sym.CodeOpen)) {
|
||
|
tempState.ConsumeBlock(Sym.CodeOpen, Sym.CodeClose);
|
||
|
}
|
||
|
else {
|
||
|
textOutsideCodeBlocks += tempState.Char();
|
||
|
tempState.Step();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var containsAnyExpressionOperators = (textOutsideCodeBlocks.indexOf(Sym.ConditionEnd) != -1) ||
|
||
|
(textOutsideCodeBlocks.indexOf(Sym.Set) != -1) ||
|
||
|
(Sym.Operators.some(function(opSym) { return textOutsideCodeBlocks.indexOf(opSym) != -1; }));
|
||
|
|
||
|
return containsAnyExpressionOperators;
|
||
|
}
|
||
|
|
||
|
function IsLiteral(str) {
|
||
|
var isBool = str === "true" || str === "false";
|
||
|
var isNum = !isNaN(parseFloat(str));
|
||
|
var isStr = str[0] === '"' && str[str.length-1] === '"';
|
||
|
var isVar = IsValidVariableName(str);
|
||
|
var isEmpty = str.length === 0;
|
||
|
return isBool || isNum || isStr || isVar || isEmpty;
|
||
|
}
|
||
|
|
||
|
function ParseExpression(state) {
|
||
|
var line = state.Source(); // state.Peak( [Sym.Linebreak] ); // TODO : remove the linebreak thing
|
||
|
// console.log("EXPRESSION " + line);
|
||
|
var exp = CreateExpression(line);
|
||
|
// console.log(exp);
|
||
|
state.curNode.AddChild(exp);
|
||
|
state.Step(line.length);
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
function IsConditionalBlock(state) {
|
||
|
var peakToFirstListSymbol = state.Peak([Sym.List]);
|
||
|
|
||
|
var foundListSymbol = peakToFirstListSymbol < state.Source().length;
|
||
|
|
||
|
var areAllCharsBeforeListWhitespace = true;
|
||
|
for (var i = 0; i < peakToFirstListSymbol.length; i++) {
|
||
|
if (!IsWhitespace(peakToFirstListSymbol[i])) {
|
||
|
areAllCharsBeforeListWhitespace = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var peakToFirstConditionSymbol = state.Peak([Sym.ConditionEnd]);
|
||
|
peakToFirstConditionSymbol = peakToFirstConditionSymbol.slice(peakToFirstListSymbol.length);
|
||
|
var hasNoLinebreakBetweenListAndConditionEnd = peakToFirstConditionSymbol.indexOf(Sym.Linebreak) == -1;
|
||
|
|
||
|
return foundListSymbol &&
|
||
|
areAllCharsBeforeListWhitespace &&
|
||
|
hasNoLinebreakBetweenListAndConditionEnd;
|
||
|
}
|
||
|
|
||
|
function ParseCode(state) {
|
||
|
if (IsConditionalBlock(state)) {
|
||
|
state = ParseConditional(state);
|
||
|
}
|
||
|
else if (environment.HasFunction(state.Peak([" "]))) { // TODO --- what about newlines???
|
||
|
var funcName = state.Peak([" "]);
|
||
|
state.Step(funcName.length);
|
||
|
state = ParseFunction(state, funcName);
|
||
|
}
|
||
|
else if (IsSequence(state.Peak([" ", Sym.Linebreak]))) {
|
||
|
var sequenceType = state.Peak([" ", Sym.Linebreak]);
|
||
|
state.Step(sequenceType.length);
|
||
|
state = ParseSequence(state, sequenceType);
|
||
|
}
|
||
|
else if (IsLiteral(state.Source()) || IsExpression(state.Source())) {
|
||
|
state = ParseExpression(state);
|
||
|
}
|
||
|
else {
|
||
|
var undefinedSrc = state.Peak([]);
|
||
|
var undefinedNode = new UndefinedNode(undefinedSrc);
|
||
|
state.curNode.AddChild(undefinedNode);
|
||
|
}
|
||
|
|
||
|
// just go to the end now
|
||
|
while (!state.Done()) {
|
||
|
state.Step();
|
||
|
}
|
||
|
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
function ParseCodeBlock(state) {
|
||
|
var codeStr = state.ConsumeBlock( Sym.CodeOpen, Sym.CodeClose );
|
||
|
var codeState = new ParserState(new CodeBlockNode(), codeStr);
|
||
|
codeState = ParseCode( codeState );
|
||
|
state.curNode.AddChild( codeState.rootNode );
|
||
|
return state;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
} // Script()
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
function Dialog() {
|
||
|
|
||
|
this.CreateRenderer = function() {
|
||
|
return new DialogRenderer();
|
||
|
};
|
||
|
|
||
|
this.CreateBuffer = function() {
|
||
|
return new DialogBuffer();
|
||
|
};
|
||
|
|
||
|
var DialogRenderer = function() {
|
||
|
|
||
|
// TODO : refactor this eventually? remove everything from struct.. avoid the defaults?
|
||
|
var textboxInfo = {
|
||
|
img : null,
|
||
|
width : 104,
|
||
|
height : 8+4+2+5, //8 for text, 4 for top-bottom padding, 2 for line padding, 5 for arrow
|
||
|
top : 12,
|
||
|
left : 12,
|
||
|
bottom : 12, //for drawing it from the bottom
|
||
|
font_scale : 0.5, // we draw font at half-size compared to everything else
|
||
|
padding_vert : 2,
|
||
|
padding_horz : 4,
|
||
|
arrow_height : 5,
|
||
|
};
|
||
|
|
||
|
var font = null;
|
||
|
this.SetFont = function(f) {
|
||
|
font = f;
|
||
|
textboxInfo.height = (textboxInfo.padding_vert * 3) + (relativeFontHeight() * 2) + textboxInfo.arrow_height;
|
||
|
textboxInfo.img = context.createImageData(textboxInfo.width*scale, textboxInfo.height*scale);
|
||
|
}
|
||
|
|
||
|
function textScale() {
|
||
|
return scale * textboxInfo.font_scale;
|
||
|
}
|
||
|
|
||
|
function relativeFontWidth() {
|
||
|
return Math.ceil( font.getWidth() * textboxInfo.font_scale );
|
||
|
}
|
||
|
|
||
|
function relativeFontHeight() {
|
||
|
return Math.ceil( font.getHeight() * textboxInfo.font_scale );
|
||
|
}
|
||
|
|
||
|
var context = null;
|
||
|
this.AttachContext = function(c) {
|
||
|
context = c;
|
||
|
};
|
||
|
|
||
|
this.ClearTextbox = function() {
|
||
|
if(context == null) return;
|
||
|
|
||
|
//create new image none exists
|
||
|
if(textboxInfo.img == null)
|
||
|
textboxInfo.img = context.createImageData(textboxInfo.width*scale, textboxInfo.height*scale);
|
||
|
|
||
|
// fill text box with black
|
||
|
for (var i=0;i<textboxInfo.img.data.length;i+=4)
|
||
|
{
|
||
|
textboxInfo.img.data[i+0]=0;
|
||
|
textboxInfo.img.data[i+1]=0;
|
||
|
textboxInfo.img.data[i+2]=0;
|
||
|
textboxInfo.img.data[i+3]=255;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var isCentered = false;
|
||
|
this.SetCentered = function(centered) {
|
||
|
isCentered = centered;
|
||
|
};
|
||
|
|
||
|
this.DrawTextbox = function() {
|
||
|
if(context == null) return;
|
||
|
if (isCentered) {
|
||
|
context.putImageData(textboxInfo.img, textboxInfo.left*scale, ((height/2)-(textboxInfo.height/2))*scale);
|
||
|
}
|
||
|
else if (player().y < mapsize/2) {
|
||
|
//bottom
|
||
|
context.putImageData(textboxInfo.img, textboxInfo.left*scale, (height-textboxInfo.bottom-textboxInfo.height)*scale);
|
||
|
}
|
||
|
else {
|
||
|
//top
|
||
|
context.putImageData(textboxInfo.img, textboxInfo.left*scale, textboxInfo.top*scale);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var arrowdata = [
|
||
|
1,1,1,1,1,
|
||
|
0,1,1,1,0,
|
||
|
0,0,1,0,0
|
||
|
];
|
||
|
this.DrawNextArrow = function() {
|
||
|
// console.log("draw arrow!");
|
||
|
var top = (textboxInfo.height-5) * scale;
|
||
|
var left = (textboxInfo.width-(5+4)) * scale;
|
||
|
if (textDirection === TextDirection.RightToLeft) { // RTL hack
|
||
|
left = 4 * scale;
|
||
|
}
|
||
|
|
||
|
for (var y = 0; y < 3; y++) {
|
||
|
for (var x = 0; x < 5; x++) {
|
||
|
var i = (y * 5) + x;
|
||
|
if (arrowdata[i] == 1) {
|
||
|
//scaling nonsense
|
||
|
for (var sy = 0; sy < scale; sy++) {
|
||
|
for (var sx = 0; sx < scale; sx++) {
|
||
|
var pxl = 4 * ( ((top+(y*scale)+sy) * (textboxInfo.width*scale)) + (left+(x*scale)+sx) );
|
||
|
textboxInfo.img.data[pxl+0] = 255;
|
||
|
textboxInfo.img.data[pxl+1] = 255;
|
||
|
textboxInfo.img.data[pxl+2] = 255;
|
||
|
textboxInfo.img.data[pxl+3] = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var text_scale = 2; //using a different scaling factor for text feels like cheating... but it looks better
|
||
|
this.DrawChar = function(char, row, col, leftPos) {
|
||
|
char.offset = {
|
||
|
x: char.base_offset.x,
|
||
|
y: char.base_offset.y
|
||
|
}; // compute render offset *every* frame
|
||
|
|
||
|
char.SetPosition(row,col);
|
||
|
char.ApplyEffects(effectTime);
|
||
|
|
||
|
var charData = char.bitmap;
|
||
|
|
||
|
var top = (4 * scale) + (row * 2 * scale) + (row * font.getHeight() * text_scale) + Math.floor( char.offset.y );
|
||
|
var left = (4 * scale) + (leftPos * text_scale) + Math.floor( char.offset.x );
|
||
|
|
||
|
var debug_r = Math.random() * 255;
|
||
|
|
||
|
for (var y = 0; y < char.height; y++) {
|
||
|
for (var x = 0; x < char.width; x++) {
|
||
|
|
||
|
var i = (y * char.width) + x;
|
||
|
if ( charData[i] == 1 ) {
|
||
|
|
||
|
//scaling nonsense
|
||
|
for (var sy = 0; sy < text_scale; sy++) {
|
||
|
for (var sx = 0; sx < text_scale; sx++) {
|
||
|
var pxl = 4 * ( ((top+(y*text_scale)+sy) * (textboxInfo.width*scale)) + (left+(x*text_scale)+sx) );
|
||
|
textboxInfo.img.data[pxl+0] = char.color.r;
|
||
|
textboxInfo.img.data[pxl+1] = char.color.g;
|
||
|
textboxInfo.img.data[pxl+2] = char.color.b;
|
||
|
textboxInfo.img.data[pxl+3] = char.color.a;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// else {
|
||
|
// // DEBUG
|
||
|
|
||
|
// //scaling nonsense
|
||
|
// for (var sy = 0; sy < text_scale; sy++) {
|
||
|
// for (var sx = 0; sx < text_scale; sx++) {
|
||
|
// var pxl = 4 * ( ((top+(y*text_scale)+sy) * (textboxInfo.width*scale)) + (left+(x*text_scale)+sx) );
|
||
|
// textboxInfo.img.data[pxl+0] = debug_r;
|
||
|
// textboxInfo.img.data[pxl+1] = 0;
|
||
|
// textboxInfo.img.data[pxl+2] = 0;
|
||
|
// textboxInfo.img.data[pxl+3] = 255;
|
||
|
// }
|
||
|
// }
|
||
|
// }
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// call printHandler for character
|
||
|
char.OnPrint();
|
||
|
};
|
||
|
|
||
|
var effectTime = 0; // TODO this variable should live somewhere better
|
||
|
this.Draw = function(buffer, dt) {
|
||
|
effectTime += dt;
|
||
|
|
||
|
this.ClearTextbox();
|
||
|
|
||
|
buffer.ForEachActiveChar(this.DrawChar);
|
||
|
|
||
|
if (buffer.CanContinue()) {
|
||
|
this.DrawNextArrow();
|
||
|
}
|
||
|
|
||
|
this.DrawTextbox();
|
||
|
|
||
|
if (buffer.DidPageFinishThisFrame() && onPageFinish != null) {
|
||
|
onPageFinish();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/* this is a hook for GIF rendering */
|
||
|
var onPageFinish = null;
|
||
|
this.SetPageFinishHandler = function(handler) {
|
||
|
onPageFinish = handler;
|
||
|
};
|
||
|
|
||
|
this.Reset = function() {
|
||
|
effectTime = 0;
|
||
|
// TODO - anything else?
|
||
|
}
|
||
|
|
||
|
// this.CharsPerRow = function() {
|
||
|
// return textboxInfo.charsPerRow;
|
||
|
// }
|
||
|
}
|
||
|
|
||
|
|
||
|
var DialogBuffer = function() {
|
||
|
var buffer = [[[]]]; // holds dialog in an array buffer
|
||
|
var pageIndex = 0;
|
||
|
var rowIndex = 0;
|
||
|
var charIndex = 0;
|
||
|
var nextCharTimer = 0;
|
||
|
var nextCharMaxTime = 50; // in milliseconds
|
||
|
var isDialogReadyToContinue = false;
|
||
|
var activeTextEffects = [];
|
||
|
var font = null;
|
||
|
var arabicHandler = new ArabicHandler();
|
||
|
var onDialogEndCallbacks = [];
|
||
|
|
||
|
this.SetFont = function(f) {
|
||
|
font = f;
|
||
|
}
|
||
|
|
||
|
this.CurPage = function() { return buffer[ pageIndex ]; };
|
||
|
this.CurRow = function() { return this.CurPage()[ rowIndex ]; };
|
||
|
this.CurChar = function() { return this.CurRow()[ charIndex ]; };
|
||
|
this.CurPageCount = function() { return buffer.length; };
|
||
|
this.CurRowCount = function() { return this.CurPage().length; };
|
||
|
this.CurCharCount = function() { return this.CurRow().length; };
|
||
|
|
||
|
this.ForEachActiveChar = function(handler) { // Iterates over visible characters on the active page
|
||
|
var rowCount = rowIndex + 1;
|
||
|
for (var i = 0; i < rowCount; i++) {
|
||
|
var row = this.CurPage()[i];
|
||
|
var charCount = (i == rowIndex) ? charIndex+1 : row.length;
|
||
|
// console.log(charCount);
|
||
|
|
||
|
var leftPos = 0;
|
||
|
if (textDirection === TextDirection.RightToLeft) {
|
||
|
leftPos = 24 * 8; // hack -- I think this is correct?
|
||
|
}
|
||
|
|
||
|
for(var j = 0; j < charCount; j++) {
|
||
|
var char = row[j];
|
||
|
if(char) {
|
||
|
if (textDirection === TextDirection.RightToLeft) {
|
||
|
leftPos -= char.spacing;
|
||
|
}
|
||
|
// console.log(j + " " + leftPos);
|
||
|
|
||
|
// handler( char, i /*rowIndex*/, j /*colIndex*/ );
|
||
|
handler(char, i /*rowIndex*/, j /*colIndex*/, leftPos)
|
||
|
|
||
|
if (textDirection === TextDirection.LeftToRight) {
|
||
|
leftPos += char.spacing;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.Reset = function() {
|
||
|
buffer = [[[]]];
|
||
|
pageIndex = 0;
|
||
|
rowIndex = 0;
|
||
|
charIndex = 0;
|
||
|
isDialogReadyToContinue = false;
|
||
|
|
||
|
afterManualPagebreak = false;
|
||
|
|
||
|
activeTextEffects = [];
|
||
|
|
||
|
onDialogEndCallbacks = [];
|
||
|
|
||
|
isActive = false;
|
||
|
};
|
||
|
|
||
|
this.DoNextChar = function() {
|
||
|
nextCharTimer = 0; //reset timer
|
||
|
|
||
|
//time to update characters
|
||
|
if (charIndex + 1 < this.CurCharCount()) {
|
||
|
//add char to current row
|
||
|
charIndex++;
|
||
|
}
|
||
|
else if (rowIndex + 1 < this.CurRowCount()) {
|
||
|
//start next row
|
||
|
rowIndex++;
|
||
|
charIndex = 0;
|
||
|
}
|
||
|
else {
|
||
|
//the page is full!
|
||
|
isDialogReadyToContinue = true;
|
||
|
didPageFinishThisFrame = true;
|
||
|
}
|
||
|
|
||
|
if (this.CurChar() != null) {
|
||
|
if (this.CurChar().isPageBreak) {
|
||
|
// special case for page break marker character!
|
||
|
isDialogReadyToContinue = true;
|
||
|
didPageFinishThisFrame = true;
|
||
|
}
|
||
|
|
||
|
this.CurChar().OnPrint(); // make sure we hit the callback before we run out of text
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.Update = function(dt) {
|
||
|
didPageFinishThisFrame = false;
|
||
|
didFlipPageThisFrame = false;
|
||
|
// this.Draw(dt); // TODO move into a renderer object
|
||
|
if (isDialogReadyToContinue) {
|
||
|
return; //waiting for dialog to be advanced by player
|
||
|
}
|
||
|
|
||
|
nextCharTimer += dt; //tick timer
|
||
|
|
||
|
if (nextCharTimer > nextCharMaxTime) {
|
||
|
this.DoNextChar();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.Skip = function() {
|
||
|
console.log("SKIPPP");
|
||
|
didPageFinishThisFrame = false;
|
||
|
didFlipPageThisFrame = false;
|
||
|
// add new characters until you get to the end of the current line of dialog
|
||
|
while (rowIndex < this.CurRowCount()) {
|
||
|
this.DoNextChar();
|
||
|
|
||
|
if(isDialogReadyToContinue) {
|
||
|
//make sure to push the rowIndex past the end to break out of the loop
|
||
|
rowIndex++;
|
||
|
charIndex = 0;
|
||
|
}
|
||
|
}
|
||
|
rowIndex = this.CurRowCount()-1;
|
||
|
charIndex = this.CurCharCount()-1;
|
||
|
};
|
||
|
|
||
|
this.FlipPage = function() {
|
||
|
didFlipPageThisFrame = true;
|
||
|
isDialogReadyToContinue = false;
|
||
|
pageIndex++;
|
||
|
rowIndex = 0;
|
||
|
charIndex = 0;
|
||
|
}
|
||
|
|
||
|
this.EndDialog = function() {
|
||
|
isActive = false; // no more text to show... this should be a sign to stop rendering dialog
|
||
|
|
||
|
for (var i = 0; i < onDialogEndCallbacks.length; i++) {
|
||
|
onDialogEndCallbacks[i]();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var afterManualPagebreak = false; // is it bad to track this state like this?
|
||
|
|
||
|
this.Continue = function() {
|
||
|
console.log("CONTINUE");
|
||
|
|
||
|
// if we used a page break character to continue we need
|
||
|
// to run whatever is in the script afterwards! // TODO : make this comment better
|
||
|
if (this.CurChar().isPageBreak) {
|
||
|
// hacky: always treat a page break as the end of dialog
|
||
|
// if there's more dialog later we re-activate the dialog buffer
|
||
|
this.EndDialog();
|
||
|
afterManualPagebreak = true;
|
||
|
this.CurChar().OnContinue();
|
||
|
return false;
|
||
|
}
|
||
|
if (pageIndex + 1 < this.CurPageCount()) {
|
||
|
console.log("FLIP PAGE!");
|
||
|
//start next page
|
||
|
this.FlipPage();
|
||
|
return true; /* hasMoreDialog */
|
||
|
}
|
||
|
else {
|
||
|
console.log("END DIALOG!");
|
||
|
//end dialog mode
|
||
|
this.EndDialog();
|
||
|
return false; /* hasMoreDialog */
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var isActive = false;
|
||
|
this.IsActive = function() { return isActive; };
|
||
|
|
||
|
this.OnDialogEnd = function(callback) {
|
||
|
if (!isActive) {
|
||
|
callback();
|
||
|
}
|
||
|
else {
|
||
|
onDialogEndCallbacks.push(callback);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.CanContinue = function() { return isDialogReadyToContinue; };
|
||
|
|
||
|
function DialogChar(effectList) {
|
||
|
this.effectList = effectList.slice(); // clone effect list (since it can change between chars)
|
||
|
|
||
|
this.color = { r:255, g:255, b:255, a:255 };
|
||
|
this.offset = { x:0, y:0 }; // in pixels (screen pixels?)
|
||
|
|
||
|
this.col = 0;
|
||
|
this.row = 0;
|
||
|
|
||
|
this.SetPosition = function(row,col) {
|
||
|
// console.log("SET POS");
|
||
|
// console.log(this);
|
||
|
this.row = row;
|
||
|
this.col = col;
|
||
|
}
|
||
|
|
||
|
this.ApplyEffects = function(time) {
|
||
|
// console.log("APPLY EFFECTS! " + time);
|
||
|
for(var i = 0; i < this.effectList.length; i++) {
|
||
|
var effectName = this.effectList[i];
|
||
|
// console.log("FX " + effectName);
|
||
|
TextEffects[ effectName ].DoEffect( this, time );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var printHandler = null; // optional function to be called once on printing character
|
||
|
this.SetPrintHandler = function(handler) {
|
||
|
printHandler = handler;
|
||
|
}
|
||
|
this.OnPrint = function() {
|
||
|
if (printHandler != null) {
|
||
|
// console.log("PRINT HANDLER ---- DIALOG BUFFER");
|
||
|
printHandler();
|
||
|
printHandler = null; // only call handler once (hacky)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.bitmap = [];
|
||
|
this.width = 0;
|
||
|
this.height = 0;
|
||
|
this.base_offset = { // hacky name
|
||
|
x: 0,
|
||
|
y: 0
|
||
|
};
|
||
|
this.spacing = 0;
|
||
|
}
|
||
|
|
||
|
function DialogFontChar(font, char, effectList) {
|
||
|
Object.assign(this, new DialogChar(effectList));
|
||
|
|
||
|
var charData = font.getChar(char);
|
||
|
this.bitmap = charData.data;
|
||
|
this.width = charData.width;
|
||
|
this.height = charData.height;
|
||
|
this.base_offset.x = charData.offset.x;
|
||
|
this.base_offset.y = charData.offset.y;
|
||
|
this.spacing = charData.spacing;
|
||
|
}
|
||
|
|
||
|
function DialogDrawingChar(drawingId, effectList) {
|
||
|
Object.assign(this, new DialogChar(effectList));
|
||
|
|
||
|
var imageData = renderer.GetImageSource(drawingId)[0];
|
||
|
var imageDataFlat = [];
|
||
|
for (var i = 0; i < imageData.length; i++) {
|
||
|
// console.log(imageData[i]);
|
||
|
imageDataFlat = imageDataFlat.concat(imageData[i]);
|
||
|
}
|
||
|
|
||
|
this.bitmap = imageDataFlat;
|
||
|
this.width = 8;
|
||
|
this.height = 8;
|
||
|
this.spacing = 8;
|
||
|
}
|
||
|
|
||
|
function DialogScriptControlChar() {
|
||
|
Object.assign(this, new DialogChar([]));
|
||
|
|
||
|
this.width = 0;
|
||
|
this.height = 0;
|
||
|
this.spacing = 0;
|
||
|
}
|
||
|
|
||
|
// is a control character really the best way to handle page breaks?
|
||
|
function DialogPageBreakChar() {
|
||
|
Object.assign(this, new DialogChar([]));
|
||
|
|
||
|
this.width = 0;
|
||
|
this.height = 0;
|
||
|
this.spacing = 0;
|
||
|
|
||
|
this.isPageBreak = true;
|
||
|
|
||
|
var continueHandler = null;
|
||
|
|
||
|
this.SetContinueHandler = function(handler) {
|
||
|
continueHandler = handler;
|
||
|
}
|
||
|
|
||
|
this.OnContinue = function() {
|
||
|
if (continueHandler) {
|
||
|
continueHandler();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function AddWordToCharArray(charArray,word,effectList) {
|
||
|
for(var i = 0; i < word.length; i++) {
|
||
|
charArray.push( new DialogFontChar( font, word[i], effectList ) );
|
||
|
}
|
||
|
return charArray;
|
||
|
}
|
||
|
|
||
|
function GetCharArrayWidth(charArray) {
|
||
|
var width = 0;
|
||
|
for(var i = 0; i < charArray.length; i++) {
|
||
|
width += charArray[i].spacing;
|
||
|
}
|
||
|
return width;
|
||
|
}
|
||
|
|
||
|
function GetStringWidth(str) {
|
||
|
var width = 0;
|
||
|
for (var i = 0; i < str.length; i++) {
|
||
|
var charData = font.getChar(str[i]);
|
||
|
width += charData.spacing;
|
||
|
}
|
||
|
return width;
|
||
|
}
|
||
|
|
||
|
var pixelsPerRow = 192; // hard-coded fun times!!!
|
||
|
|
||
|
this.AddScriptReturn = function(onReturnHandler) {
|
||
|
var curPageIndex = buffer.length - 1;
|
||
|
var curRowIndex = buffer[curPageIndex].length - 1;
|
||
|
var curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
|
||
|
var controlChar = new DialogScriptControlChar();
|
||
|
controlChar.SetPrintHandler(onReturnHandler);
|
||
|
|
||
|
curRowArr.push(controlChar);
|
||
|
|
||
|
isActive = true;
|
||
|
}
|
||
|
|
||
|
this.AddDrawing = function(drawingId) {
|
||
|
// console.log("DRAWING ID " + drawingId);
|
||
|
|
||
|
var curPageIndex = buffer.length - 1;
|
||
|
var curRowIndex = buffer[curPageIndex].length - 1;
|
||
|
var curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
|
||
|
var drawingChar = new DialogDrawingChar(drawingId, activeTextEffects);
|
||
|
|
||
|
var rowLength = GetCharArrayWidth(curRowArr);
|
||
|
|
||
|
// TODO : clean up copy-pasted code here :/
|
||
|
if (afterManualPagebreak) {
|
||
|
this.FlipPage(); // hacky
|
||
|
|
||
|
buffer[curPageIndex][curRowIndex] = curRowArr;
|
||
|
buffer.push([]);
|
||
|
curPageIndex++;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex = 0;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
curRowArr.push(drawingChar);
|
||
|
|
||
|
afterManualPagebreak = false;
|
||
|
}
|
||
|
else if (rowLength + drawingChar.spacing <= pixelsPerRow || rowLength <= 0) {
|
||
|
//stay on same row
|
||
|
curRowArr.push(drawingChar);
|
||
|
}
|
||
|
else if (curRowIndex == 0) {
|
||
|
//start next row
|
||
|
buffer[curPageIndex][curRowIndex] = curRowArr;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex++;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
curRowArr.push(drawingChar);
|
||
|
}
|
||
|
else {
|
||
|
//start next page
|
||
|
buffer[curPageIndex][curRowIndex] = curRowArr;
|
||
|
buffer.push([]);
|
||
|
curPageIndex++;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex = 0;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
curRowArr.push(drawingChar);
|
||
|
}
|
||
|
|
||
|
isActive = true; // this feels like a bad way to do this???
|
||
|
}
|
||
|
|
||
|
// TODO : convert this into something that takes DialogChar arrays
|
||
|
this.AddText = function(textStr) {
|
||
|
console.log("ADD TEXT " + textStr);
|
||
|
|
||
|
//process dialog so it's easier to display
|
||
|
var words = textStr.split(" ");
|
||
|
|
||
|
// var curPageIndex = this.CurPageCount() - 1;
|
||
|
// var curRowIndex = this.CurRowCount() - 1;
|
||
|
// var curRowArr = this.CurRow();
|
||
|
|
||
|
var curPageIndex = buffer.length - 1;
|
||
|
var curRowIndex = buffer[curPageIndex].length - 1;
|
||
|
var curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
|
||
|
for (var i = 0; i < words.length; i++) {
|
||
|
var word = words[i];
|
||
|
if (arabicHandler.ContainsArabicCharacters(word)) {
|
||
|
word = arabicHandler.ShapeArabicCharacters(word);
|
||
|
}
|
||
|
|
||
|
var wordWithPrecedingSpace = ((i == 0) ? "" : " ") + word;
|
||
|
var wordLength = GetStringWidth(wordWithPrecedingSpace);
|
||
|
|
||
|
var rowLength = GetCharArrayWidth(curRowArr);
|
||
|
|
||
|
if (afterManualPagebreak) {
|
||
|
this.FlipPage();
|
||
|
|
||
|
// hacky copied bit for page breaks
|
||
|
buffer[curPageIndex][curRowIndex] = curRowArr;
|
||
|
buffer.push([]);
|
||
|
curPageIndex++;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex = 0;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
curRowArr = AddWordToCharArray(curRowArr, word, activeTextEffects);
|
||
|
|
||
|
afterManualPagebreak = false;
|
||
|
}
|
||
|
else if (rowLength + wordLength <= pixelsPerRow || rowLength <= 0) {
|
||
|
//stay on same row
|
||
|
curRowArr = AddWordToCharArray(curRowArr, wordWithPrecedingSpace, activeTextEffects);
|
||
|
}
|
||
|
else if (curRowIndex == 0) {
|
||
|
//start next row
|
||
|
buffer[curPageIndex][curRowIndex] = curRowArr;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex++;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
curRowArr = AddWordToCharArray(curRowArr, word, activeTextEffects);
|
||
|
}
|
||
|
else {
|
||
|
//start next page
|
||
|
buffer[curPageIndex][curRowIndex] = curRowArr;
|
||
|
buffer.push([]);
|
||
|
curPageIndex++;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex = 0;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
curRowArr = AddWordToCharArray(curRowArr, word, activeTextEffects);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//destroy any empty stuff
|
||
|
var lastPage = buffer[buffer.length-1];
|
||
|
var lastRow = lastPage[lastPage.length-1];
|
||
|
if (lastRow.length == 0) {
|
||
|
lastPage.splice(lastPage.length-1, 1);
|
||
|
}
|
||
|
if (lastPage.length == 0) {
|
||
|
buffer.splice(buffer.length-1, 1);
|
||
|
}
|
||
|
|
||
|
//finish up
|
||
|
lastPage = buffer[buffer.length-1];
|
||
|
lastRow = lastPage[lastPage.length-1];
|
||
|
if (lastRow.length > 0) {
|
||
|
var lastChar = lastRow[lastRow.length-1];
|
||
|
}
|
||
|
|
||
|
// console.log(buffer);
|
||
|
|
||
|
isActive = true;
|
||
|
};
|
||
|
|
||
|
this.AddLinebreak = function() {
|
||
|
var lastPage = buffer[buffer.length-1];
|
||
|
if (lastPage.length <= 1) {
|
||
|
// console.log("LINEBREAK - NEW ROW ");
|
||
|
// add new row
|
||
|
lastPage.push([]);
|
||
|
}
|
||
|
else {
|
||
|
// add new page
|
||
|
buffer.push([[]]);
|
||
|
}
|
||
|
// console.log(buffer);
|
||
|
|
||
|
isActive = true;
|
||
|
}
|
||
|
|
||
|
this.AddPagebreak = function(onReturnHandler) {
|
||
|
var curPageIndex = buffer.length - 1;
|
||
|
var curRowIndex = buffer[curPageIndex].length - 1;
|
||
|
var curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
|
||
|
// need to actually create a whole new page if following another pagebreak character
|
||
|
if (this.CurChar() && this.CurChar().isPageBreak) {
|
||
|
buffer.push([]);
|
||
|
curPageIndex++;
|
||
|
buffer[curPageIndex].push([]);
|
||
|
curRowIndex = 0;
|
||
|
curRowArr = buffer[curPageIndex][curRowIndex];
|
||
|
}
|
||
|
|
||
|
var pagebreakChar = new DialogPageBreakChar();
|
||
|
pagebreakChar.SetContinueHandler(onReturnHandler);
|
||
|
|
||
|
curRowArr.push(pagebreakChar);
|
||
|
|
||
|
isActive = true;
|
||
|
}
|
||
|
|
||
|
/* new text effects */
|
||
|
this.HasTextEffect = function(name) {
|
||
|
return activeTextEffects.indexOf( name ) > -1;
|
||
|
}
|
||
|
this.AddTextEffect = function(name) {
|
||
|
activeTextEffects.push( name );
|
||
|
}
|
||
|
this.RemoveTextEffect = function(name) {
|
||
|
activeTextEffects.splice( activeTextEffects.indexOf( name ), 1 );
|
||
|
}
|
||
|
|
||
|
/* this is a hook for GIF rendering */
|
||
|
var didPageFinishThisFrame = false;
|
||
|
this.DidPageFinishThisFrame = function(){ return didPageFinishThisFrame; };
|
||
|
|
||
|
var didFlipPageThisFrame = false;
|
||
|
this.DidFlipPageThisFrame = function(){ return didFlipPageThisFrame; };
|
||
|
|
||
|
// this.SetCharsPerRow = function(num){ charsPerRow = num; }; // hacky
|
||
|
};
|
||
|
|
||
|
/* ARABIC */
|
||
|
var ArabicHandler = function() {
|
||
|
|
||
|
var arabicCharStart = 0x0621;
|
||
|
var arabicCharEnd = 0x064E;
|
||
|
|
||
|
var CharacterForm = {
|
||
|
Isolated : 0,
|
||
|
Final : 1,
|
||
|
Initial : 2,
|
||
|
Middle : 3
|
||
|
};
|
||
|
|
||
|
// map glyphs to their character forms
|
||
|
var glyphForms = {
|
||
|
/* Isolated, Final, Initial, Middle Forms */
|
||
|
0x0621: [0xFE80,0xFE80,0xFE80,0xFE80], /* HAMZA */
|
||
|
0x0622: [0xFE81,0xFE82,0xFE81,0xFE82], /* ALEF WITH MADDA ABOVE */
|
||
|
0x0623: [0xFE83,0xFE84,0xFE83,0xFE84], /* ALEF WITH HAMZA ABOVE */
|
||
|
0x0624: [0xFE85,0xFE86,0xFE85,0xFE86], /* WAW WITH HAMZA ABOVE */
|
||
|
0x0625: [0xFE87,0xFE88,0xFE87,0xFE88], /* ALEF WITH HAMZA BELOW */
|
||
|
0x0626: [0xFE89,0xFE8A,0xFE8B,0xFE8C], /* YEH WITH HAMZA ABOVE */
|
||
|
0x0627: [0xFE8D,0xFE8E,0xFE8D,0xFE8E], /* ALEF */
|
||
|
0x0628: [0xFE8F,0xFE90,0xFE91,0xFE92], /* BEH */
|
||
|
0x0629: [0xFE93,0xFE94,0xFE93,0xFE94], /* TEH MARBUTA */
|
||
|
0x062A: [0xFE95,0xFE96,0xFE97,0xFE98], /* TEH */
|
||
|
0x062B: [0xFE99,0xFE9A,0xFE9B,0xFE9C], /* THEH */
|
||
|
0x062C: [0xFE9D,0xFE9E,0xFE9F,0xFEA0], /* JEEM */
|
||
|
0x062D: [0xFEA1,0xFEA2,0xFEA3,0xFEA4], /* HAH */
|
||
|
0x062E: [0xFEA5,0xFEA6,0xFEA7,0xFEA8], /* KHAH */
|
||
|
0x062F: [0xFEA9,0xFEAA,0xFEA9,0xFEAA], /* DAL */
|
||
|
0x0630: [0xFEAB,0xFEAC,0xFEAB,0xFEAC], /* THAL */
|
||
|
0x0631: [0xFEAD,0xFEAE,0xFEAD,0xFEAE], /* RAA */
|
||
|
0x0632: [0xFEAF,0xFEB0,0xFEAF,0xFEB0], /* ZAIN */
|
||
|
0x0633: [0xFEB1,0xFEB2,0xFEB3,0xFEB4], /* SEEN */
|
||
|
0x0634: [0xFEB5,0xFEB6,0xFEB7,0xFEB8], /* SHEEN */
|
||
|
0x0635: [0xFEB9,0xFEBA,0xFEBB,0xFEBC], /* SAD */
|
||
|
0x0636: [0xFEBD,0xFEBE,0xFEBF,0xFEC0], /* DAD */
|
||
|
0x0637: [0xFEC1,0xFEC2,0xFEC3,0xFEC4], /* TAH */
|
||
|
0x0638: [0xFEC5,0xFEC6,0xFEC7,0xFEC8], /* ZAH */
|
||
|
0x0639: [0xFEC9,0xFECA,0xFECB,0xFECC], /* AIN */
|
||
|
0x063A: [0xFECD,0xFECE,0xFECF,0xFED0], /* GHAIN */
|
||
|
0x063B: [0x0000,0x0000,0x0000,0x0000], /* space */
|
||
|
0x063C: [0x0000,0x0000,0x0000,0x0000], /* space */
|
||
|
0x063D: [0x0000,0x0000,0x0000,0x0000], /* space */
|
||
|
0x063E: [0x0000,0x0000,0x0000,0x0000], /* space */
|
||
|
0x063F: [0x0000,0x0000,0x0000,0x0000], /* space */
|
||
|
0x0640: [0x0640,0x0640,0x0640,0x0640], /* TATWEEL */
|
||
|
0x0641: [0xFED1,0xFED2,0xFED3,0xFED4], /* FAA */
|
||
|
0x0642: [0xFED5,0xFED6,0xFED7,0xFED8], /* QAF */
|
||
|
0x0643: [0xFED9,0xFEDA,0xFEDB,0xFEDC], /* KAF */
|
||
|
0x0644: [0xFEDD,0xFEDE,0xFEDF,0xFEE0], /* LAM */
|
||
|
0x0645: [0xFEE1,0xFEE2,0xFEE3,0xFEE4], /* MEEM */
|
||
|
0x0646: [0xFEE5,0xFEE6,0xFEE7,0xFEE8], /* NOON */
|
||
|
0x0647: [0xFEE9,0xFEEA,0xFEEB,0xFEEC], /* HEH */
|
||
|
0x0648: [0xFEED,0xFEEE,0xFEED,0xFEEE], /* WAW */
|
||
|
0x0649: [0xFEEF,0xFEF0,0xFBE8,0xFBE9], /* ALEF MAKSURA */
|
||
|
0x064A: [0xFEF1,0xFEF2,0xFEF3,0xFEF4], /* YEH */
|
||
|
0x064B: [0xFEF5,0xFEF6,0xFEF5,0xFEF6], /* LAM ALEF MADD*/
|
||
|
0x064C: [0xFEF7,0xFEF8,0xFEF7,0xFEF8], /* LAM ALEF HAMZA ABOVE*/
|
||
|
0x064D: [0xFEF9,0xFEFa,0xFEF9,0xFEFa], /* LAM ALEF HAMZA BELOW*/
|
||
|
0x064E: [0xFEFb,0xFEFc,0xFEFb,0xFEFc], /* LAM ALEF */
|
||
|
};
|
||
|
|
||
|
var disconnectedCharacters = [0x0621,0x0622,0x0623,0x0624,0x0625,0x0627,0x062f,0x0630,0x0631,0x0632,0x0648,0x0649,0x064b,0x064c,0x064d,0x064e];
|
||
|
|
||
|
function IsArabicCharacter(char) {
|
||
|
var code = char.charCodeAt(0);
|
||
|
return (code >= arabicCharStart && code <= arabicCharEnd);
|
||
|
}
|
||
|
|
||
|
function ContainsArabicCharacters(word) {
|
||
|
for (var i = 0; i < word.length; i++) {
|
||
|
if (IsArabicCharacter(word[i])) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function IsDisconnectedCharacter(char) {
|
||
|
var code = char.charCodeAt(0);
|
||
|
return disconnectedCharacters.indexOf(code) != -1;
|
||
|
}
|
||
|
|
||
|
function ShapeArabicCharacters(word) {
|
||
|
var shapedWord = "";
|
||
|
|
||
|
for (var i = 0; i < word.length; i++) {
|
||
|
if (!IsArabicCharacter(word[i])) {
|
||
|
shapedWord += word[i];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var connectedToPreviousChar = i-1 >= 0 && IsArabicCharacter(word[i-1]) && !IsDisconnectedCharacter(word[i-1]);
|
||
|
|
||
|
var connectedToNextChar = i+1 < word.length && IsArabicCharacter(word[i+1]) && !IsDisconnectedCharacter(word[i]);
|
||
|
|
||
|
var form;
|
||
|
if (!connectedToPreviousChar && !connectedToNextChar) {
|
||
|
form = CharacterForm.Isolated;
|
||
|
}
|
||
|
else if (connectedToPreviousChar && !connectedToNextChar) {
|
||
|
form = CharacterForm.Final;
|
||
|
}
|
||
|
else if (!connectedToPreviousChar && connectedToNextChar) {
|
||
|
form = CharacterForm.Initial;
|
||
|
}
|
||
|
else if (connectedToPreviousChar && connectedToNextChar) {
|
||
|
form = CharacterForm.Middle;
|
||
|
}
|
||
|
|
||
|
var code = word[i].charCodeAt(0);
|
||
|
|
||
|
// handle lam alef special case
|
||
|
if (code == 0x0644 && connectedToNextChar) {
|
||
|
var nextCode = word[i+1].charCodeAt(0);
|
||
|
var specialCode = null;
|
||
|
if (nextCode == 0x0622) {
|
||
|
// alef madd
|
||
|
specialCode = glyphForms[0x064b][form];
|
||
|
}
|
||
|
else if (nextCode == 0x0623) {
|
||
|
// hamza above
|
||
|
specialCode = glyphForms[0x064c][form];
|
||
|
}
|
||
|
else if (nextCode == 0x0625) {
|
||
|
// hamza below
|
||
|
specialCode = glyphForms[0x064d][form];
|
||
|
}
|
||
|
else if (nextCode == 0x0627) {
|
||
|
// alef
|
||
|
specialCode = glyphForms[0x064e][form];
|
||
|
}
|
||
|
|
||
|
if (specialCode != null) {
|
||
|
shapedWord += String.fromCharCode(specialCode);
|
||
|
i++; // skip a step
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// hacky?
|
||
|
if (form === CharacterForm.Isolated) {
|
||
|
shapedWord += word[i];
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
var shapedCode = glyphForms[code][form];
|
||
|
shapedWord += String.fromCharCode(shapedCode);
|
||
|
}
|
||
|
|
||
|
return shapedWord;
|
||
|
}
|
||
|
|
||
|
this.ContainsArabicCharacters = ContainsArabicCharacters;
|
||
|
this.ShapeArabicCharacters = ShapeArabicCharacters;
|
||
|
}
|
||
|
|
||
|
/* NEW TEXT EFFECTS */
|
||
|
var TextEffects = new Map();
|
||
|
|
||
|
var RainbowEffect = function() { // TODO - should it be an object or just a method?
|
||
|
this.DoEffect = function(char,time) {
|
||
|
// console.log("RAINBOW!!!");
|
||
|
// console.log(char);
|
||
|
// console.log(char.color);
|
||
|
// console.log(char.col);
|
||
|
|
||
|
var h = Math.abs( Math.sin( (time / 600) - (char.col / 8) ) );
|
||
|
var rgb = hslToRgb( h, 1, 0.5 );
|
||
|
char.color.r = rgb[0];
|
||
|
char.color.g = rgb[1];
|
||
|
char.color.b = rgb[2];
|
||
|
char.color.a = 255;
|
||
|
}
|
||
|
};
|
||
|
TextEffects["rbw"] = new RainbowEffect();
|
||
|
|
||
|
var ColorEffect = function(index) {
|
||
|
this.DoEffect = function(char) {
|
||
|
var pal = getPal( curPal() );
|
||
|
var color = pal[ parseInt( index ) ];
|
||
|
// console.log(color);
|
||
|
char.color.r = color[0];
|
||
|
char.color.g = color[1];
|
||
|
char.color.b = color[2];
|
||
|
char.color.a = 255;
|
||
|
}
|
||
|
};
|
||
|
TextEffects["clr1"] = new ColorEffect(0);
|
||
|
TextEffects["clr2"] = new ColorEffect(1); // TODO : should I use parameters instead of special names?
|
||
|
TextEffects["clr3"] = new ColorEffect(2);
|
||
|
|
||
|
var WavyEffect = function() {
|
||
|
this.DoEffect = function(char,time) {
|
||
|
char.offset.y += Math.sin( (time / 250) - (char.col / 2) ) * 4;
|
||
|
}
|
||
|
};
|
||
|
TextEffects["wvy"] = new WavyEffect();
|
||
|
|
||
|
var ShakyEffect = function() {
|
||
|
function disturb(func,time,offset,mult1,mult2) {
|
||
|
return func( (time * mult1) - (offset * mult2) );
|
||
|
}
|
||
|
|
||
|
this.DoEffect = function(char,time) {
|
||
|
char.offset.y += 3
|
||
|
* disturb(Math.sin,time,char.col,0.1,0.5)
|
||
|
* disturb(Math.cos,time,char.col,0.3,0.2)
|
||
|
* disturb(Math.sin,time,char.row,2.0,1.0);
|
||
|
char.offset.x += 3
|
||
|
* disturb(Math.cos,time,char.row,0.1,1.0)
|
||
|
* disturb(Math.sin,time,char.col,3.0,0.7)
|
||
|
* disturb(Math.cos,time,char.col,0.2,0.3);
|
||
|
}
|
||
|
};
|
||
|
TextEffects["shk"] = new ShakyEffect();
|
||
|
|
||
|
var DebugHighlightEffect = function() {
|
||
|
this.DoEffect = function(char) {
|
||
|
char.color.r = 255;
|
||
|
char.color.g = 255;
|
||
|
char.color.b = 0;
|
||
|
char.color.a = 255;
|
||
|
}
|
||
|
}
|
||
|
TextEffects["_debug_highlight"] = new DebugHighlightEffect();
|
||
|
|
||
|
} // Dialog()
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
/*
|
||
|
TODO
|
||
|
- reset renderer function
|
||
|
- react to changes in: drawings, palettes
|
||
|
- possible future plan: limit size of cache (remove old images)
|
||
|
- change image store path from (pal > col > draw) to (draw > pal > col)
|
||
|
- get rid of old getSpriteImage (etc) methods
|
||
|
- get editor working again [in progress]
|
||
|
- move debug timer class into core (seems useful)
|
||
|
*/
|
||
|
|
||
|
function Renderer(tilesize, scale) {
|
||
|
|
||
|
console.log("!!!!! NEW RENDERER");
|
||
|
|
||
|
var imageStore = { // TODO : rename to imageCache
|
||
|
source: {},
|
||
|
render: {}
|
||
|
};
|
||
|
|
||
|
var palettes = null; // TODO : need null checks?
|
||
|
var context = null;
|
||
|
|
||
|
function setPalettes(paletteObj) {
|
||
|
palettes = paletteObj;
|
||
|
|
||
|
// TODO : should this really clear out the render cache?
|
||
|
imageStore.render = {};
|
||
|
}
|
||
|
|
||
|
function getPaletteColor(paletteId, colorIndex) {
|
||
|
if (palettes[paletteId] === undefined) {
|
||
|
paletteId = "default";
|
||
|
}
|
||
|
|
||
|
var palette = palettes[paletteId];
|
||
|
|
||
|
if (colorIndex > palette.colors.length) { // do I need this failure case? (seems un-reliable)
|
||
|
colorIndex = 0;
|
||
|
}
|
||
|
|
||
|
var color = palette.colors[colorIndex];
|
||
|
|
||
|
return {
|
||
|
r : color[0],
|
||
|
g : color[1],
|
||
|
b : color[2]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var debugRenderCount = 0;
|
||
|
|
||
|
// TODO : change image store path from (pal > col > draw) to (draw > pal > col)
|
||
|
function renderImage(drawing, paletteId) {
|
||
|
// debugRenderCount++;
|
||
|
// console.log("RENDER COUNT " + debugRenderCount);
|
||
|
|
||
|
var col = drawing.col;
|
||
|
var colStr = "" + col;
|
||
|
var pal = paletteId;
|
||
|
var drwId = drawing.drw;
|
||
|
var imgSrc = imageStore.source[ drawing.drw ];
|
||
|
|
||
|
// initialize render cache entry
|
||
|
if (imageStore.render[drwId] === undefined || imageStore.render[drwId] === null) {
|
||
|
imageStore.render[drwId] = {};
|
||
|
}
|
||
|
|
||
|
if (imageStore.render[drwId][pal] === undefined || imageStore.render[drwId][pal] === null) {
|
||
|
imageStore.render[drwId][pal] = {};
|
||
|
}
|
||
|
|
||
|
// create array of ImageData frames
|
||
|
imageStore.render[drwId][pal][colStr] = [];
|
||
|
|
||
|
for (var i = 0; i < imgSrc.length; i++) {
|
||
|
var frameSrc = imgSrc[i];
|
||
|
var frameData = imageDataFromImageSource( frameSrc, pal, col );
|
||
|
imageStore.render[drwId][pal][colStr].push(frameData);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function imageDataFromImageSource(imageSource, pal, col) {
|
||
|
//console.log(imageSource);
|
||
|
var tilesize = imageSource.length;
|
||
|
var scale = Math.ceil(4 / (tilesize / 8));
|
||
|
|
||
|
var img = context.createImageData(tilesize*scale,tilesize*scale);
|
||
|
|
||
|
var backgroundColor = getPaletteColor(pal,0);
|
||
|
var foregroundColor = getPaletteColor(pal,col);
|
||
|
|
||
|
for (var y = 0; y < tilesize; y++) {
|
||
|
for (var x = 0; x < tilesize; x++) {
|
||
|
var px = imageSource[y][x];
|
||
|
for (var sy = 0; sy < scale; sy++) {
|
||
|
for (var sx = 0; sx < scale; sx++) {
|
||
|
var pxl = (((y * scale) + sy) * tilesize * scale * 4) + (((x*scale) + sx) * 4);
|
||
|
if ( px === 1 ) {
|
||
|
img.data[pxl + 0] = foregroundColor.r;
|
||
|
img.data[pxl + 1] = foregroundColor.g;
|
||
|
img.data[pxl + 2] = foregroundColor.b;
|
||
|
img.data[pxl + 3] = 255;
|
||
|
}
|
||
|
else { //ch === 0
|
||
|
img.data[pxl + 0] = backgroundColor.r;
|
||
|
img.data[pxl + 1] = backgroundColor.g;
|
||
|
img.data[pxl + 2] = backgroundColor.b;
|
||
|
img.data[pxl + 3] = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// convert to canvas: chrome has poor performance when working directly with image data
|
||
|
var imageCanvas = document.createElement("canvas");
|
||
|
imageCanvas.width = img.width;
|
||
|
imageCanvas.height = img.height;
|
||
|
var imageContext = imageCanvas.getContext("2d");
|
||
|
imageContext.putImageData(img,0,0);
|
||
|
|
||
|
return imageCanvas;
|
||
|
}
|
||
|
|
||
|
// TODO : move into core
|
||
|
function undefinedOrNull(x) {
|
||
|
return x === undefined || x === null;
|
||
|
}
|
||
|
|
||
|
function isImageRendered(drawing, paletteId) {
|
||
|
var col = drawing.col;
|
||
|
var colStr = "" + col;
|
||
|
var pal = paletteId;
|
||
|
var drwId = drawing.drw;
|
||
|
|
||
|
if (undefinedOrNull(imageStore.render[drwId]) ||
|
||
|
undefinedOrNull(imageStore.render[drwId][pal]) ||
|
||
|
undefinedOrNull(imageStore.render[drwId][pal][colStr])) {
|
||
|
return false;
|
||
|
}
|
||
|
else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getImageSet(drawing, paletteId) {
|
||
|
return imageStore.render[drawing.drw][paletteId][drawing.col];
|
||
|
}
|
||
|
|
||
|
function getImageFrame(drawing, paletteId, frameOverride) {
|
||
|
var frameIndex = 0;
|
||
|
if (drawing.animation.isAnimated) {
|
||
|
if (frameOverride != undefined && frameOverride != null) {
|
||
|
frameIndex = frameOverride;
|
||
|
}
|
||
|
else {
|
||
|
frameIndex = drawing.animation.frameIndex;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return getImageSet(drawing, paletteId)[frameIndex];
|
||
|
}
|
||
|
|
||
|
function getOrRenderImage(drawing, paletteId, frameOverride) {
|
||
|
if (!isImageRendered(drawing, paletteId)) {
|
||
|
renderImage(drawing, paletteId);
|
||
|
}
|
||
|
|
||
|
return getImageFrame(drawing, paletteId, frameOverride);
|
||
|
}
|
||
|
|
||
|
/* PUBLIC INTERFACE */
|
||
|
this.GetImage = getOrRenderImage;
|
||
|
|
||
|
this.SetPalettes = setPalettes;
|
||
|
|
||
|
this.SetImageSource = function(drawingId, imageSourceData) {
|
||
|
imageStore.source[drawingId] = imageSourceData;
|
||
|
imageStore.render[drawingId] = {}; // reset render cache for this image
|
||
|
}
|
||
|
|
||
|
this.GetImageSource = function(drawingId) {
|
||
|
return imageStore.source[drawingId];
|
||
|
}
|
||
|
|
||
|
this.GetFrameCount = function(drawingId) {
|
||
|
return imageStore.source[drawingId].length;
|
||
|
}
|
||
|
|
||
|
this.AttachContext = function(ctx) {
|
||
|
context = ctx;
|
||
|
}
|
||
|
|
||
|
} // Renderer()
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
var xhr; // TODO : remove
|
||
|
var canvas;
|
||
|
var context; // TODO : remove if safe?
|
||
|
var ctx;
|
||
|
|
||
|
var room = {};
|
||
|
var tile = {};
|
||
|
var sprite = {};
|
||
|
var item = {};
|
||
|
var dialog = {};
|
||
|
var palette = { //start off with a default palette
|
||
|
"default" : {
|
||
|
name : "default",
|
||
|
colors : [[0,0,0],[255,255,255],[255,255,255]]
|
||
|
}
|
||
|
};
|
||
|
var variable = {}; // these are starting variable values -- they don't update (or I don't think they will)
|
||
|
var playerId = "A";
|
||
|
|
||
|
var titleDialogId = "title";
|
||
|
function getTitle() {
|
||
|
return dialog[titleDialogId].src;
|
||
|
}
|
||
|
function setTitle(titleSrc) {
|
||
|
dialog[titleDialogId] = { src:titleSrc, name:null };
|
||
|
}
|
||
|
|
||
|
var defaultFontName = "ascii_small";
|
||
|
var fontName = defaultFontName;
|
||
|
var TextDirection = {
|
||
|
LeftToRight : "LTR",
|
||
|
RightToLeft : "RTL"
|
||
|
};
|
||
|
var textDirection = TextDirection.LeftToRight;
|
||
|
|
||
|
var names = {
|
||
|
room : new Map(),
|
||
|
tile : new Map(), // Note: Not currently enabled in the UI
|
||
|
sprite : new Map(),
|
||
|
item : new Map(),
|
||
|
dialog : new Map(),
|
||
|
};
|
||
|
function updateNamesFromCurData() {
|
||
|
|
||
|
function createNameMap(objectStore) {
|
||
|
var map = new Map();
|
||
|
for (id in objectStore) {
|
||
|
if (objectStore[id].name != undefined && objectStore[id].name != null) {
|
||
|
map.set(objectStore[id].name, id);
|
||
|
}
|
||
|
}
|
||
|
return map;
|
||
|
}
|
||
|
|
||
|
names.room = createNameMap(room);
|
||
|
names.tile = createNameMap(tile);
|
||
|
names.sprite = createNameMap(sprite);
|
||
|
names.item = createNameMap(item);
|
||
|
names.dialog = createNameMap(dialog);
|
||
|
}
|
||
|
|
||
|
var spriteStartLocations = {};
|
||
|
|
||
|
/* VERSION */
|
||
|
var version = {
|
||
|
major: 7, // major changes
|
||
|
minor: 3, // smaller changes
|
||
|
devBuildPhase: "RELEASE",
|
||
|
};
|
||
|
function getEngineVersion() {
|
||
|
return version.major + "." + version.minor;
|
||
|
}
|
||
|
|
||
|
/* FLAGS */
|
||
|
var flags;
|
||
|
function resetFlags() {
|
||
|
flags = {
|
||
|
ROOM_FORMAT : 0 // 0 = non-comma separated, 1 = comma separated
|
||
|
};
|
||
|
}
|
||
|
resetFlags(); //init flags on load script
|
||
|
|
||
|
// SUPER hacky location... :/
|
||
|
var editorDevFlags = {
|
||
|
// NONE right now!
|
||
|
};
|
||
|
|
||
|
function clearGameData() {
|
||
|
room = {};
|
||
|
tile = {};
|
||
|
sprite = {};
|
||
|
item = {};
|
||
|
dialog = {};
|
||
|
palette = { //start off with a default palette
|
||
|
"default" : {
|
||
|
name : "default",
|
||
|
colors : [[0,0,0],[255,255,255],[255,255,255]]
|
||
|
}
|
||
|
};
|
||
|
isEnding = false; //todo - correct place for this?
|
||
|
variable = {};
|
||
|
|
||
|
// TODO RENDERER : clear data?
|
||
|
|
||
|
spriteStartLocations = {};
|
||
|
|
||
|
// hacky to have this multiple times...
|
||
|
names = {
|
||
|
room : new Map(),
|
||
|
tile : new Map(),
|
||
|
sprite : new Map(),
|
||
|
item : new Map(),
|
||
|
dialog : new Map(),
|
||
|
};
|
||
|
|
||
|
fontName = defaultFontName; // TODO : reset font manager too?
|
||
|
textDirection = TextDirection.LeftToRight;
|
||
|
}
|
||
|
|
||
|
var width = 128;
|
||
|
var height = 128;
|
||
|
var scale = 4; //this is stupid but necessary
|
||
|
var tilesize = 8;
|
||
|
var mapsize = 16;
|
||
|
|
||
|
var curRoom = "0";
|
||
|
|
||
|
var key = {
|
||
|
left : 37,
|
||
|
right : 39,
|
||
|
up : 38,
|
||
|
down : 40,
|
||
|
space : 32,
|
||
|
enter : 13,
|
||
|
w : 87,
|
||
|
a : 65,
|
||
|
s : 83,
|
||
|
d : 68,
|
||
|
r : 82,
|
||
|
shift : 16,
|
||
|
ctrl : 17,
|
||
|
alt : 18,
|
||
|
cmd : 224
|
||
|
};
|
||
|
|
||
|
var prevTime = 0;
|
||
|
var deltaTime = 0;
|
||
|
|
||
|
//inventory update UI handles
|
||
|
var onInventoryChanged = null;
|
||
|
var onVariableChanged = null;
|
||
|
var onGameReset = null;
|
||
|
|
||
|
var isPlayerEmbeddedInEditor = false;
|
||
|
|
||
|
var renderer = new Renderer(tilesize, scale);
|
||
|
|
||
|
function getGameNameFromURL() {
|
||
|
var game = window.location.hash.substring(1);
|
||
|
// console.log("game name --- " + game);
|
||
|
return game;
|
||
|
}
|
||
|
|
||
|
function attachCanvas(c) {
|
||
|
canvas = c;
|
||
|
canvas.width = width * scale;
|
||
|
canvas.height = width * scale;
|
||
|
ctx = canvas.getContext("2d");
|
||
|
dialogRenderer.AttachContext(ctx);
|
||
|
renderer.AttachContext(ctx);
|
||
|
}
|
||
|
|
||
|
var curGameData = null;
|
||
|
function load_game(game_data, startWithTitle) {
|
||
|
curGameData = game_data; //remember the current game (used to reset the game)
|
||
|
|
||
|
dialogBuffer.Reset();
|
||
|
scriptInterpreter.ResetEnvironment(); // ensures variables are reset -- is this the best way?
|
||
|
|
||
|
parseWorld(game_data);
|
||
|
|
||
|
if (!isPlayerEmbeddedInEditor) {
|
||
|
// hack to ensure default font is available
|
||
|
fontManager.AddResource(defaultFontName + fontManager.GetExtension(), document.getElementById(defaultFontName).text.slice(1));
|
||
|
}
|
||
|
|
||
|
var font = fontManager.Get( fontName );
|
||
|
dialogBuffer.SetFont(font);
|
||
|
dialogRenderer.SetFont(font);
|
||
|
|
||
|
setInitialVariables();
|
||
|
|
||
|
// setInterval(updateLoadingScreen, 300); // hack test
|
||
|
|
||
|
onready(startWithTitle);
|
||
|
}
|
||
|
|
||
|
function reset_cur_game() {
|
||
|
if (curGameData == null) {
|
||
|
return; //can't reset if we don't have the game data
|
||
|
}
|
||
|
|
||
|
stopGame();
|
||
|
clearGameData();
|
||
|
load_game(curGameData);
|
||
|
|
||
|
if (isPlayerEmbeddedInEditor && onGameReset != null) {
|
||
|
onGameReset();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var update_interval = null;
|
||
|
function onready(startWithTitle) {
|
||
|
if(startWithTitle === undefined || startWithTitle === null) startWithTitle = true;
|
||
|
|
||
|
clearInterval(loading_interval);
|
||
|
|
||
|
input = new InputManager();
|
||
|
|
||
|
document.addEventListener('keydown', input.onkeydown);
|
||
|
document.addEventListener('keyup', input.onkeyup);
|
||
|
|
||
|
if (isPlayerEmbeddedInEditor) {
|
||
|
canvas.addEventListener('touchstart', input.ontouchstart, {passive:false});
|
||
|
canvas.addEventListener('touchmove', input.ontouchmove, {passive:false});
|
||
|
canvas.addEventListener('touchend', input.ontouchend, {passive:false});
|
||
|
}
|
||
|
else {
|
||
|
// creates a 'touchTrigger' element that covers the entire screen and can universally have touch event listeners added w/o issue.
|
||
|
|
||
|
// we're checking for existing touchTriggers both at game start and end, so it's slightly redundant.
|
||
|
var existingTouchTrigger = document.querySelector('#touchTrigger');
|
||
|
if (existingTouchTrigger === null){
|
||
|
var touchTrigger = document.createElement("div");
|
||
|
touchTrigger.setAttribute("id","touchTrigger");
|
||
|
|
||
|
// afaik css in js is necessary here to force a fullscreen element
|
||
|
touchTrigger.setAttribute(
|
||
|
"style","position: absolute; top: 0; left: 0; width: 100vw; height: 100vh; overflow: hidden;"
|
||
|
);
|
||
|
document.body.appendChild(touchTrigger);
|
||
|
|
||
|
touchTrigger.addEventListener('touchstart', input.ontouchstart);
|
||
|
touchTrigger.addEventListener('touchmove', input.ontouchmove);
|
||
|
touchTrigger.addEventListener('touchend', input.ontouchend);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
window.onblur = input.onblur;
|
||
|
|
||
|
update_interval = setInterval(update,16);
|
||
|
|
||
|
if(startWithTitle) { // used by editor
|
||
|
startNarrating(getTitle());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function setInitialVariables() {
|
||
|
for(id in variable) {
|
||
|
var value = variable[id]; // default to string
|
||
|
if(value === "true") {
|
||
|
value = true;
|
||
|
}
|
||
|
else if(value === "false") {
|
||
|
value = false;
|
||
|
}
|
||
|
else if(!isNaN(parseFloat(value))) {
|
||
|
value = parseFloat(value);
|
||
|
}
|
||
|
scriptInterpreter.SetVariable(id,value);
|
||
|
}
|
||
|
scriptInterpreter.SetOnVariableChangeHandler( onVariableChanged );
|
||
|
}
|
||
|
|
||
|
function getOffset(evt) {
|
||
|
var offset = { x:0, y:0 };
|
||
|
|
||
|
var el = evt.target;
|
||
|
var rect = el.getBoundingClientRect();
|
||
|
|
||
|
offset.x += rect.left + el.scrollLeft;
|
||
|
offset.y += rect.top + el.scrollTop;
|
||
|
|
||
|
offset.x = evt.clientX - offset.x;
|
||
|
offset.y = evt.clientY - offset.y;
|
||
|
|
||
|
return offset;
|
||
|
}
|
||
|
|
||
|
function stopGame() {
|
||
|
console.log("stop GAME!");
|
||
|
|
||
|
document.removeEventListener('keydown', input.onkeydown);
|
||
|
document.removeEventListener('keyup', input.onkeyup);
|
||
|
|
||
|
if (isPlayerEmbeddedInEditor) {
|
||
|
canvas.removeEventListener('touchstart', input.ontouchstart);
|
||
|
canvas.removeEventListener('touchmove', input.ontouchmove);
|
||
|
canvas.removeEventListener('touchend', input.ontouchend);
|
||
|
}
|
||
|
else {
|
||
|
//check for touchTrigger and removes it
|
||
|
|
||
|
var existingTouchTrigger = document.querySelector('#touchTrigger');
|
||
|
if (existingTouchTrigger !== null){
|
||
|
existingTouchTrigger.removeEventListener('touchstart', input.ontouchstart);
|
||
|
existingTouchTrigger.removeEventListener('touchmove', input.ontouchmove);
|
||
|
existingTouchTrigger.removeEventListener('touchend', input.ontouchend);
|
||
|
|
||
|
existingTouchTrigger.parentElement.removeChild(existingTouchTrigger);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
window.onblur = null;
|
||
|
|
||
|
clearInterval(update_interval);
|
||
|
}
|
||
|
|
||
|
/* loading animation */
|
||
|
var loading_anim_data = [
|
||
|
[
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
],
|
||
|
[
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
],
|
||
|
[
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
],
|
||
|
[
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,1,0,0,1,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,0,1,1,0,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,0,1,1,1,1,0,0,
|
||
|
0,1,1,1,1,1,1,0,
|
||
|
],
|
||
|
[
|
||
|
0,0,0,0,0,0,0,0,
|
||
|
1,0,0,0,0,0,0,1,
|
||
|
1,1,1,0,0,1,1,1,
|
||
|
1,1,1,1,1,0,0,1,
|
||
|
1,1,1,1,1,0,0,1,
|
||
|
1,1,1,0,0,1,1,1,
|
||
|
1,0,0,0,0,0,0,1,
|
||
|
0,0,0,0,0,0,0,0,
|
||
|
]
|
||
|
];
|
||
|
var loading_anim_frame = 0;
|
||
|
var loading_anim_speed = 500;
|
||
|
var loading_interval = null;
|
||
|
|
||
|
function loadingAnimation() {
|
||
|
//create image
|
||
|
var loadingAnimImg = ctx.createImageData(8*scale, 8*scale);
|
||
|
//draw image
|
||
|
for (var y = 0; y < 8; y++) {
|
||
|
for (var x = 0; x < 8; x++) {
|
||
|
var i = (y * 8) + x;
|
||
|
if (loading_anim_data[loading_anim_frame][i] == 1) {
|
||
|
//scaling nonsense
|
||
|
for (var sy = 0; sy < scale; sy++) {
|
||
|
for (var sx = 0; sx < scale; sx++) {
|
||
|
var pxl = 4 * ( (((y*scale)+sy) * (8*scale)) + ((x*scale)+sx) );
|
||
|
loadingAnimImg.data[pxl+0] = 255;
|
||
|
loadingAnimImg.data[pxl+1] = 255;
|
||
|
loadingAnimImg.data[pxl+2] = 255;
|
||
|
loadingAnimImg.data[pxl+3] = 255;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
//put image on canvas
|
||
|
ctx.putImageData(loadingAnimImg,scale*(width/2 - 4),scale*(height/2 - 4));
|
||
|
//update frame
|
||
|
loading_anim_frame++;
|
||
|
if (loading_anim_frame >= 5) loading_anim_frame = 0;
|
||
|
}
|
||
|
|
||
|
function updateLoadingScreen() {
|
||
|
// TODO : in progress
|
||
|
ctx.fillStyle = "rgb(0,0,0)";
|
||
|
ctx.fillRect(0,0,canvas.width,canvas.height);
|
||
|
|
||
|
loadingAnimation();
|
||
|
drawSprite( getSpriteImage(sprite["a"],"0",0), 8, 8, ctx );
|
||
|
}
|
||
|
|
||
|
function update() {
|
||
|
var curTime = Date.now();
|
||
|
deltaTime = curTime - prevTime;
|
||
|
|
||
|
if (curRoom == null) {
|
||
|
// in the special case where there is no valid room, end the game
|
||
|
startNarrating( "", true /*isEnding*/ );
|
||
|
}
|
||
|
|
||
|
if (!transition.IsTransitionActive()) {
|
||
|
updateInput();
|
||
|
}
|
||
|
|
||
|
if (transition.IsTransitionActive()) {
|
||
|
// transition animation takes over everything!
|
||
|
transition.UpdateTransition(deltaTime);
|
||
|
}
|
||
|
else {
|
||
|
if (!isNarrating && !isEnding) {
|
||
|
updateAnimation();
|
||
|
drawRoom( room[curRoom] ); // draw world if game has begun
|
||
|
}
|
||
|
else {
|
||
|
//make sure to still clear screen
|
||
|
ctx.fillStyle = "rgb(" + getPal(curPal())[0][0] + "," + getPal(curPal())[0][1] + "," + getPal(curPal())[0][2] + ")";
|
||
|
ctx.fillRect(0,0,canvas.width,canvas.height);
|
||
|
}
|
||
|
|
||
|
// if (isDialogMode) { // dialog mode
|
||
|
if(dialogBuffer.IsActive()) {
|
||
|
dialogRenderer.Draw( dialogBuffer, deltaTime );
|
||
|
dialogBuffer.Update( deltaTime );
|
||
|
}
|
||
|
|
||
|
// keep moving avatar if player holds down button
|
||
|
if( !dialogBuffer.IsActive() && !isEnding )
|
||
|
{
|
||
|
if( curPlayerDirection != Direction.None ) {
|
||
|
playerHoldToMoveTimer -= deltaTime;
|
||
|
|
||
|
if( playerHoldToMoveTimer <= 0 )
|
||
|
{
|
||
|
movePlayer( curPlayerDirection );
|
||
|
playerHoldToMoveTimer = playerHoldToMoveInterval;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
prevTime = curTime;
|
||
|
|
||
|
input.resetKeyPressed();
|
||
|
input.resetTapReleased();
|
||
|
}
|
||
|
|
||
|
function updateInput() {
|
||
|
if( dialogBuffer.IsActive() ) {
|
||
|
if (input.anyKeyPressed() || input.isTapReleased()) {
|
||
|
/* CONTINUE DIALOG */
|
||
|
if (dialogBuffer.CanContinue()) {
|
||
|
var hasMoreDialog = dialogBuffer.Continue();
|
||
|
if(!hasMoreDialog) {
|
||
|
// ignore currently held keys UNTIL they are released (stops player from insta-moving)
|
||
|
input.ignoreHeldKeys();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
dialogBuffer.Skip();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if ( isEnding ) {
|
||
|
/* BITSY MUSEUM HACK:
|
||
|
instead of reseting on ending it takes player back to the museum
|
||
|
also removes need to click button to reset */
|
||
|
|
||
|
if (!redirectBitsy){
|
||
|
redirectBitsy = true;
|
||
|
window.location.href = "lootboxes.html";
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
/* WALK */
|
||
|
var prevPlayerDirection = curPlayerDirection;
|
||
|
|
||
|
if ( input.isKeyDown( key.left ) || input.isKeyDown( key.a ) || input.swipeLeft() ) {
|
||
|
curPlayerDirection = Direction.Left;
|
||
|
}
|
||
|
else if ( input.isKeyDown( key.right ) || input.isKeyDown( key.d ) || input.swipeRight() ) {
|
||
|
curPlayerDirection = Direction.Right;
|
||
|
}
|
||
|
else if ( input.isKeyDown( key.up ) || input.isKeyDown( key.w ) || input.swipeUp() ) {
|
||
|
curPlayerDirection = Direction.Up;
|
||
|
}
|
||
|
else if ( input.isKeyDown( key.down ) || input.isKeyDown( key.s ) || input.swipeDown() ) {
|
||
|
curPlayerDirection = Direction.Down;
|
||
|
}
|
||
|
else {
|
||
|
curPlayerDirection = Direction.None;
|
||
|
}
|
||
|
|
||
|
if (curPlayerDirection != Direction.None && curPlayerDirection != prevPlayerDirection) {
|
||
|
movePlayer( curPlayerDirection );
|
||
|
playerHoldToMoveTimer = playerSecondStepInterval;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var animationCounter = 0;
|
||
|
var animationTime = 400;
|
||
|
function updateAnimation() {
|
||
|
animationCounter += deltaTime;
|
||
|
|
||
|
if ( animationCounter >= animationTime ) {
|
||
|
|
||
|
// animate sprites
|
||
|
for (id in sprite) {
|
||
|
var spr = sprite[id];
|
||
|
if (spr.animation.isAnimated) {
|
||
|
spr.animation.frameIndex = ( spr.animation.frameIndex + 1 ) % spr.animation.frameCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// animate tiles
|
||
|
for (id in tile) {
|
||
|
var til = tile[id];
|
||
|
if (til.animation.isAnimated) {
|
||
|
til.animation.frameIndex = ( til.animation.frameIndex + 1 ) % til.animation.frameCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// animate items
|
||
|
for (id in item) {
|
||
|
var itm = item[id];
|
||
|
if (itm.animation.isAnimated) {
|
||
|
itm.animation.frameIndex = ( itm.animation.frameIndex + 1 ) % itm.animation.frameCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reset counter
|
||
|
animationCounter = 0;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function resetAllAnimations() {
|
||
|
for (id in sprite) {
|
||
|
var spr = sprite[id];
|
||
|
if (spr.animation.isAnimated) {
|
||
|
spr.animation.frameIndex = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (id in tile) {
|
||
|
var til = tile[id];
|
||
|
if (til.animation.isAnimated) {
|
||
|
til.animation.frameIndex = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (id in item) {
|
||
|
var itm = item[id];
|
||
|
if (itm.animation.isAnimated) {
|
||
|
itm.animation.frameIndex = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getSpriteAt(x,y) {
|
||
|
for (id in sprite) {
|
||
|
var spr = sprite[id];
|
||
|
if (spr.room === curRoom) {
|
||
|
if (spr.x == x && spr.y == y) {
|
||
|
return id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
var Direction = {
|
||
|
None : -1,
|
||
|
Up : 0,
|
||
|
Down : 1,
|
||
|
Left : 2,
|
||
|
Right : 3
|
||
|
};
|
||
|
|
||
|
var curPlayerDirection = Direction.None;
|
||
|
var playerHoldToMoveTimer = 0;
|
||
|
var playerHoldToMoveInterval = 150;
|
||
|
var playerSecondStepInterval = 500;
|
||
|
|
||
|
var InputManager = function() {
|
||
|
var self = this;
|
||
|
|
||
|
var pressed;
|
||
|
var ignored;
|
||
|
var newKeyPress;
|
||
|
var touchState;
|
||
|
|
||
|
function resetAll() {
|
||
|
pressed = {};
|
||
|
ignored = {};
|
||
|
newKeyPress = false;
|
||
|
|
||
|
touchState = {
|
||
|
isDown : false,
|
||
|
startX : 0,
|
||
|
startY : 0,
|
||
|
curX : 0,
|
||
|
curY : 0,
|
||
|
swipeDistance : 30,
|
||
|
swipeDirection : Direction.None,
|
||
|
tapReleased : false
|
||
|
};
|
||
|
}
|
||
|
resetAll();
|
||
|
|
||
|
function stopWindowScrolling(e) {
|
||
|
if(e.keyCode == key.left || e.keyCode == key.right || e.keyCode == key.up || e.keyCode == key.down || !isPlayerEmbeddedInEditor)
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
|
||
|
function tryRestartGame(e) {
|
||
|
/* RESTART GAME */
|
||
|
if ( e.keyCode === key.r && ( e.getModifierState("Control") || e.getModifierState("Meta") ) ) {
|
||
|
if ( confirm("Restart the game?") ) {
|
||
|
reset_cur_game();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function eventIsModifier(event) {
|
||
|
return (event.keyCode == key.shift || event.keyCode == key.ctrl || event.keyCode == key.alt || event.keyCode == key.cmd);
|
||
|
}
|
||
|
|
||
|
function isModifierKeyDown() {
|
||
|
return ( self.isKeyDown(key.shift) || self.isKeyDown(key.ctrl) || self.isKeyDown(key.alt) || self.isKeyDown(key.cmd) );
|
||
|
}
|
||
|
|
||
|
this.ignoreHeldKeys = function() {
|
||
|
for (var key in pressed) {
|
||
|
if (pressed[key]) { // only ignore keys that are actually held
|
||
|
ignored[key] = true;
|
||
|
// console.log("IGNORE -- " + key);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.onkeydown = function(event) {
|
||
|
// console.log("KEYDOWN -- " + event.keyCode);
|
||
|
|
||
|
stopWindowScrolling(event);
|
||
|
|
||
|
tryRestartGame(event);
|
||
|
|
||
|
// Special keys being held down can interfere with keyup events and lock movement
|
||
|
// so just don't collect input when they're held
|
||
|
{
|
||
|
if (isModifierKeyDown()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (eventIsModifier(event)) {
|
||
|
resetAll();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (ignored[event.keyCode]) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!self.isKeyDown(event.keyCode)) {
|
||
|
newKeyPress = true;
|
||
|
}
|
||
|
|
||
|
pressed[event.keyCode] = true;
|
||
|
ignored[event.keyCode] = false;
|
||
|
}
|
||
|
|
||
|
this.onkeyup = function(event) {
|
||
|
// console.log("KEYUP -- " + event.keyCode);
|
||
|
pressed[event.keyCode] = false;
|
||
|
ignored[event.keyCode] = false;
|
||
|
}
|
||
|
|
||
|
this.ontouchstart = function(event) {
|
||
|
event.preventDefault();
|
||
|
|
||
|
if( event.changedTouches.length > 0 ) {
|
||
|
touchState.isDown = true;
|
||
|
|
||
|
touchState.startX = touchState.curX = event.changedTouches[0].clientX;
|
||
|
touchState.startY = touchState.curY = event.changedTouches[0].clientY;
|
||
|
|
||
|
touchState.swipeDirection = Direction.None;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.ontouchmove = function(event) {
|
||
|
event.preventDefault();
|
||
|
|
||
|
if( touchState.isDown && event.changedTouches.length > 0 ) {
|
||
|
touchState.curX = event.changedTouches[0].clientX;
|
||
|
touchState.curY = event.changedTouches[0].clientY;
|
||
|
|
||
|
var prevDirection = touchState.swipeDirection;
|
||
|
|
||
|
if( touchState.curX - touchState.startX <= -touchState.swipeDistance ) {
|
||
|
touchState.swipeDirection = Direction.Left;
|
||
|
}
|
||
|
else if( touchState.curX - touchState.startX >= touchState.swipeDistance ) {
|
||
|
touchState.swipeDirection = Direction.Right;
|
||
|
}
|
||
|
else if( touchState.curY - touchState.startY <= -touchState.swipeDistance ) {
|
||
|
touchState.swipeDirection = Direction.Up;
|
||
|
}
|
||
|
else if( touchState.curY - touchState.startY >= touchState.swipeDistance ) {
|
||
|
touchState.swipeDirection = Direction.Down;
|
||
|
}
|
||
|
|
||
|
if( touchState.swipeDirection != prevDirection ) {
|
||
|
// reset center so changing directions is easier
|
||
|
touchState.startX = touchState.curX;
|
||
|
touchState.startY = touchState.curY;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.ontouchend = function(event) {
|
||
|
event.preventDefault();
|
||
|
|
||
|
touchState.isDown = false;
|
||
|
|
||
|
if( touchState.swipeDirection == Direction.None ) {
|
||
|
// tap!
|
||
|
touchState.tapReleased = true;
|
||
|
}
|
||
|
|
||
|
touchState.swipeDirection = Direction.None;
|
||
|
}
|
||
|
|
||
|
this.isKeyDown = function(keyCode) {
|
||
|
return pressed[keyCode] != null && pressed[keyCode] == true && (ignored[keyCode] == null || ignored[keyCode] == false);
|
||
|
}
|
||
|
|
||
|
this.anyKeyPressed = function() {
|
||
|
return newKeyPress;
|
||
|
}
|
||
|
|
||
|
this.resetKeyPressed = function() {
|
||
|
newKeyPress = false;
|
||
|
}
|
||
|
|
||
|
this.swipeLeft = function() {
|
||
|
return touchState.swipeDirection == Direction.Left;
|
||
|
}
|
||
|
|
||
|
this.swipeRight = function() {
|
||
|
return touchState.swipeDirection == Direction.Right;
|
||
|
}
|
||
|
|
||
|
this.swipeUp = function() {
|
||
|
return touchState.swipeDirection == Direction.Up;
|
||
|
}
|
||
|
|
||
|
this.swipeDown = function() {
|
||
|
return touchState.swipeDirection == Direction.Down;
|
||
|
}
|
||
|
|
||
|
this.isTapReleased = function() {
|
||
|
return touchState.tapReleased;
|
||
|
}
|
||
|
|
||
|
this.resetTapReleased = function() {
|
||
|
touchState.tapReleased = false;
|
||
|
}
|
||
|
|
||
|
this.onblur = function() {
|
||
|
// console.log("~~~ BLUR ~~");
|
||
|
resetAll();
|
||
|
}
|
||
|
}
|
||
|
var input = null;
|
||
|
|
||
|
function movePlayer(direction) {
|
||
|
if (player().room == null || !Object.keys(room).includes(player().room)) {
|
||
|
return; // player room is missing or invalid.. can't move them!
|
||
|
}
|
||
|
|
||
|
var spr = null;
|
||
|
|
||
|
if ( curPlayerDirection == Direction.Left && !(spr = getSpriteLeft()) && !isWallLeft()) {
|
||
|
player().x -= 1;
|
||
|
}
|
||
|
else if ( curPlayerDirection == Direction.Right && !(spr = getSpriteRight()) && !isWallRight()) {
|
||
|
player().x += 1;
|
||
|
}
|
||
|
else if ( curPlayerDirection == Direction.Up && !(spr = getSpriteUp()) && !isWallUp()) {
|
||
|
player().y -= 1;
|
||
|
}
|
||
|
else if ( curPlayerDirection == Direction.Down && !(spr = getSpriteDown()) && !isWallDown()) {
|
||
|
player().y += 1;
|
||
|
}
|
||
|
|
||
|
var ext = getExit( player().room, player().x, player().y );
|
||
|
var end = getEnding( player().room, player().x, player().y );
|
||
|
var itmIndex = getItemIndex( player().room, player().x, player().y );
|
||
|
|
||
|
// do items first, because you can pick up an item AND go through a door
|
||
|
if (itmIndex > -1) {
|
||
|
var itm = room[player().room].items[itmIndex];
|
||
|
var itemRoom = player().room;
|
||
|
|
||
|
startItemDialog(itm.id, function() {
|
||
|
// remove item from room
|
||
|
room[itemRoom].items.splice(itmIndex, 1);
|
||
|
|
||
|
// update player inventory
|
||
|
if (player().inventory[itm.id]) {
|
||
|
player().inventory[itm.id] += 1;
|
||
|
}
|
||
|
else {
|
||
|
player().inventory[itm.id] = 1;
|
||
|
}
|
||
|
|
||
|
// show inventory change in UI
|
||
|
if (onInventoryChanged != null) {
|
||
|
onInventoryChanged(itm.id);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (end) {
|
||
|
startEndingDialog(end);
|
||
|
}
|
||
|
else if (ext) {
|
||
|
movePlayerThroughExit(ext);
|
||
|
}
|
||
|
else if (spr) {
|
||
|
startSpriteDialog(spr /*spriteId*/);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var transition = new TransitionManager();
|
||
|
|
||
|
function movePlayerThroughExit(ext) {
|
||
|
var GoToDest = function() {
|
||
|
if (ext.transition_effect != null) {
|
||
|
transition.BeginTransition(player().room, player().x, player().y, ext.dest.room, ext.dest.x, ext.dest.y, ext.transition_effect);
|
||
|
transition.UpdateTransition(0);
|
||
|
}
|
||
|
|
||
|
player().room = ext.dest.room;
|
||
|
player().x = ext.dest.x;
|
||
|
player().y = ext.dest.y;
|
||
|
curRoom = ext.dest.room;
|
||
|
|
||
|
initRoom(curRoom);
|
||
|
};
|
||
|
|
||
|
if (ext.dlg != undefined && ext.dlg != null) {
|
||
|
// TODO : I need to simplify dialog code,
|
||
|
// so I don't have to get the ID and the source str
|
||
|
// every time!
|
||
|
startDialog(
|
||
|
dialog[ext.dlg].src,
|
||
|
ext.dlg,
|
||
|
function(result) {
|
||
|
var isLocked = ext.property && ext.property.locked === true;
|
||
|
if (!isLocked) {
|
||
|
GoToDest();
|
||
|
}
|
||
|
},
|
||
|
ext);
|
||
|
}
|
||
|
else {
|
||
|
GoToDest();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function initRoom(roomId) {
|
||
|
// init exit properties
|
||
|
for (var i = 0; i < room[roomId].exits.length; i++) {
|
||
|
room[roomId].exits[i].property = { locked:false };
|
||
|
}
|
||
|
|
||
|
// init ending properties
|
||
|
for (var i = 0; i < room[roomId].endings.length; i++) {
|
||
|
room[roomId].endings[i].property = { locked:false };
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getItemIndex( roomId, x, y ) {
|
||
|
for( var i = 0; i < room[roomId].items.length; i++ ) {
|
||
|
var itm = room[roomId].items[i];
|
||
|
if ( itm.x == x && itm.y == y)
|
||
|
return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
function getSpriteLeft() { //repetitive?
|
||
|
return getSpriteAt( player().x - 1, player().y );
|
||
|
}
|
||
|
|
||
|
function getSpriteRight() {
|
||
|
return getSpriteAt( player().x + 1, player().y );
|
||
|
}
|
||
|
|
||
|
function getSpriteUp() {
|
||
|
return getSpriteAt( player().x, player().y - 1 );
|
||
|
}
|
||
|
|
||
|
function getSpriteDown() {
|
||
|
return getSpriteAt( player().x, player().y + 1 );
|
||
|
}
|
||
|
|
||
|
function isWallLeft() {
|
||
|
return (player().x - 1 < 0) || isWall( player().x - 1, player().y );
|
||
|
}
|
||
|
|
||
|
function isWallRight() {
|
||
|
return (player().x + 1 >= 16) || isWall( player().x + 1, player().y );
|
||
|
}
|
||
|
|
||
|
function isWallUp() {
|
||
|
return (player().y - 1 < 0) || isWall( player().x, player().y - 1 );
|
||
|
}
|
||
|
|
||
|
function isWallDown() {
|
||
|
return (player().y + 1 >= 16) || isWall( player().x, player().y + 1 );
|
||
|
}
|
||
|
|
||
|
function isWall(x,y,roomId) {
|
||
|
if(roomId == undefined || roomId == null)
|
||
|
roomId = curRoom;
|
||
|
|
||
|
var tileId = getTile( x, y );
|
||
|
|
||
|
if( tileId === '0' )
|
||
|
return false; // Blank spaces aren't walls, ya doofus
|
||
|
|
||
|
if( tile[tileId].isWall === undefined || tile[tileId].isWall === null ) {
|
||
|
// No wall-state defined: check room-specific walls
|
||
|
var i = room[roomId].walls.indexOf( getTile(x,y) );
|
||
|
return i > -1;
|
||
|
}
|
||
|
|
||
|
// Otherwise, use the tile's own wall-state
|
||
|
return tile[tileId].isWall;
|
||
|
}
|
||
|
|
||
|
function getItem(roomId,x,y) {
|
||
|
for (i in room[roomId].items) {
|
||
|
var item = room[roomId].items[i];
|
||
|
if (x == item.x && y == item.y) {
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function getExit(roomId,x,y) {
|
||
|
for (i in room[roomId].exits) {
|
||
|
var e = room[roomId].exits[i];
|
||
|
if (x == e.x && y == e.y) {
|
||
|
return e;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function getEnding(roomId,x,y) {
|
||
|
for (i in room[roomId].endings) {
|
||
|
var e = room[roomId].endings[i];
|
||
|
if (x == e.x && y == e.y) {
|
||
|
return e;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
function getTile(x,y) {
|
||
|
// console.log(x + " " + y);
|
||
|
var t = getRoom().tilemap[y][x];
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
function player() {
|
||
|
return sprite[playerId];
|
||
|
}
|
||
|
|
||
|
// Sort of a hack for legacy palette code (when it was just an array)
|
||
|
function getPal(id) {
|
||
|
if (palette[id] === undefined) {
|
||
|
id = "default";
|
||
|
}
|
||
|
|
||
|
return palette[ id ].colors;
|
||
|
}
|
||
|
|
||
|
function getRoom() {
|
||
|
return room[curRoom];
|
||
|
}
|
||
|
|
||
|
function isSpriteOffstage(id) {
|
||
|
return sprite[id].room == null;
|
||
|
}
|
||
|
|
||
|
function parseWorld(file) {
|
||
|
spriteStartLocations = {};
|
||
|
|
||
|
resetFlags();
|
||
|
|
||
|
var versionNumber = 0;
|
||
|
|
||
|
// flags to keep track of which compatibility conversions
|
||
|
// need to be applied to this game data
|
||
|
var compatibilityFlags = {
|
||
|
convertSayToPrint : false,
|
||
|
combineEndingsWithDialog : false,
|
||
|
convertImplicitSpriteDialogIds : false,
|
||
|
};
|
||
|
|
||
|
var lines = file.split("\n");
|
||
|
var i = 0;
|
||
|
while (i < lines.length) {
|
||
|
var curLine = lines[i];
|
||
|
|
||
|
// console.log(lines[i]);
|
||
|
|
||
|
if (i == 0) {
|
||
|
i = parseTitle(lines, i);
|
||
|
}
|
||
|
else if (curLine.length <= 0 || curLine.charAt(0) === "#") {
|
||
|
// collect version number (from a comment.. hacky I know)
|
||
|
if (curLine.indexOf("# BITSY VERSION ") != -1) {
|
||
|
versionNumber = parseFloat(curLine.replace("# BITSY VERSION ", ""));
|
||
|
|
||
|
if (versionNumber < 5.0) {
|
||
|
compatibilityFlags.convertSayToPrint = true;
|
||
|
}
|
||
|
|
||
|
if (versionNumber < 7.0) {
|
||
|
compatibilityFlags.combineEndingsWithDialog = true;
|
||
|
compatibilityFlags.convertImplicitSpriteDialogIds = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//skip blank lines & comments
|
||
|
i++;
|
||
|
}
|
||
|
else if (getType(curLine) == "PAL") {
|
||
|
i = parsePalette(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "ROOM" || getType(curLine) === "SET") { //SET for back compat
|
||
|
i = parseRoom(lines, i, compatibilityFlags);
|
||
|
}
|
||
|
else if (getType(curLine) === "TIL") {
|
||
|
i = parseTile(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "SPR") {
|
||
|
i = parseSprite(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "ITM") {
|
||
|
i = parseItem(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "DRW") {
|
||
|
i = parseDrawing(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "DLG") {
|
||
|
i = parseDialog(lines, i, compatibilityFlags);
|
||
|
}
|
||
|
else if (getType(curLine) === "END" && compatibilityFlags.combineEndingsWithDialog) {
|
||
|
// parse endings for back compat
|
||
|
i = parseEnding(lines, i, compatibilityFlags);
|
||
|
}
|
||
|
else if (getType(curLine) === "VAR") {
|
||
|
i = parseVariable(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "DEFAULT_FONT") {
|
||
|
i = parseFontName(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "TEXT_DIRECTION") {
|
||
|
i = parseTextDirection(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "FONT") {
|
||
|
i = parseFontData(lines, i);
|
||
|
}
|
||
|
else if (getType(curLine) === "!") {
|
||
|
i = parseFlag(lines, i);
|
||
|
}
|
||
|
else {
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
placeSprites();
|
||
|
|
||
|
var roomIds = Object.keys(room);
|
||
|
if (player() != undefined && player().room != null && roomIds.includes(player().room)) {
|
||
|
// player has valid room
|
||
|
curRoom = player().room;
|
||
|
}
|
||
|
else if (roomIds.length > 0) {
|
||
|
// player not in any room! what the heck
|
||
|
curRoom = roomIds[0];
|
||
|
}
|
||
|
else {
|
||
|
// uh oh there are no rooms I guess???
|
||
|
curRoom = null;
|
||
|
}
|
||
|
|
||
|
if (curRoom != null) {
|
||
|
initRoom(curRoom);
|
||
|
}
|
||
|
|
||
|
renderer.SetPalettes(palette);
|
||
|
|
||
|
scriptCompatibility(compatibilityFlags);
|
||
|
|
||
|
return versionNumber;
|
||
|
}
|
||
|
|
||
|
function scriptCompatibility(compatibilityFlags) {
|
||
|
if (compatibilityFlags.convertSayToPrint) {
|
||
|
console.log("CONVERT SAY TO PRINT!");
|
||
|
|
||
|
var PrintFunctionVisitor = function() {
|
||
|
var didChange = false;
|
||
|
this.DidChange = function() { return didChange; };
|
||
|
|
||
|
this.Visit = function(node) {
|
||
|
if (node.type != "function") {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (node.name === "say") {
|
||
|
node.name = "print";
|
||
|
didChange = true;
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
for (dlgId in dialog) {
|
||
|
var dialogScript = scriptInterpreter.Parse(dialog[dlgId].src);
|
||
|
var visitor = new PrintFunctionVisitor();
|
||
|
dialogScript.VisitAll(visitor);
|
||
|
if (visitor.DidChange()) {
|
||
|
var newDialog = dialogScript.Serialize();
|
||
|
if (newDialog.indexOf("\n") > -1) {
|
||
|
newDialog = '"""\n' + newDialog + '\n"""';
|
||
|
}
|
||
|
dialog[dlgId].src = newDialog;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//TODO this is in progress and doesn't support all features
|
||
|
function serializeWorld(skipFonts) {
|
||
|
if (skipFonts === undefined || skipFonts === null)
|
||
|
skipFonts = false;
|
||
|
|
||
|
var worldStr = "";
|
||
|
/* TITLE */
|
||
|
worldStr += getTitle() + "\n";
|
||
|
worldStr += "\n";
|
||
|
/* VERSION */
|
||
|
worldStr += "# BITSY VERSION " + getEngineVersion() + "\n"; // add version as a comment for debugging purposes
|
||
|
if (version.devBuildPhase != "RELEASE") {
|
||
|
worldStr += "# DEVELOPMENT BUILD -- " + version.devBuildPhase;
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
/* FLAGS */
|
||
|
for (f in flags) {
|
||
|
worldStr += "! " + f + " " + flags[f] + "\n";
|
||
|
}
|
||
|
worldStr += "\n"
|
||
|
/* FONT */
|
||
|
if (fontName != defaultFontName) {
|
||
|
worldStr += "DEFAULT_FONT " + fontName + "\n";
|
||
|
worldStr += "\n"
|
||
|
}
|
||
|
if (textDirection != TextDirection.LeftToRight) {
|
||
|
worldStr += "TEXT_DIRECTION " + textDirection + "\n";
|
||
|
worldStr += "\n"
|
||
|
}
|
||
|
/* PALETTE */
|
||
|
for (id in palette) {
|
||
|
if (id != "default") {
|
||
|
worldStr += "PAL " + id + "\n";
|
||
|
if( palette[id].name != null )
|
||
|
worldStr += "NAME " + palette[id].name + "\n";
|
||
|
for (i in getPal(id)) {
|
||
|
for (j in getPal(id)[i]) {
|
||
|
worldStr += getPal(id)[i][j];
|
||
|
if (j < 2) worldStr += ",";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
/* ROOM */
|
||
|
for (id in room) {
|
||
|
worldStr += "ROOM " + id + "\n";
|
||
|
if ( flags.ROOM_FORMAT == 0 ) {
|
||
|
// old non-comma separated format
|
||
|
for (i in room[id].tilemap) {
|
||
|
for (j in room[id].tilemap[i]) {
|
||
|
worldStr += room[id].tilemap[i][j];
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
else if ( flags.ROOM_FORMAT == 1 ) {
|
||
|
// new comma separated format
|
||
|
for (i in room[id].tilemap) {
|
||
|
for (j in room[id].tilemap[i]) {
|
||
|
worldStr += room[id].tilemap[i][j];
|
||
|
if (j < room[id].tilemap[i].length-1) worldStr += ","
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
if (room[id].name != null) {
|
||
|
/* NAME */
|
||
|
worldStr += "NAME " + room[id].name + "\n";
|
||
|
}
|
||
|
if (room[id].walls.length > 0) {
|
||
|
/* WALLS */
|
||
|
worldStr += "WAL ";
|
||
|
for (j in room[id].walls) {
|
||
|
worldStr += room[id].walls[j];
|
||
|
if (j < room[id].walls.length-1) {
|
||
|
worldStr += ",";
|
||
|
}
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
if (room[id].items.length > 0) {
|
||
|
/* ITEMS */
|
||
|
for (j in room[id].items) {
|
||
|
var itm = room[id].items[j];
|
||
|
worldStr += "ITM " + itm.id + " " + itm.x + "," + itm.y;
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
if (room[id].exits.length > 0) {
|
||
|
/* EXITS */
|
||
|
for (j in room[id].exits) {
|
||
|
var e = room[id].exits[j];
|
||
|
if ( isExitValid(e) ) {
|
||
|
worldStr += "EXT " + e.x + "," + e.y + " " + e.dest.room + " " + e.dest.x + "," + e.dest.y;
|
||
|
if (e.transition_effect != undefined && e.transition_effect != null) {
|
||
|
worldStr += " FX " + e.transition_effect;
|
||
|
}
|
||
|
if (e.dlg != undefined && e.dlg != null) {
|
||
|
worldStr += " DLG " + e.dlg;
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (room[id].endings.length > 0) {
|
||
|
/* ENDINGS */
|
||
|
for (j in room[id].endings) {
|
||
|
var e = room[id].endings[j];
|
||
|
// todo isEndingValid
|
||
|
worldStr += "END " + e.id + " " + e.x + "," + e.y;
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
if (room[id].pal != null && room[id].pal != "default") {
|
||
|
/* PALETTE */
|
||
|
worldStr += "PAL " + room[id].pal + "\n";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
/* TILES */
|
||
|
for (id in tile) {
|
||
|
worldStr += "TIL " + id + "\n";
|
||
|
worldStr += serializeDrawing( "TIL_" + id );
|
||
|
if (tile[id].name != null && tile[id].name != undefined) {
|
||
|
/* NAME */
|
||
|
worldStr += "NAME " + tile[id].name + "\n";
|
||
|
}
|
||
|
if (tile[id].isWall != null && tile[id].isWall != undefined) {
|
||
|
/* WALL */
|
||
|
worldStr += "WAL " + tile[id].isWall + "\n";
|
||
|
}
|
||
|
if (tile[id].col != null && tile[id].col != undefined && tile[id].col != 1) {
|
||
|
/* COLOR OVERRIDE */
|
||
|
worldStr += "COL " + tile[id].col + "\n";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
/* SPRITES */
|
||
|
for (id in sprite) {
|
||
|
worldStr += "SPR " + id + "\n";
|
||
|
worldStr += serializeDrawing( "SPR_" + id );
|
||
|
if (sprite[id].name != null && sprite[id].name != undefined) {
|
||
|
/* NAME */
|
||
|
worldStr += "NAME " + sprite[id].name + "\n";
|
||
|
}
|
||
|
if (sprite[id].dlg != null) {
|
||
|
worldStr += "DLG " + sprite[id].dlg + "\n";
|
||
|
}
|
||
|
if (sprite[id].room != null) {
|
||
|
/* SPRITE POSITION */
|
||
|
worldStr += "POS " + sprite[id].room + " " + sprite[id].x + "," + sprite[id].y + "\n";
|
||
|
}
|
||
|
if (sprite[id].inventory != null) {
|
||
|
for(itemId in sprite[id].inventory) {
|
||
|
worldStr += "ITM " + itemId + " " + sprite[id].inventory[itemId] + "\n";
|
||
|
}
|
||
|
}
|
||
|
if (sprite[id].col != null && sprite[id].col != undefined && sprite[id].col != 2) {
|
||
|
/* COLOR OVERRIDE */
|
||
|
worldStr += "COL " + sprite[id].col + "\n";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
/* ITEMS */
|
||
|
for (id in item) {
|
||
|
worldStr += "ITM " + id + "\n";
|
||
|
worldStr += serializeDrawing( "ITM_" + id );
|
||
|
if (item[id].name != null && item[id].name != undefined) {
|
||
|
/* NAME */
|
||
|
worldStr += "NAME " + item[id].name + "\n";
|
||
|
}
|
||
|
if (item[id].dlg != null) {
|
||
|
worldStr += "DLG " + item[id].dlg + "\n";
|
||
|
}
|
||
|
if (item[id].col != null && item[id].col != undefined && item[id].col != 2) {
|
||
|
/* COLOR OVERRIDE */
|
||
|
worldStr += "COL " + item[id].col + "\n";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
/* DIALOG */
|
||
|
for (id in dialog) {
|
||
|
if (id != titleDialogId) {
|
||
|
worldStr += "DLG " + id + "\n";
|
||
|
worldStr += dialog[id].src + "\n";
|
||
|
if (dialog[id].name != null) {
|
||
|
worldStr += "NAME " + dialog[id].name + "\n";
|
||
|
}
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
}
|
||
|
/* VARIABLES */
|
||
|
for (id in variable) {
|
||
|
worldStr += "VAR " + id + "\n";
|
||
|
worldStr += variable[id] + "\n";
|
||
|
worldStr += "\n";
|
||
|
}
|
||
|
/* FONT */
|
||
|
// TODO : support multiple fonts
|
||
|
if (fontName != defaultFontName && !skipFonts) {
|
||
|
worldStr += fontManager.GetData(fontName);
|
||
|
}
|
||
|
|
||
|
return worldStr;
|
||
|
}
|
||
|
|
||
|
function serializeDrawing(drwId) {
|
||
|
var imageSource = renderer.GetImageSource(drwId);
|
||
|
var drwStr = "";
|
||
|
for (f in imageSource) {
|
||
|
for (y in imageSource[f]) {
|
||
|
var rowStr = "";
|
||
|
for (x in imageSource[f][y]) {
|
||
|
rowStr += imageSource[f][y][x];
|
||
|
}
|
||
|
drwStr += rowStr + "\n";
|
||
|
}
|
||
|
if (f < (imageSource.length-1)) drwStr += ">\n";
|
||
|
}
|
||
|
return drwStr;
|
||
|
}
|
||
|
|
||
|
function isExitValid(e) {
|
||
|
var hasValidStartPos = e.x >= 0 && e.x < 16 && e.y >= 0 && e.y < 16;
|
||
|
var hasDest = e.dest != null;
|
||
|
var hasValidRoomDest = (e.dest.room != null && e.dest.x >= 0 && e.dest.x < 16 && e.dest.y >= 0 && e.dest.y < 16);
|
||
|
return hasValidStartPos && hasDest && hasValidRoomDest;
|
||
|
}
|
||
|
|
||
|
function placeSprites() {
|
||
|
for (id in spriteStartLocations) {
|
||
|
//console.log(id);
|
||
|
//console.log( spriteStartLocations[id] );
|
||
|
//console.log(sprite[id]);
|
||
|
sprite[id].room = spriteStartLocations[id].room;
|
||
|
sprite[id].x = spriteStartLocations[id].x;
|
||
|
sprite[id].y = spriteStartLocations[id].y;
|
||
|
//console.log(sprite[id]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ARGUMENT GETTERS */
|
||
|
function getType(line) {
|
||
|
return getArg(line,0);
|
||
|
}
|
||
|
|
||
|
function getId(line) {
|
||
|
return getArg(line,1);
|
||
|
}
|
||
|
|
||
|
function getArg(line,arg) {
|
||
|
return line.split(" ")[arg];
|
||
|
}
|
||
|
|
||
|
function getCoord(line,arg) {
|
||
|
return getArg(line,arg).split(",");
|
||
|
}
|
||
|
|
||
|
function parseTitle(lines, i) {
|
||
|
var results = scriptUtils.ReadDialogScript(lines,i);
|
||
|
setTitle(results.script);
|
||
|
i = results.index;
|
||
|
|
||
|
i++;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseRoom(lines, i, compatibilityFlags) {
|
||
|
var id = getId(lines[i]);
|
||
|
room[id] = {
|
||
|
id : id,
|
||
|
tilemap : [],
|
||
|
walls : [],
|
||
|
exits : [],
|
||
|
endings : [],
|
||
|
items : [],
|
||
|
pal : null,
|
||
|
name : null
|
||
|
};
|
||
|
i++;
|
||
|
|
||
|
// create tile map
|
||
|
if ( flags.ROOM_FORMAT == 0 ) {
|
||
|
// old way: no commas, single char tile ids
|
||
|
var end = i + mapsize;
|
||
|
var y = 0;
|
||
|
for (; i<end; i++) {
|
||
|
room[id].tilemap.push( [] );
|
||
|
for (x = 0; x<mapsize; x++) {
|
||
|
room[id].tilemap[y].push( lines[i].charAt(x) );
|
||
|
}
|
||
|
y++;
|
||
|
}
|
||
|
}
|
||
|
else if ( flags.ROOM_FORMAT == 1 ) {
|
||
|
// new way: comma separated, multiple char tile ids
|
||
|
var end = i + mapsize;
|
||
|
var y = 0;
|
||
|
for (; i<end; i++) {
|
||
|
room[id].tilemap.push( [] );
|
||
|
var lineSep = lines[i].split(",");
|
||
|
for (x = 0; x<mapsize; x++) {
|
||
|
room[id].tilemap[y].push( lineSep[x] );
|
||
|
}
|
||
|
y++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (i < lines.length && lines[i].length > 0) { //look for empty line
|
||
|
// console.log(getType(lines[i]));
|
||
|
if (getType(lines[i]) === "SPR") {
|
||
|
/* NOTE SPRITE START LOCATIONS */
|
||
|
var sprId = getId(lines[i]);
|
||
|
if (sprId.indexOf(",") == -1 && lines[i].split(" ").length >= 3) { //second conditional checks for coords
|
||
|
/* PLACE A SINGLE SPRITE */
|
||
|
var sprCoord = lines[i].split(" ")[2].split(",");
|
||
|
spriteStartLocations[sprId] = {
|
||
|
room : id,
|
||
|
x : parseInt(sprCoord[0]),
|
||
|
y : parseInt(sprCoord[1])
|
||
|
};
|
||
|
}
|
||
|
else if ( flags.ROOM_FORMAT == 0 ) { // TODO: right now this shortcut only works w/ the old comma separate format
|
||
|
/* PLACE MULTIPLE SPRITES*/
|
||
|
//Does find and replace in the tilemap (may be hacky, but its convenient)
|
||
|
var sprList = sprId.split(",");
|
||
|
for (row in room[id].tilemap) {
|
||
|
for (s in sprList) {
|
||
|
var col = room[id].tilemap[row].indexOf( sprList[s] );
|
||
|
//if the sprite is in this row, replace it with the "null tile" and set its starting position
|
||
|
if (col != -1) {
|
||
|
room[id].tilemap[row][col] = "0";
|
||
|
spriteStartLocations[ sprList[s] ] = {
|
||
|
room : id,
|
||
|
x : parseInt(col),
|
||
|
y : parseInt(row)
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (getType(lines[i]) === "ITM") {
|
||
|
var itmId = getId(lines[i]);
|
||
|
var itmCoord = lines[i].split(" ")[2].split(",");
|
||
|
var itm = {
|
||
|
id: itmId,
|
||
|
x : parseInt(itmCoord[0]),
|
||
|
y : parseInt(itmCoord[1])
|
||
|
};
|
||
|
room[id].items.push( itm );
|
||
|
}
|
||
|
else if (getType(lines[i]) === "WAL") {
|
||
|
/* DEFINE COLLISIONS (WALLS) */
|
||
|
room[id].walls = getId(lines[i]).split(",");
|
||
|
}
|
||
|
else if (getType(lines[i]) === "EXT") {
|
||
|
/* ADD EXIT */
|
||
|
var exitArgs = lines[i].split(" ");
|
||
|
//arg format: EXT 10,5 M 3,2 [AVA:7 LCK:a,9] [AVA 7 LCK a 9]
|
||
|
var exitCoords = exitArgs[1].split(",");
|
||
|
var destName = exitArgs[2];
|
||
|
var destCoords = exitArgs[3].split(",");
|
||
|
var ext = {
|
||
|
x : parseInt(exitCoords[0]),
|
||
|
y : parseInt(exitCoords[1]),
|
||
|
dest : {
|
||
|
room : destName,
|
||
|
x : parseInt(destCoords[0]),
|
||
|
y : parseInt(destCoords[1])
|
||
|
},
|
||
|
transition_effect : null,
|
||
|
dlg: null,
|
||
|
};
|
||
|
|
||
|
// optional arguments
|
||
|
var exitArgIndex = 4;
|
||
|
while (exitArgIndex < exitArgs.length) {
|
||
|
if (exitArgs[exitArgIndex] == "FX") {
|
||
|
ext.transition_effect = exitArgs[exitArgIndex+1];
|
||
|
exitArgIndex += 2;
|
||
|
}
|
||
|
else if (exitArgs[exitArgIndex] == "DLG") {
|
||
|
ext.dlg = exitArgs[exitArgIndex+1];
|
||
|
exitArgIndex += 2;
|
||
|
}
|
||
|
else {
|
||
|
exitArgIndex += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
room[id].exits.push(ext);
|
||
|
}
|
||
|
else if (getType(lines[i]) === "END") {
|
||
|
/* ADD ENDING */
|
||
|
var endId = getId(lines[i]);
|
||
|
|
||
|
// compatibility with when endings were stored separate from other dialog
|
||
|
if (compatibilityFlags.combineEndingsWithDialog) {
|
||
|
endId = "end_" + endId;
|
||
|
}
|
||
|
|
||
|
var endCoords = getCoord(lines[i], 2);
|
||
|
var end = {
|
||
|
id : endId,
|
||
|
x : parseInt(endCoords[0]),
|
||
|
y : parseInt(endCoords[1])
|
||
|
};
|
||
|
|
||
|
room[id].endings.push(end);
|
||
|
}
|
||
|
else if (getType(lines[i]) === "PAL") {
|
||
|
/* CHOOSE PALETTE (that's not default) */
|
||
|
room[id].pal = getId(lines[i]);
|
||
|
}
|
||
|
else if (getType(lines[i]) === "NAME") {
|
||
|
var name = lines[i].split(/\s(.+)/)[1];
|
||
|
room[id].name = name;
|
||
|
names.room.set(name, id);
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parsePalette(lines,i) { //todo this has to go first right now :(
|
||
|
var id = getId(lines[i]);
|
||
|
i++;
|
||
|
var colors = [];
|
||
|
var name = null;
|
||
|
while (i < lines.length && lines[i].length > 0) { //look for empty line
|
||
|
var args = lines[i].split(" ");
|
||
|
if (args[0] === "NAME") {
|
||
|
name = lines[i].split(/\s(.+)/)[1];
|
||
|
}
|
||
|
else {
|
||
|
var col = [];
|
||
|
lines[i].split(",").forEach(function(i) {
|
||
|
col.push(parseInt(i));
|
||
|
});
|
||
|
colors.push(col);
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
palette[id] = {
|
||
|
id : id,
|
||
|
name : name,
|
||
|
colors : colors
|
||
|
};
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseTile(lines, i) {
|
||
|
var id = getId(lines[i]);
|
||
|
var drwId = null;
|
||
|
var name = null;
|
||
|
|
||
|
i++;
|
||
|
|
||
|
if (getType(lines[i]) === "DRW") { //load existing drawing
|
||
|
drwId = getId(lines[i]);
|
||
|
i++;
|
||
|
}
|
||
|
else {
|
||
|
// store tile source
|
||
|
drwId = "TIL_" + id;
|
||
|
i = parseDrawingCore( lines, i, drwId );
|
||
|
}
|
||
|
|
||
|
//other properties
|
||
|
var colorIndex = 1; // default palette color index is 1
|
||
|
var isWall = null; // null indicates it can vary from room to room (original version)
|
||
|
while (i < lines.length && lines[i].length > 0) { //look for empty line
|
||
|
if (getType(lines[i]) === "COL") {
|
||
|
colorIndex = parseInt( getId(lines[i]) );
|
||
|
}
|
||
|
else if (getType(lines[i]) === "NAME") {
|
||
|
/* NAME */
|
||
|
name = lines[i].split(/\s(.+)/)[1];
|
||
|
names.tile.set( name, id );
|
||
|
}
|
||
|
else if (getType(lines[i]) === "WAL") {
|
||
|
var wallArg = getArg( lines[i], 1 );
|
||
|
if( wallArg === "true" ) {
|
||
|
isWall = true;
|
||
|
}
|
||
|
else if( wallArg === "false" ) {
|
||
|
isWall = false;
|
||
|
}
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
//tile data
|
||
|
tile[id] = {
|
||
|
id : id,
|
||
|
drw : drwId, //drawing id
|
||
|
col : colorIndex,
|
||
|
animation : {
|
||
|
isAnimated : (renderer.GetFrameCount(drwId) > 1),
|
||
|
frameIndex : 0,
|
||
|
frameCount : renderer.GetFrameCount(drwId)
|
||
|
},
|
||
|
name : name,
|
||
|
isWall : isWall
|
||
|
};
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseSprite(lines, i) {
|
||
|
var id = getId(lines[i]);
|
||
|
var drwId = null;
|
||
|
var name = null;
|
||
|
|
||
|
i++;
|
||
|
|
||
|
if (getType(lines[i]) === "DRW") { //load existing drawing
|
||
|
drwId = getId(lines[i]);
|
||
|
i++;
|
||
|
}
|
||
|
else {
|
||
|
// store sprite source
|
||
|
drwId = "SPR_" + id;
|
||
|
i = parseDrawingCore( lines, i, drwId );
|
||
|
}
|
||
|
|
||
|
//other properties
|
||
|
var colorIndex = 2; //default palette color index is 2
|
||
|
var dialogId = null;
|
||
|
var startingInventory = {};
|
||
|
while (i < lines.length && lines[i].length > 0) { //look for empty line
|
||
|
if (getType(lines[i]) === "COL") {
|
||
|
/* COLOR OFFSET INDEX */
|
||
|
colorIndex = parseInt( getId(lines[i]) );
|
||
|
}
|
||
|
else if (getType(lines[i]) === "POS") {
|
||
|
/* STARTING POSITION */
|
||
|
var posArgs = lines[i].split(" ");
|
||
|
var roomId = posArgs[1];
|
||
|
var coordArgs = posArgs[2].split(",");
|
||
|
spriteStartLocations[id] = {
|
||
|
room : roomId,
|
||
|
x : parseInt(coordArgs[0]),
|
||
|
y : parseInt(coordArgs[1])
|
||
|
};
|
||
|
}
|
||
|
else if(getType(lines[i]) === "DLG") {
|
||
|
dialogId = getId(lines[i]);
|
||
|
}
|
||
|
else if (getType(lines[i]) === "NAME") {
|
||
|
/* NAME */
|
||
|
name = lines[i].split(/\s(.+)/)[1];
|
||
|
names.sprite.set( name, id );
|
||
|
}
|
||
|
else if (getType(lines[i]) === "ITM") {
|
||
|
/* ITEM STARTING INVENTORY */
|
||
|
var itemId = getId(lines[i]);
|
||
|
var itemCount = parseFloat( getArg(lines[i], 2) );
|
||
|
startingInventory[itemId] = itemCount;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
//sprite data
|
||
|
sprite[id] = {
|
||
|
id : id,
|
||
|
drw : drwId, //drawing id
|
||
|
col : colorIndex,
|
||
|
dlg : dialogId,
|
||
|
room : null, //default location is "offstage"
|
||
|
x : -1,
|
||
|
y : -1,
|
||
|
animation : {
|
||
|
isAnimated : (renderer.GetFrameCount(drwId) > 1),
|
||
|
frameIndex : 0,
|
||
|
frameCount : renderer.GetFrameCount(drwId)
|
||
|
},
|
||
|
inventory : startingInventory,
|
||
|
name : name
|
||
|
};
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseItem(lines, i) {
|
||
|
var id = getId(lines[i]);
|
||
|
var drwId = null;
|
||
|
var name = null;
|
||
|
|
||
|
i++;
|
||
|
|
||
|
if (getType(lines[i]) === "DRW") { //load existing drawing
|
||
|
drwId = getId(lines[i]);
|
||
|
i++;
|
||
|
}
|
||
|
else {
|
||
|
// store item source
|
||
|
drwId = "ITM_" + id; // these prefixes are maybe a terrible way to differentiate drawing tyepes :/
|
||
|
i = parseDrawingCore( lines, i, drwId );
|
||
|
}
|
||
|
|
||
|
//other properties
|
||
|
var colorIndex = 2; //default palette color index is 2
|
||
|
var dialogId = null;
|
||
|
while (i < lines.length && lines[i].length > 0) { //look for empty line
|
||
|
if (getType(lines[i]) === "COL") {
|
||
|
/* COLOR OFFSET INDEX */
|
||
|
colorIndex = parseInt( getArg( lines[i], 1 ) );
|
||
|
}
|
||
|
// else if (getType(lines[i]) === "POS") {
|
||
|
// /* STARTING POSITION */
|
||
|
// var posArgs = lines[i].split(" ");
|
||
|
// var roomId = posArgs[1];
|
||
|
// var coordArgs = posArgs[2].split(",");
|
||
|
// spriteStartLocations[id] = {
|
||
|
// room : roomId,
|
||
|
// x : parseInt(coordArgs[0]),
|
||
|
// y : parseInt(coordArgs[1])
|
||
|
// };
|
||
|
// }
|
||
|
else if(getType(lines[i]) === "DLG") {
|
||
|
dialogId = getId(lines[i]);
|
||
|
}
|
||
|
else if (getType(lines[i]) === "NAME") {
|
||
|
/* NAME */
|
||
|
name = lines[i].split(/\s(.+)/)[1];
|
||
|
names.item.set( name, id );
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
//item data
|
||
|
item[id] = {
|
||
|
id : id,
|
||
|
drw : drwId, //drawing id
|
||
|
col : colorIndex,
|
||
|
dlg : dialogId,
|
||
|
// room : null, //default location is "offstage"
|
||
|
// x : -1,
|
||
|
// y : -1,
|
||
|
animation : {
|
||
|
isAnimated : (renderer.GetFrameCount(drwId) > 1),
|
||
|
frameIndex : 0,
|
||
|
frameCount : renderer.GetFrameCount(drwId)
|
||
|
},
|
||
|
name : name
|
||
|
};
|
||
|
|
||
|
// console.log("ITM " + id);
|
||
|
// console.log(item[id]);
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseDrawing(lines, i) {
|
||
|
// store drawing source
|
||
|
var drwId = getId( lines[i] );
|
||
|
return parseDrawingCore( lines, i, drwId );
|
||
|
}
|
||
|
|
||
|
function parseDrawingCore(lines, i, drwId) {
|
||
|
var frameIndex = 0;
|
||
|
var frameListStrings = [];
|
||
|
frameListStrings.push([]);
|
||
|
|
||
|
while (!isNaN(parseInt(lines[i].charAt(0))) || lines[i].charAt(0) === ">") {
|
||
|
if ( lines[i].charAt(0) === ">") {
|
||
|
frameListStrings.push([]);
|
||
|
frameIndex++;
|
||
|
} else {
|
||
|
frameListStrings[frameIndex].push(lines[i]);
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
// interpret drawing size as a number of lines in the first frame
|
||
|
var drawingSize = frameListStrings[0].length;
|
||
|
|
||
|
var framesParsed = [];
|
||
|
|
||
|
// parse drawing data
|
||
|
frameListStrings.forEach(function (frame, frameIndex) {
|
||
|
framesParsed[frameIndex] = [];
|
||
|
for (y = 0; y < drawingSize; y++) {
|
||
|
var line = frame[y] || '';
|
||
|
framesParsed[frameIndex][y] = [];
|
||
|
for (x = 0; x < drawingSize; x++) {
|
||
|
var parsedPixel = parseInt(line.charAt(x));
|
||
|
parsedPixel = isNaN(parsedPixel)? 0: parsedPixel;
|
||
|
framesParsed[frameIndex][y].push(parsedPixel);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
renderer.SetImageSource(drwId, framesParsed);
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseScript(lines, i, backCompatPrefix, compatibilityFlags) {
|
||
|
var id = getId(lines[i]);
|
||
|
id = backCompatPrefix + id;
|
||
|
i++;
|
||
|
|
||
|
var results = scriptUtils.ReadDialogScript(lines,i);
|
||
|
|
||
|
dialog[id] = { src:results.script, name:null };
|
||
|
|
||
|
if (compatibilityFlags.convertImplicitSpriteDialogIds) {
|
||
|
// explicitly hook up dialog that used to be implicitly
|
||
|
// connected by sharing sprite and dialog IDs in old versions
|
||
|
if (sprite[id]) {
|
||
|
if (sprite[id].dlg === undefined || sprite[id].dlg === null) {
|
||
|
sprite[id].dlg = id;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i = results.index;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseDialog(lines, i, compatibilityFlags) {
|
||
|
// hacky but I need to store this so I can set the name below
|
||
|
var id = getId(lines[i]);
|
||
|
|
||
|
i = parseScript(lines, i, "", compatibilityFlags);
|
||
|
|
||
|
if (lines[i].length > 0 && getType(lines[i]) === "NAME") {
|
||
|
dialog[id].name = lines[i].split(/\s(.+)/)[1]; // TODO : hacky to keep copying this regex around...
|
||
|
names.dialog.set(dialog[id].name, id);
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
// keeping this around to parse old files where endings were separate from dialogs
|
||
|
function parseEnding(lines, i, compatibilityFlags) {
|
||
|
return parseScript(lines, i, "end_", compatibilityFlags);
|
||
|
}
|
||
|
|
||
|
function parseVariable(lines, i) {
|
||
|
var id = getId(lines[i]);
|
||
|
i++;
|
||
|
var value = lines[i];
|
||
|
i++;
|
||
|
variable[id] = value;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseFontName(lines, i) {
|
||
|
fontName = getArg(lines[i], 1);
|
||
|
i++;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseTextDirection(lines, i) {
|
||
|
textDirection = getArg(lines[i], 1);
|
||
|
i++;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseFontData(lines, i) {
|
||
|
// NOTE : we're not doing the actual parsing here --
|
||
|
// just grabbing the block of text that represents the font
|
||
|
// and giving it to the font manager to use later
|
||
|
|
||
|
var localFontName = getId(lines[i]);
|
||
|
var localFontData = lines[i];
|
||
|
i++;
|
||
|
|
||
|
while (i < lines.length && lines[i] != "") {
|
||
|
localFontData += "\n" + lines[i];
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
var localFontFilename = localFontName + fontManager.GetExtension();
|
||
|
fontManager.AddResource( localFontFilename, localFontData );
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function parseFlag(lines, i) {
|
||
|
var id = getId(lines[i]);
|
||
|
var valStr = lines[i].split(" ")[2];
|
||
|
flags[id] = parseInt( valStr );
|
||
|
i++;
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
function drawTile(img,x,y,context) {
|
||
|
if (!context) { //optional pass in context; otherwise, use default
|
||
|
context = ctx;
|
||
|
}
|
||
|
// NOTE: images are now canvases, instead of raw image data (for chrome performance reasons)
|
||
|
context.drawImage(img,x*tilesize*scale,y*tilesize*scale,tilesize*scale,tilesize*scale);
|
||
|
}
|
||
|
|
||
|
function drawSprite(img,x,y,context) { //this may differ later (or not haha)
|
||
|
drawTile(img,x,y,context);
|
||
|
}
|
||
|
|
||
|
function drawItem(img,x,y,context) {
|
||
|
drawTile(img,x,y,context); //TODO these methods are dumb and repetitive
|
||
|
}
|
||
|
|
||
|
// var debugLastRoomDrawn = "0";
|
||
|
|
||
|
function drawRoom(room,context,frameIndex) { // context & frameIndex are optional
|
||
|
if (!context) { //optional pass in context; otherwise, use default (ok this is REAL hacky isn't it)
|
||
|
context = ctx;
|
||
|
}
|
||
|
|
||
|
// if (room.id != debugLastRoomDrawn) {
|
||
|
// debugLastRoomDrawn = room.id;
|
||
|
// console.log("DRAW ROOM " + debugLastRoomDrawn);
|
||
|
// }
|
||
|
|
||
|
var paletteId = "default";
|
||
|
|
||
|
if (room === undefined) {
|
||
|
// protect against invalid rooms
|
||
|
context.fillStyle = "rgb(" + getPal(paletteId)[0][0] + "," + getPal(paletteId)[0][1] + "," + getPal(paletteId)[0][2] + ")";
|
||
|
context.fillRect(0,0,canvas.width,canvas.height);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//clear screen
|
||
|
if (room.pal != null && palette[paletteId] != undefined) {
|
||
|
paletteId = room.pal;
|
||
|
}
|
||
|
context.fillStyle = "rgb(" + getPal(paletteId)[0][0] + "," + getPal(paletteId)[0][1] + "," + getPal(paletteId)[0][2] + ")";
|
||
|
context.fillRect(0,0,canvas.width,canvas.height);
|
||
|
|
||
|
//draw tiles
|
||
|
for (i in room.tilemap) {
|
||
|
for (j in room.tilemap[i]) {
|
||
|
var id = room.tilemap[i][j];
|
||
|
if (id != "0") {
|
||
|
//console.log(id);
|
||
|
if (tile[id] == null) { // hack-around to avoid corrupting files (not a solution though!)
|
||
|
id = "0";
|
||
|
room.tilemap[i][j] = id;
|
||
|
}
|
||
|
else {
|
||
|
// console.log(id);
|
||
|
drawTile( getTileImage(tile[id],paletteId,frameIndex), j, i, context );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//draw items
|
||
|
for (var i = 0; i < room.items.length; i++) {
|
||
|
var itm = room.items[i];
|
||
|
drawItem( getItemImage(item[itm.id],paletteId,frameIndex), itm.x, itm.y, context );
|
||
|
}
|
||
|
|
||
|
//draw sprites
|
||
|
for (id in sprite) {
|
||
|
var spr = sprite[id];
|
||
|
if (spr.room === room.id) {
|
||
|
drawSprite( getSpriteImage(spr,paletteId,frameIndex), spr.x, spr.y, context );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TODO : remove these get*Image methods
|
||
|
function getTileImage(t,palId,frameIndex) {
|
||
|
return renderer.GetImage(t,palId,frameIndex);
|
||
|
}
|
||
|
|
||
|
function getSpriteImage(s,palId,frameIndex) {
|
||
|
return renderer.GetImage(s,palId,frameIndex);
|
||
|
}
|
||
|
|
||
|
function getItemImage(itm,palId,frameIndex) {
|
||
|
return renderer.GetImage(itm,palId,frameIndex);
|
||
|
}
|
||
|
|
||
|
function curPal() {
|
||
|
return getRoomPal(curRoom);
|
||
|
}
|
||
|
|
||
|
function getRoomPal(roomId) {
|
||
|
var defaultId = "default";
|
||
|
|
||
|
if (roomId == null) {
|
||
|
return defaultId;
|
||
|
}
|
||
|
else if (room[roomId].pal != null) {
|
||
|
//a specific palette was chosen
|
||
|
return room[roomId].pal;
|
||
|
}
|
||
|
else {
|
||
|
if (roomId in palette) {
|
||
|
//there is a palette matching the name of the room
|
||
|
return roomId;
|
||
|
}
|
||
|
else {
|
||
|
//use the default palette
|
||
|
return defaultId;
|
||
|
}
|
||
|
}
|
||
|
return defaultId;
|
||
|
}
|
||
|
|
||
|
var isDialogMode = false;
|
||
|
var isNarrating = false;
|
||
|
var isEnding = false;
|
||
|
var redirectBitsy = false;
|
||
|
var dialogModule = new Dialog();
|
||
|
var dialogRenderer = dialogModule.CreateRenderer();
|
||
|
var dialogBuffer = dialogModule.CreateBuffer();
|
||
|
var fontManager = new FontManager();
|
||
|
|
||
|
// TODO : is this scriptResult thing being used anywhere???
|
||
|
function onExitDialog(scriptResult, dialogCallback) {
|
||
|
console.log("EXIT DIALOG!");
|
||
|
|
||
|
isDialogMode = false;
|
||
|
|
||
|
if (isNarrating) {
|
||
|
isNarrating = false;
|
||
|
}
|
||
|
|
||
|
if (isDialogPreview) {
|
||
|
isDialogPreview = false;
|
||
|
|
||
|
if (onDialogPreviewEnd != null) {
|
||
|
onDialogPreviewEnd();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (dialogCallback != undefined && dialogCallback != null) {
|
||
|
dialogCallback(scriptResult);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
TODO
|
||
|
- titles and endings should also take advantage of the script pre-compilation if possible??
|
||
|
- could there be a namespace collision?
|
||
|
- what about dialog NAMEs vs IDs?
|
||
|
- what about a special script block separate from DLG?
|
||
|
*/
|
||
|
function startNarrating(dialogStr,end) {
|
||
|
console.log("NARRATE " + dialogStr);
|
||
|
|
||
|
if(end === undefined) {
|
||
|
end = false;
|
||
|
}
|
||
|
|
||
|
isNarrating = true;
|
||
|
isEnding = end;
|
||
|
|
||
|
startDialog(dialogStr);
|
||
|
}
|
||
|
|
||
|
function startEndingDialog(ending) {
|
||
|
isNarrating = true;
|
||
|
isEnding = true;
|
||
|
|
||
|
startDialog(
|
||
|
dialog[ending.id].src,
|
||
|
ending.id,
|
||
|
function() {
|
||
|
var isLocked = ending.property && ending.property.locked === true;
|
||
|
if (isLocked) {
|
||
|
isEnding = false;
|
||
|
}
|
||
|
},
|
||
|
ending);
|
||
|
}
|
||
|
|
||
|
function startItemDialog(itemId, dialogCallback) {
|
||
|
var dialogId = item[itemId].dlg;
|
||
|
// console.log("START ITEM DIALOG " + dialogId);
|
||
|
if (dialog[dialogId]) {
|
||
|
var dialogStr = dialog[dialogId].src;
|
||
|
startDialog(dialogStr, dialogId, dialogCallback);
|
||
|
}
|
||
|
else {
|
||
|
dialogCallback();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function startSpriteDialog(spriteId) {
|
||
|
var spr = sprite[spriteId];
|
||
|
var dialogId = spr.dlg;
|
||
|
// console.log("START SPRITE DIALOG " + dialogId);
|
||
|
if (dialog[dialogId]){
|
||
|
var dialogStr = dialog[dialogId].src;
|
||
|
startDialog(dialogStr,dialogId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function startDialog(dialogStr, scriptId, dialogCallback, objectContext) {
|
||
|
// console.log("START DIALOG ");
|
||
|
if (dialogStr.length <= 0) {
|
||
|
// console.log("ON EXIT DIALOG -- startDialog 1");
|
||
|
onExitDialog(null, dialogCallback);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
isDialogMode = true;
|
||
|
|
||
|
dialogRenderer.Reset();
|
||
|
dialogRenderer.SetCentered(isNarrating /*centered*/);
|
||
|
dialogBuffer.Reset();
|
||
|
scriptInterpreter.SetDialogBuffer(dialogBuffer);
|
||
|
|
||
|
var onScriptEnd = function(scriptResult) {
|
||
|
dialogBuffer.OnDialogEnd(function() {
|
||
|
onExitDialog(scriptResult, dialogCallback);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
if (scriptId === undefined) { // TODO : what's this for again?
|
||
|
scriptInterpreter.Interpret(dialogStr, onScriptEnd);
|
||
|
}
|
||
|
else {
|
||
|
if (!scriptInterpreter.HasScript(scriptId)) {
|
||
|
scriptInterpreter.Compile(scriptId, dialogStr);
|
||
|
}
|
||
|
// scriptInterpreter.DebugVisualizeScript(scriptId);
|
||
|
scriptInterpreter.Run(scriptId, onScriptEnd, objectContext);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
var isDialogPreview = false;
|
||
|
function startPreviewDialog(script, dialogCallback) {
|
||
|
isNarrating = true;
|
||
|
|
||
|
isDialogMode = true;
|
||
|
|
||
|
isDialogPreview = true;
|
||
|
|
||
|
dialogRenderer.Reset();
|
||
|
dialogRenderer.SetCentered(true);
|
||
|
dialogBuffer.Reset();
|
||
|
scriptInterpreter.SetDialogBuffer(dialogBuffer);
|
||
|
|
||
|
// TODO : do I really need a seperate callback for this debug mode??
|
||
|
onDialogPreviewEnd = dialogCallback;
|
||
|
|
||
|
var onScriptEndCallback = function(scriptResult) {
|
||
|
dialogBuffer.OnDialogEnd(function() {
|
||
|
onExitDialog(scriptResult, null);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
scriptInterpreter.Eval(script, onScriptEndCallback);
|
||
|
}
|
||
|
|
||
|
/* NEW SCRIPT STUFF */
|
||
|
var scriptModule = new Script();
|
||
|
var scriptInterpreter = scriptModule.CreateInterpreter();
|
||
|
var scriptUtils = scriptModule.CreateUtils(); // TODO: move to editor.js?
|
||
|
// scriptInterpreter.SetDialogBuffer( dialogBuffer );
|
||
|
|
||
|
</script>
|
||
|
|
||
|
<!-- store default font in separate script tag for back compat-->
|
||
|
<script type="text/bitsyFontData" id="ascii_small">
|
||
|
FONT ascii_small
|
||
|
SIZE 6 8
|
||
|
CHAR 0
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 1
|
||
|
001110
|
||
|
010001
|
||
|
011011
|
||
|
010001
|
||
|
010101
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 2
|
||
|
001110
|
||
|
011111
|
||
|
010101
|
||
|
011111
|
||
|
010001
|
||
|
011111
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 3
|
||
|
000000
|
||
|
001010
|
||
|
011111
|
||
|
011111
|
||
|
011111
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 4
|
||
|
000000
|
||
|
000000
|
||
|
001010
|
||
|
001110
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 5
|
||
|
000100
|
||
|
001110
|
||
|
001110
|
||
|
000100
|
||
|
011111
|
||
|
011111
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 6
|
||
|
000000
|
||
|
000100
|
||
|
001110
|
||
|
011111
|
||
|
011111
|
||
|
000100
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 7
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 8
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
110011
|
||
|
110011
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 9
|
||
|
000000
|
||
|
000000
|
||
|
011110
|
||
|
010010
|
||
|
010010
|
||
|
011110
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 10
|
||
|
111111
|
||
|
111111
|
||
|
100001
|
||
|
101101
|
||
|
101101
|
||
|
100001
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 11
|
||
|
000000
|
||
|
000111
|
||
|
000011
|
||
|
001101
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 12
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000100
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 13
|
||
|
000100
|
||
|
000110
|
||
|
000101
|
||
|
000100
|
||
|
001100
|
||
|
011100
|
||
|
011000
|
||
|
000000
|
||
|
CHAR 14
|
||
|
000011
|
||
|
001101
|
||
|
001011
|
||
|
001101
|
||
|
001011
|
||
|
011011
|
||
|
011000
|
||
|
000000
|
||
|
CHAR 15
|
||
|
000000
|
||
|
010101
|
||
|
001110
|
||
|
011011
|
||
|
001110
|
||
|
010101
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 16
|
||
|
001000
|
||
|
001100
|
||
|
001110
|
||
|
001111
|
||
|
001110
|
||
|
001100
|
||
|
001000
|
||
|
000000
|
||
|
CHAR 17
|
||
|
000010
|
||
|
000110
|
||
|
001110
|
||
|
011110
|
||
|
001110
|
||
|
000110
|
||
|
000010
|
||
|
000000
|
||
|
CHAR 18
|
||
|
000100
|
||
|
001110
|
||
|
011111
|
||
|
000100
|
||
|
011111
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 19
|
||
|
001010
|
||
|
001010
|
||
|
001010
|
||
|
001010
|
||
|
001010
|
||
|
000000
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 20
|
||
|
001111
|
||
|
010101
|
||
|
010101
|
||
|
001101
|
||
|
000101
|
||
|
000101
|
||
|
000101
|
||
|
000000
|
||
|
CHAR 21
|
||
|
001110
|
||
|
010001
|
||
|
001100
|
||
|
001010
|
||
|
000110
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 22
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
011110
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 23
|
||
|
000100
|
||
|
001110
|
||
|
011111
|
||
|
000100
|
||
|
011111
|
||
|
001110
|
||
|
000100
|
||
|
001110
|
||
|
CHAR 24
|
||
|
000100
|
||
|
001110
|
||
|
011111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 25
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
011111
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 26
|
||
|
000000
|
||
|
000100
|
||
|
000110
|
||
|
011111
|
||
|
000110
|
||
|
000100
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 27
|
||
|
000000
|
||
|
000100
|
||
|
001100
|
||
|
011111
|
||
|
001100
|
||
|
000100
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 28
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
011111
|
||
|
000000
|
||
|
CHAR 29
|
||
|
000000
|
||
|
001010
|
||
|
001010
|
||
|
011111
|
||
|
001010
|
||
|
001010
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 30
|
||
|
000100
|
||
|
000100
|
||
|
001110
|
||
|
001110
|
||
|
011111
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 31
|
||
|
011111
|
||
|
011111
|
||
|
001110
|
||
|
001110
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 32
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 33
|
||
|
000100
|
||
|
001110
|
||
|
001110
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 34
|
||
|
011011
|
||
|
011011
|
||
|
010010
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 35
|
||
|
000000
|
||
|
001010
|
||
|
011111
|
||
|
001010
|
||
|
001010
|
||
|
011111
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 36
|
||
|
001000
|
||
|
001110
|
||
|
010000
|
||
|
001100
|
||
|
000010
|
||
|
011100
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 37
|
||
|
011001
|
||
|
011001
|
||
|
000010
|
||
|
000100
|
||
|
001000
|
||
|
010011
|
||
|
010011
|
||
|
000000
|
||
|
CHAR 38
|
||
|
001000
|
||
|
010100
|
||
|
010100
|
||
|
001000
|
||
|
010101
|
||
|
010010
|
||
|
001101
|
||
|
000000
|
||
|
CHAR 39
|
||
|
001100
|
||
|
001100
|
||
|
001000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 40
|
||
|
000100
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 41
|
||
|
001000
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
001000
|
||
|
000000
|
||
|
CHAR 42
|
||
|
000000
|
||
|
001010
|
||
|
001110
|
||
|
011111
|
||
|
001110
|
||
|
001010
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 43
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
011111
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 44
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
001000
|
||
|
CHAR 45
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 46
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 47
|
||
|
000000
|
||
|
000001
|
||
|
000010
|
||
|
000100
|
||
|
001000
|
||
|
010000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 48
|
||
|
001110
|
||
|
010001
|
||
|
010011
|
||
|
010101
|
||
|
011001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 49
|
||
|
000100
|
||
|
001100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 50
|
||
|
001110
|
||
|
010001
|
||
|
000001
|
||
|
000110
|
||
|
001000
|
||
|
010000
|
||
|
011111
|
||
|
000000
|
||
|
CHAR 51
|
||
|
001110
|
||
|
010001
|
||
|
000001
|
||
|
001110
|
||
|
000001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 52
|
||
|
000010
|
||
|
000110
|
||
|
001010
|
||
|
010010
|
||
|
011111
|
||
|
000010
|
||
|
000010
|
||
|
000000
|
||
|
CHAR 53
|
||
|
011111
|
||
|
010000
|
||
|
010000
|
||
|
011110
|
||
|
000001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 54
|
||
|
000110
|
||
|
001000
|
||
|
010000
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 55
|
||
|
011111
|
||
|
000001
|
||
|
000010
|
||
|
000100
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
000000
|
||
|
CHAR 56
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 57
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
001111
|
||
|
000001
|
||
|
000010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 58
|
||
|
000000
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 59
|
||
|
000000
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
000000
|
||
|
001100
|
||
|
001100
|
||
|
001000
|
||
|
CHAR 60
|
||
|
000010
|
||
|
000100
|
||
|
001000
|
||
|
010000
|
||
|
001000
|
||
|
000100
|
||
|
000010
|
||
|
000000
|
||
|
CHAR 61
|
||
|
000000
|
||
|
000000
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 62
|
||
|
001000
|
||
|
000100
|
||
|
000010
|
||
|
000001
|
||
|
000010
|
||
|
000100
|
||
|
001000
|
||
|
000000
|
||
|
CHAR 63
|
||
|
001110
|
||
|
010001
|
||
|
000001
|
||
|
000110
|
||
|
000100
|
||
|
000000
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 64
|
||
|
001110
|
||
|
010001
|
||
|
010111
|
||
|
010101
|
||
|
010111
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 65
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
011111
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 66
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 67
|
||
|
001110
|
||
|
010001
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 68
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 69
|
||
|
011111
|
||
|
010000
|
||
|
010000
|
||
|
011110
|
||
|
010000
|
||
|
010000
|
||
|
011111
|
||
|
000000
|
||
|
CHAR 70
|
||
|
011111
|
||
|
010000
|
||
|
010000
|
||
|
011110
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
000000
|
||
|
CHAR 71
|
||
|
001110
|
||
|
010001
|
||
|
010000
|
||
|
010111
|
||
|
010001
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 72
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
011111
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 73
|
||
|
001110
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 74
|
||
|
000001
|
||
|
000001
|
||
|
000001
|
||
|
000001
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 75
|
||
|
010001
|
||
|
010010
|
||
|
010100
|
||
|
011000
|
||
|
010100
|
||
|
010010
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 76
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
011111
|
||
|
000000
|
||
|
CHAR 77
|
||
|
010001
|
||
|
011011
|
||
|
010101
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 78
|
||
|
010001
|
||
|
011001
|
||
|
010101
|
||
|
010011
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 79
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 80
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
000000
|
||
|
CHAR 81
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010101
|
||
|
010010
|
||
|
001101
|
||
|
000000
|
||
|
CHAR 82
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
010010
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 83
|
||
|
001110
|
||
|
010001
|
||
|
010000
|
||
|
001110
|
||
|
000001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 84
|
||
|
011111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 85
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 86
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001010
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 87
|
||
|
010001
|
||
|
010001
|
||
|
010101
|
||
|
010101
|
||
|
010101
|
||
|
010101
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 88
|
||
|
010001
|
||
|
010001
|
||
|
001010
|
||
|
000100
|
||
|
001010
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 89
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001010
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 90
|
||
|
011110
|
||
|
000010
|
||
|
000100
|
||
|
001000
|
||
|
010000
|
||
|
010000
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 91
|
||
|
001110
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 92
|
||
|
000000
|
||
|
010000
|
||
|
001000
|
||
|
000100
|
||
|
000010
|
||
|
000001
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 93
|
||
|
001110
|
||
|
000010
|
||
|
000010
|
||
|
000010
|
||
|
000010
|
||
|
000010
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 94
|
||
|
000100
|
||
|
001010
|
||
|
010001
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 95
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
CHAR 96
|
||
|
001100
|
||
|
001100
|
||
|
000100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 97
|
||
|
000000
|
||
|
000000
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 98
|
||
|
010000
|
||
|
010000
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 99
|
||
|
000000
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
010000
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 100
|
||
|
000001
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 101
|
||
|
000000
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 102
|
||
|
000110
|
||
|
001000
|
||
|
001000
|
||
|
011110
|
||
|
001000
|
||
|
001000
|
||
|
001000
|
||
|
000000
|
||
|
CHAR 103
|
||
|
000000
|
||
|
000000
|
||
|
001111
|
||
|
010001
|
||
|
010001
|
||
|
001111
|
||
|
000001
|
||
|
001110
|
||
|
CHAR 104
|
||
|
010000
|
||
|
010000
|
||
|
011100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 105
|
||
|
000100
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 106
|
||
|
000010
|
||
|
000000
|
||
|
000110
|
||
|
000010
|
||
|
000010
|
||
|
000010
|
||
|
010010
|
||
|
001100
|
||
|
CHAR 107
|
||
|
010000
|
||
|
010000
|
||
|
010010
|
||
|
010100
|
||
|
011000
|
||
|
010100
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 108
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 109
|
||
|
000000
|
||
|
000000
|
||
|
011010
|
||
|
010101
|
||
|
010101
|
||
|
010001
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 110
|
||
|
000000
|
||
|
000000
|
||
|
011100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 111
|
||
|
000000
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 112
|
||
|
000000
|
||
|
000000
|
||
|
011110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
CHAR 113
|
||
|
000000
|
||
|
000000
|
||
|
001111
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001111
|
||
|
000001
|
||
|
CHAR 114
|
||
|
000000
|
||
|
000000
|
||
|
010110
|
||
|
001001
|
||
|
001000
|
||
|
001000
|
||
|
011100
|
||
|
000000
|
||
|
CHAR 115
|
||
|
000000
|
||
|
000000
|
||
|
001110
|
||
|
010000
|
||
|
001110
|
||
|
000001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 116
|
||
|
000000
|
||
|
001000
|
||
|
011110
|
||
|
001000
|
||
|
001000
|
||
|
001010
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 117
|
||
|
000000
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010110
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 118
|
||
|
000000
|
||
|
000000
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001010
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 119
|
||
|
000000
|
||
|
000000
|
||
|
010001
|
||
|
010001
|
||
|
010101
|
||
|
011111
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 120
|
||
|
000000
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 121
|
||
|
000000
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001110
|
||
|
000100
|
||
|
011000
|
||
|
CHAR 122
|
||
|
000000
|
||
|
000000
|
||
|
011110
|
||
|
000010
|
||
|
001100
|
||
|
010000
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 123
|
||
|
000110
|
||
|
001000
|
||
|
001000
|
||
|
011000
|
||
|
001000
|
||
|
001000
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 124
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 125
|
||
|
001100
|
||
|
000010
|
||
|
000010
|
||
|
000011
|
||
|
000010
|
||
|
000010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 126
|
||
|
001010
|
||
|
010100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 127
|
||
|
000100
|
||
|
001110
|
||
|
011011
|
||
|
010001
|
||
|
010001
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 128
|
||
|
001110
|
||
|
010001
|
||
|
010000
|
||
|
010000
|
||
|
010001
|
||
|
001110
|
||
|
000100
|
||
|
001100
|
||
|
CHAR 129
|
||
|
010010
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010110
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 130
|
||
|
000011
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 131
|
||
|
001110
|
||
|
000000
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 132
|
||
|
001010
|
||
|
000000
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 133
|
||
|
001100
|
||
|
000000
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 134
|
||
|
001110
|
||
|
001010
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 135
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
010000
|
||
|
010001
|
||
|
001110
|
||
|
000100
|
||
|
001100
|
||
|
CHAR 136
|
||
|
001110
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 137
|
||
|
001010
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 138
|
||
|
001100
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
011110
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 139
|
||
|
001010
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 140
|
||
|
000100
|
||
|
001010
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 141
|
||
|
001000
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 142
|
||
|
001010
|
||
|
000000
|
||
|
000100
|
||
|
001010
|
||
|
010001
|
||
|
011111
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 143
|
||
|
001110
|
||
|
001010
|
||
|
001110
|
||
|
011011
|
||
|
010001
|
||
|
011111
|
||
|
010001
|
||
|
000000
|
||
|
CHAR 144
|
||
|
000011
|
||
|
000000
|
||
|
011111
|
||
|
010000
|
||
|
011110
|
||
|
010000
|
||
|
011111
|
||
|
000000
|
||
|
CHAR 145
|
||
|
000000
|
||
|
000000
|
||
|
011110
|
||
|
000101
|
||
|
011111
|
||
|
010100
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 146
|
||
|
001111
|
||
|
010100
|
||
|
010100
|
||
|
011111
|
||
|
010100
|
||
|
010100
|
||
|
010111
|
||
|
000000
|
||
|
CHAR 147
|
||
|
001110
|
||
|
000000
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 148
|
||
|
001010
|
||
|
000000
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 149
|
||
|
011000
|
||
|
000000
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 150
|
||
|
001110
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010110
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 151
|
||
|
011000
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010110
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 152
|
||
|
001010
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001110
|
||
|
000100
|
||
|
011000
|
||
|
CHAR 153
|
||
|
010010
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 154
|
||
|
001010
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 155
|
||
|
000000
|
||
|
000100
|
||
|
001110
|
||
|
010000
|
||
|
010000
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 156
|
||
|
000110
|
||
|
001001
|
||
|
001000
|
||
|
011110
|
||
|
001000
|
||
|
001001
|
||
|
010111
|
||
|
000000
|
||
|
CHAR 157
|
||
|
010001
|
||
|
001010
|
||
|
000100
|
||
|
011111
|
||
|
000100
|
||
|
011111
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 158
|
||
|
011000
|
||
|
010100
|
||
|
010100
|
||
|
011010
|
||
|
010111
|
||
|
010010
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 159
|
||
|
000010
|
||
|
000101
|
||
|
000100
|
||
|
001110
|
||
|
000100
|
||
|
000100
|
||
|
010100
|
||
|
001000
|
||
|
CHAR 160
|
||
|
000110
|
||
|
000000
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 161
|
||
|
000110
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000110
|
||
|
000000
|
||
|
CHAR 162
|
||
|
000110
|
||
|
000000
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 163
|
||
|
000110
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010110
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 164
|
||
|
001010
|
||
|
010100
|
||
|
000000
|
||
|
011100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 165
|
||
|
001010
|
||
|
010100
|
||
|
000000
|
||
|
010010
|
||
|
011010
|
||
|
010110
|
||
|
010010
|
||
|
000000
|
||
|
CHAR 166
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 167
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 168
|
||
|
000100
|
||
|
000000
|
||
|
000100
|
||
|
001100
|
||
|
010000
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 169
|
||
|
000000
|
||
|
000000
|
||
|
011111
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 170
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
000001
|
||
|
000001
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 171
|
||
|
010000
|
||
|
010010
|
||
|
010100
|
||
|
001110
|
||
|
010001
|
||
|
000010
|
||
|
000111
|
||
|
000000
|
||
|
CHAR 172
|
||
|
010000
|
||
|
010010
|
||
|
010100
|
||
|
001011
|
||
|
010101
|
||
|
000111
|
||
|
000001
|
||
|
000000
|
||
|
CHAR 173
|
||
|
000100
|
||
|
000000
|
||
|
000100
|
||
|
000100
|
||
|
001110
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 174
|
||
|
000000
|
||
|
000000
|
||
|
001001
|
||
|
010010
|
||
|
001001
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 175
|
||
|
000000
|
||
|
000000
|
||
|
010010
|
||
|
001001
|
||
|
010010
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 176
|
||
|
010101
|
||
|
000000
|
||
|
101010
|
||
|
000000
|
||
|
010101
|
||
|
000000
|
||
|
101010
|
||
|
000000
|
||
|
CHAR 177
|
||
|
010101
|
||
|
101010
|
||
|
010101
|
||
|
101010
|
||
|
010101
|
||
|
101010
|
||
|
010101
|
||
|
101010
|
||
|
CHAR 178
|
||
|
101010
|
||
|
111111
|
||
|
010101
|
||
|
111111
|
||
|
101010
|
||
|
111111
|
||
|
010101
|
||
|
111111
|
||
|
CHAR 179
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 180
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
111100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 181
|
||
|
000000
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
011100
|
||
|
010000
|
||
|
010000
|
||
|
CHAR 182
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
110100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 183
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 184
|
||
|
000000
|
||
|
111100
|
||
|
000100
|
||
|
111100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 185
|
||
|
010100
|
||
|
110100
|
||
|
000100
|
||
|
110100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 186
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 187
|
||
|
000000
|
||
|
111100
|
||
|
000100
|
||
|
110100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 188
|
||
|
010100
|
||
|
110100
|
||
|
000100
|
||
|
111100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 189
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
111100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 190
|
||
|
000100
|
||
|
111100
|
||
|
000100
|
||
|
111100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 191
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 192
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 193
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
111111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 194
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 195
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 196
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 197
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
111111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 198
|
||
|
000100
|
||
|
000111
|
||
|
000100
|
||
|
000111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 199
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010111
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 200
|
||
|
010100
|
||
|
010111
|
||
|
010000
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 201
|
||
|
000000
|
||
|
011111
|
||
|
010000
|
||
|
010111
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 202
|
||
|
010100
|
||
|
110111
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 203
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
110111
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 204
|
||
|
010100
|
||
|
010111
|
||
|
010000
|
||
|
010111
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 205
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 206
|
||
|
010100
|
||
|
110111
|
||
|
000000
|
||
|
110111
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 207
|
||
|
000100
|
||
|
111111
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 208
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
111111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 209
|
||
|
000000
|
||
|
111111
|
||
|
000000
|
||
|
111111
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
CHAR 210
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
CHAR 211
|
||
|
010100
|
||
|
010100
|
||
|
010100
|
||
|
011111
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 212
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
CHAR 213
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 214
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 215
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 216
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 217
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 218
|
||
|
000000
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 219
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
111111
|
||
|
CHAR 220
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
CHAR 221
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
CHAR 222
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
CHAR 223
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
CHAR 224
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
CHAR 225
|
||
|
000000
|
||
|
011100
|
||
|
010010
|
||
|
011100
|
||
|
010010
|
||
|
010010
|
||
|
011100
|
||
|
010000
|
||
|
CHAR 226
|
||
|
011110
|
||
|
010010
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
010000
|
||
|
000000
|
||
|
CHAR 227
|
||
|
000000
|
||
|
011111
|
||
|
001010
|
||
|
001010
|
||
|
001010
|
||
|
001010
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 228
|
||
|
001010
|
||
|
000000
|
||
|
001110
|
||
|
000001
|
||
|
001111
|
||
|
010001
|
||
|
001111
|
||
|
000000
|
||
|
CHAR 229
|
||
|
000000
|
||
|
000000
|
||
|
001111
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 230
|
||
|
000000
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
011100
|
||
|
010000
|
||
|
010000
|
||
|
CHAR 231
|
||
|
000000
|
||
|
000000
|
||
|
001010
|
||
|
010100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 232
|
||
|
001110
|
||
|
000100
|
||
|
001110
|
||
|
010001
|
||
|
001110
|
||
|
000100
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 233
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
011110
|
||
|
010010
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 234
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
001010
|
||
|
001010
|
||
|
011011
|
||
|
000000
|
||
|
CHAR 235
|
||
|
001100
|
||
|
010000
|
||
|
001000
|
||
|
000100
|
||
|
001110
|
||
|
010010
|
||
|
001100
|
||
|
000000
|
||
|
CHAR 236
|
||
|
000000
|
||
|
000000
|
||
|
001010
|
||
|
010101
|
||
|
010101
|
||
|
001010
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 237
|
||
|
000000
|
||
|
000100
|
||
|
001110
|
||
|
010101
|
||
|
010101
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
CHAR 238
|
||
|
000000
|
||
|
001110
|
||
|
010000
|
||
|
011110
|
||
|
010000
|
||
|
001110
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 239
|
||
|
000000
|
||
|
001100
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 240
|
||
|
000000
|
||
|
011110
|
||
|
000000
|
||
|
011110
|
||
|
000000
|
||
|
011110
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 241
|
||
|
000000
|
||
|
000100
|
||
|
001110
|
||
|
000100
|
||
|
000000
|
||
|
001110
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 242
|
||
|
010000
|
||
|
001100
|
||
|
000010
|
||
|
001100
|
||
|
010000
|
||
|
000000
|
||
|
011110
|
||
|
000000
|
||
|
CHAR 243
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
111000
|
||
|
100110
|
||
|
100001
|
||
|
100000
|
||
|
111111
|
||
|
CHAR 244
|
||
|
000000
|
||
|
000000
|
||
|
111111
|
||
|
000111
|
||
|
011001
|
||
|
100001
|
||
|
000001
|
||
|
111111
|
||
|
CHAR 245
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
000100
|
||
|
010100
|
||
|
001000
|
||
|
000000
|
||
|
CHAR 246
|
||
|
001010
|
||
|
000000
|
||
|
001110
|
||
|
010001
|
||
|
010001
|
||
|
010001
|
||
|
001110
|
||
|
000000
|
||
|
CHAR 247
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
111110
|
||
|
CHAR 248
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
111100
|
||
|
CHAR 249
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
111000
|
||
|
CHAR 250
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
110000
|
||
|
CHAR 251
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
100000
|
||
|
CHAR 252
|
||
|
001010
|
||
|
000000
|
||
|
010010
|
||
|
010010
|
||
|
010010
|
||
|
010110
|
||
|
001010
|
||
|
000000
|
||
|
CHAR 253
|
||
|
011000
|
||
|
000100
|
||
|
001000
|
||
|
011100
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
CHAR 254
|
||
|
000000
|
||
|
000000
|
||
|
000000
|
||
|
011110
|
||
|
110010
|
||
|
110011
|
||
|
111110
|
||
|
001111
|
||
|
CHAR 255
|
||
|
010010
|
||
|
111111
|
||
|
010010
|
||
|
010010
|
||
|
111111
|
||
|
010010
|
||
|
000000
|
||
|
000000
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
</script>
|
||
|
|
||
|
<!-- include 3d hack with exported games -->
|
||
|
<script>
|
||
|
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("babylonjs",[],t):"object"==typeof exports?exports.babylonjs=t():e.BABYLON=t()}("undefined"!=typeof self?self:"undefined"!=typeof global?global:this,function(){return function(e){var t={};function i(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=129)}([function(e,t,i){"use strict";i.d(t,"u",function(){return s}),i.d(t,"v",function(){return a}),i.d(t,"h",function(){return c}),i.d(t,"e",function(){return l}),i.d(t,"f",function(){return u}),i.d(t,"w",function(){return h}),i.d(t,"x",function(){return d}),i.d(t,"y",function(){return f}),i.d(t,"r",function(){return p}),i.d(t,"q",function(){return _}),i.d(t,"j",function(){return g}),i.d(t,"n",function(){return m}),i.d(t,"z",function(){return v}),i.d(t,"i",function(){return y}),i.d(t,"s",function(){return n}),i.d(t,"c",function(){return T}),i.d(t,"d",function(){return E}),i.d(t,"k",function(){return b}),i.d(t,"a",function(){return A}),i.d(t,"b",function(){return x}),i.d(t,"l",function(){return R}),i.d(t,"m",function(){return P}),i.d(t,"g",function(){return S}),i.d(t,"p",function(){return C}),i.d(t,"o",function(){return M}),i.d(t,"t",function(){return O});var n,r=i(34),o=i(12),s=1/2.2,a=2.2,c=.001,l=function(){function e(e,t,i){void 0===e&&(e=0),void 0===t&&(t=0),void 0===i&&(i=0),this.r=e,this.g=t,this.b=i}return e.prototype.toString=function(){return"{R: "+this.r+" G:"+this.g+" B:"+this.b+"}"},e.prototype.getClassName=function(){return"Color3"},e.prototype.getHashCode=function(){var e=this.r||0;return e=397*(e=397*e^(this.g||0))^(this.b||0)},e.prototype.toArray=function(e,t){return void 0===t&&(t=0),e[t]=this.r,e[t+1]=this.g,e[t+2]=this.b,this},e.prototype.toColor4=function(e){return void 0===e&&(e=1),new u(this.r,this.g,this.b,e)},e.prototype.asArray=function(){var e=new Array;return this.toArray(e,0),e},e.prototype.toLuminance=function(){return.3*this.r+.59*this.g+.11*this.b},e.prototype.multiply=function(t){return new e(this.r*t.r,this.g*t.g,this.b*t.b)},e.prototype.multiplyToRef=function(e,t){return t.r=this.r*e.r,t.g=this.g*e.g,t.b=this.b*e.b,this},e.prototype.equals=function(e){return e&&this.r===e.r&&this.g===e.g&&this.b===e.b},e.prototype.equalsFloats=function(e,t,i){return this.r===e&&this.g===t&&this.b===i},e.prototype.scale=function(t){return new e(this.r*t,this.g*t,this.b*t)},e.prototype.scaleToRef=function(e,t){return t.r=this.r*e,t.g=this.g*e,t.b=this.b*e,this},e.prototype.scaleAndAddToRef=function(e,t){return t.r+=this.r*e,t.g+=this.g*e,t.b+=this.b*e,this},e.prototype.clampToRef=function(e,t,i){return void 0===e&&(e=0),void 0===t&&(t=1),i.r=o.a.Clamp(this.r,e,t),i.g=o.a.Clamp(this.g,e,t),i.b=o.a.Clamp(this.b,e,t),this},e.prototype.add=function(t){return new e(this.r+t.r,this.g+t.g,this.b+t.b)},e.prototype.addToRef=function(e,t){return t.r=this.r+e.r,t.g=this.g+e.g,t.b=this.b+e.b,this},e.prototype.subtract=function(t){return new e(this.r-t.r,this.g-t.g,this.b-t.b)},e.prototype.subtractToRef=function(e,t){return t.r=this.r-e.r,t.g=this.g-e.g,t.b=this.b-e.b,this},e.prototype.clone=function(){return new e(this.r,this.g,this.b)},e.prototype.copyFrom=function(e){return this.r=e.r,this.g=e.g,this.b=e.b,this},e.prototype.copy
|
||
|
/*! *****************************************************************************
|
||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||
|
this file except in compliance with the License. You may obtain a copy of the
|
||
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||
|
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||
|
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||
|
|
||
|
See the Apache Version 2.0 License for specific language governing permissions
|
||
|
and limitations under the License.
|
||
|
***************************************************************************** */
|
||
|
var n=function(e,t){return(n=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var i in t)t.hasOwnProperty(i)&&(e[i]=t[i])})(e,t)};function r(e,t){function i(){this.constructor=e}n(e,t),e.prototype=null===t?Object.create(t):(i.prototype=t.prototype,new i)}var o=function(){return(o=Object.assign||function(e){for(var t,i=1,n=arguments.length;i<n;i++)for(var r in t=arguments[i])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e}).apply(this,arguments)};function s(e,t,i,n){var r,o=arguments.length,s=o<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,i,n);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(s=(o<3?r(s):o>3?r(t,i,s):r(t,i))||s);return o>3&&s&&Object.defineProperty(t,i,s),s}function a(e,t,i,n){return new(i||(i=Promise))(function(r,o){function s(e){try{c(n.next(e))}catch(e){o(e)}}function a(e){try{c(n.throw(e))}catch(e){o(e)}}function c(e){e.done?r(e.value):new i(function(t){t(e.value)}).then(s,a)}c((n=n.apply(e,t||[])).next())})}function c(e,t){var i,n,r,o,s={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return o={next:a(0),throw:a(1),return:a(2)},"function"==typeof Symbol&&(o[Symbol.iterator]=function(){return this}),o;function a(o){return function(a){return function(o){if(i)throw new TypeError("Generator is already executing.");for(;s;)try{if(i=1,n&&(r=2&o[0]?n.return:o[0]?n.throw||((r=n.return)&&r.call(n),0):n.next)&&!(r=r.call(n,o[1])).done)return r;switch(n=0,r&&(o=[2&o[0],r.value]),o[0]){case 0:case 1:r=o;break;case 4:return s.label++,{value:o[1],done:!1};case 5:s.label++,n=o[1],o=[0];continue;case 7:o=s.ops.pop(),s.trys.pop();continue;default:if(!(r=(r=s.trys).length>0&&r[r.length-1])&&(6===o[0]||2===o[0])){s=0;continue}if(3===o[0]&&(!r||o[1]>r[0]&&o[1]<r[3])){s.label=o[1];break}if(6===o[0]&&s.label<r[1]){s.label=r[1],r=o;break}if(r&&s.label<r[2]){s.label=r[2],s.ops.push(o);break}r[2]&&s.ops.pop(),s.trys.pop();continue}o=t.call(e,s)}catch(e){o=[6,e],n=0}finally{i=r=0}if(5&o[0])throw o[1];return{value:o[0]?o[1]:void 0,done:!0}}([o,a])}}}},function(e,t,i){"use strict";i.d(t,"b",function(){return h}),i.d(t,"c",function(){return d}),i.d(t,"m",function(){return f}),i.d(t,"e",function(){return p}),i.d(t,"h",function(){return _}),i.d(t,"n",function(){return g}),i.d(t,"o",function(){return m}),i.d(t,"k",function(){return v}),i.d(t,"g",function(){return y}),i.d(t,"f",function(){return b}),i.d(t,"i",function(){return T}),i.d(t,"l",function(){return E}),i.d(t,"j",function(){return A}),i.d(t,"d",function(){return x}),i.d(t,"a",function(){return R});var n=i(29),r=i(0),o=i(19),s={},a={},c=function(e,t,i){var r=e();n.a&&n.a.AddTagsTo(r,t.tags);var o=l(r);for(var s in o){var a=o[s],c=t[s],u=a.type;if(null!=c&&"uniqueId"!==s)switch(u){case 0:case 6:case 11:r[s]=c;break;case 1:r[s]=i||c.isRenderTarget?c:c.clone();break;case 2:case 3:case 4:case 5:case 7:case 10:case 12:r[s]=i?c:c.clone()}}return r};function l(e){var t=e.getClassName();if(a[t])return a[t];a[t]={};for(var i=a[t],n=e,r=t;r;){var o=s[r];for(var c in o)i[c]=o[c];var l=void 0,u=!1;do{if(!(l=Object.getPrototypeOf(n)).getClassName){u=!0;break}if(l.getClassName()!==r)break;n=l}while(l);if(u)break;r=l.getClassName(),n=l}return i}function u(e,t){return function(i,n){var r=function(e){var t=e.getClassName();return s[t]||(s[t]={}),s[t]}(i);r[n]||(r[n]={type:e,sourceName:t})}}function h(e,t){return void 0===t&&(t=null),function(e,t){return void 0===t&&(t=null),function(i,n){var r=t||"_"+n;Object.defineProperty(i,n,{get:function(){return this[r]},set:function(t){this[r]!==t&&(this[r]=t,i[e].apply(this))},enumerable:!0,configurable:!0})}}(e,t)}function d(e){return u(0,e)}function f(e){return u(1,e)}function p(e){return u(2,e)}function _(e){return u(3,e)}function g(e){return u(4,e)}function m(e){return u(5,e)}function v(e){return u(6,e)}function y(e){return u(7,e)}function b(e){return u(8,e)}function T(e){return u(9,e)}function E(e){return u(10,e)}function A(e){return u(12,e)}function x(e){retu
|
||
|
</script>
|
||
|
|
||
|
<script>
|
||
|
var bitsy = window;
|
||
|
|
||
|
var b3d = {
|
||
|
defaultSettings: {
|
||
|
engineSize: '512x512',
|
||
|
canvasSize: 'auto',
|
||
|
|
||
|
clearColor: 0,
|
||
|
|
||
|
enableFog: false,
|
||
|
fogColor: 0,
|
||
|
fogStart: 5,
|
||
|
fogEnd: 20,
|
||
|
|
||
|
// todo: dialog position
|
||
|
positionDialogBoxAtTheTop: false,
|
||
|
|
||
|
tweenDistance: 1.5,
|
||
|
tweenDuration: 150,
|
||
|
tweenFunction: 'linear',
|
||
|
|
||
|
movementHoldInterval: 150,
|
||
|
movementSecondStepInterval: 150,
|
||
|
},
|
||
|
|
||
|
mainCamera: null,
|
||
|
curActiveCamera: null,
|
||
|
curCameraPreset: null,
|
||
|
|
||
|
engine: null,
|
||
|
scene: null,
|
||
|
|
||
|
meshTemplates: {},
|
||
|
baseMat: null,
|
||
|
|
||
|
meshConfig: {},
|
||
|
roomsInStack: {},
|
||
|
stackPosOfRoom: {},
|
||
|
|
||
|
curStack: null,
|
||
|
lastStack: null,
|
||
|
lastRoom: null,
|
||
|
|
||
|
sprites: {},
|
||
|
items: {},
|
||
|
tiles: {},
|
||
|
|
||
|
caches: {},
|
||
|
animatedMaterials: {},
|
||
|
didUpdateAnimations: false,
|
||
|
|
||
|
avatarRef: null,
|
||
|
avatarNode: null,
|
||
|
|
||
|
sceneCanvas: null,
|
||
|
textCanvas: null,
|
||
|
textContext: null,
|
||
|
|
||
|
spriteLastPos: {},
|
||
|
tweens: {},
|
||
|
|
||
|
dialogDirty: false,
|
||
|
rawDirection: bitsy.Direction.None,
|
||
|
|
||
|
isPointerLocked: false,
|
||
|
|
||
|
defaultCameraPreset: 'fixed target orbiter',
|
||
|
};
|
||
|
|
||
|
b3d.tweenFunctions = {
|
||
|
'linear': function (t) {
|
||
|
return t;
|
||
|
},
|
||
|
'quadratic': function (t) {
|
||
|
t = 1 - ((1 - t) ** 2);
|
||
|
return t;
|
||
|
},
|
||
|
};
|
||
|
|
||
|
b3d.cameraPresets = {
|
||
|
'orbiting follower': {
|
||
|
type: 'arc',
|
||
|
fov: 0.9,
|
||
|
inertia: 0.7,
|
||
|
target: {x: 7.5, z: 7.5, y: 3},
|
||
|
alpha: -Math.PI/2,
|
||
|
beta: Math.PI/3,
|
||
|
radius: 6,
|
||
|
lowerRadiusLimit: 6,
|
||
|
upperRadiusLimit: 6,
|
||
|
upperBetaLimit: Math.PI / 2,
|
||
|
attachControl: true,
|
||
|
followAvatar: true,
|
||
|
lockPointer: true,
|
||
|
},
|
||
|
'fixed target orbiter': {
|
||
|
type: 'arc',
|
||
|
fov: 0.9,
|
||
|
inertia: 0.7,
|
||
|
target: {x: 7.5, z: 7.5, y: 1.5},
|
||
|
alpha: -Math.PI/2,
|
||
|
beta: Math.PI/3,
|
||
|
radius: 20,
|
||
|
lowerRadiusLimit: 20,
|
||
|
upperRadiusLimit: 20,
|
||
|
upperBetaLimit: Math.PI / 2,
|
||
|
attachControl: true,
|
||
|
},
|
||
|
'fixed position rotating follower': {
|
||
|
type: 'universal',
|
||
|
position: {x: -1, z: 0, y: 3},
|
||
|
followAvatar: true,
|
||
|
},
|
||
|
'free first person': {
|
||
|
type: 'arc',
|
||
|
fov: 1,
|
||
|
inertia: 0.6,
|
||
|
alpha: -Math.PI/2,
|
||
|
beta: Math.PI/2,
|
||
|
radius: 0.5,
|
||
|
lowerRadiusLimit: 0.5,
|
||
|
upperRadiusLimit: 0.5,
|
||
|
upperBetaLimit: 0.75 * Math.PI,
|
||
|
lowerBetaLimit: 0.1 * Math.PI,
|
||
|
minZ: 0.001,
|
||
|
maxZ: 100,
|
||
|
attachControl: true,
|
||
|
followAvatar: true,
|
||
|
lockPointer: true,
|
||
|
},
|
||
|
'dungeon crawler': {
|
||
|
type: 'arc',
|
||
|
fov: 1,
|
||
|
inertia: 0.6,
|
||
|
alpha: -Math.PI/2,
|
||
|
beta: Math.PI/2,
|
||
|
radius: 0.5,
|
||
|
lowerRadiusLimit: 0.5,
|
||
|
upperRadiusLimit: 0.5,
|
||
|
upperBetaLimit: 0.75 * Math.PI,
|
||
|
lowerBetaLimit: 0.1 * Math.PI,
|
||
|
minZ: 0.001,
|
||
|
maxZ: 100,
|
||
|
attachControl: false,
|
||
|
followAvatar: true,
|
||
|
lockPointer: false,
|
||
|
useLeftAndRightToRotateByAngle: 0.5 * Math.PI,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
b3d.cameraDataModel = {
|
||
|
commonProperties: {
|
||
|
value: {
|
||
|
// mode can be either 'perspective' or 'orthographic'
|
||
|
mode: 'perspective',
|
||
|
orthoSize: 16,
|
||
|
fov: 0.9,
|
||
|
minZ: 0.001,
|
||
|
maxZ: 100,
|
||
|
},
|
||
|
trait: { followAvatar: false, lockPointer: false },
|
||
|
},
|
||
|
cameraTypes: {
|
||
|
arc: {
|
||
|
class: BABYLON.ArcRotateCamera,
|
||
|
value: {
|
||
|
inertia: 0.8,
|
||
|
alpha: -Math.PI/2,
|
||
|
beta: Math.PI/2,
|
||
|
radius: 10,
|
||
|
lowerRadiusLimit: 1,
|
||
|
upperRadiusLimit: 30,
|
||
|
wheelPrecision: 3,
|
||
|
upperBetaLimit: Math.PI/2,
|
||
|
lowerBetaLimit: 0,
|
||
|
rotationTweenTime: 250,
|
||
|
rotationTweenFunction: 'linear',
|
||
|
},
|
||
|
vector3: { target: {x: 7.5, z: 7.5, y: 0} },
|
||
|
trait: {
|
||
|
attachControl: false,
|
||
|
useArrowKeysToControlCameraInsteadOfAvatar: false,
|
||
|
useLeftAndRightToRotateByAngle: 0
|
||
|
},
|
||
|
},
|
||
|
universal: {
|
||
|
class: BABYLON.UniversalCamera,
|
||
|
vector3: {
|
||
|
position: {x: 0, z: 0, y: 0},
|
||
|
rotation: {x: 0, z: 0, y: 0}
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
controllableProperties: ['target', 'alpha', 'beta', 'radius'],
|
||
|
traitEffects: {
|
||
|
// to be used inside camera trait setters
|
||
|
// 'this' should refer to camera object
|
||
|
// trait effects will be applied every time the camera is activated or deactivated
|
||
|
attachControl: function (v) {
|
||
|
if (v === true) {
|
||
|
this.ref.attachControl(b3d.sceneCanvas);
|
||
|
// update camera controls
|
||
|
if (this.hasOwnProperty('useArrowKeysToControlCameraInsteadOfAvatar')) {
|
||
|
this.useArrowKeysToControlCameraInsteadOfAvatar = this.useArrowKeysToControlCameraInsteadOfAvatar;
|
||
|
}
|
||
|
} else if (v === false) {
|
||
|
this.ref.detachControl(b3d.sceneCanvas);
|
||
|
}
|
||
|
},
|
||
|
followAvatar: function (v) {
|
||
|
if (v === true) {
|
||
|
this.ref.lockedTarget = b3d.avatarNode;
|
||
|
} else if (v === false) {
|
||
|
this.ref.lockedTarget = null;
|
||
|
}
|
||
|
},
|
||
|
lockPointer: function (v) {
|
||
|
if (v === true) {
|
||
|
b3d.sceneCanvas.addEventListener("click", b3d.lockPointer);
|
||
|
} else if (v === false) {
|
||
|
b3d.sceneCanvas.removeEventListener("click", b3d.lockPointer);
|
||
|
}
|
||
|
},
|
||
|
useArrowKeysToControlCameraInsteadOfAvatar: function (v) {
|
||
|
if (v === true) {
|
||
|
if (this.ref.inputs.attached.keyboard) {
|
||
|
this.ref.inputs.attached.keyboard.keysLeft = [37];
|
||
|
this.ref.inputs.attached.keyboard.keysUp = [38];
|
||
|
this.ref.inputs.attached.keyboard.keysRight = [39];
|
||
|
this.ref.inputs.attached.keyboard.keysDown = [40];
|
||
|
}
|
||
|
|
||
|
['left', 'up', 'right', 'down'].forEach(function (k) {
|
||
|
bitsy.key[k] = null;
|
||
|
});
|
||
|
} else if (v === false) {
|
||
|
var cam = this;
|
||
|
if (cam.ref.inputs.attached.keyboard) {
|
||
|
['keysLeft', 'keysUp', 'keysRight', 'keysDown'].forEach(function (k) {
|
||
|
cam.ref.inputs.attached.keyboard[k] = [];
|
||
|
});
|
||
|
}
|
||
|
|
||
|
bitsy.key.left = 37;
|
||
|
bitsy.key.up = 38;
|
||
|
bitsy.key.right = 39;
|
||
|
bitsy.key.down = 40;
|
||
|
}
|
||
|
},
|
||
|
useLeftAndRightToRotateByAngle: function (v) {
|
||
|
if (!this.hasOwnProperty('rotationState')) {
|
||
|
Object.defineProperty(this, 'rotationState', { value: {}});
|
||
|
}
|
||
|
if (v === 0 || v === false) {
|
||
|
// turn it off and return
|
||
|
if (this.rotationState.movePlayerOriginal) {
|
||
|
// restore the original bitsy function
|
||
|
bitsy.movePlayer = this.rotationState.movePlayerOriginal;
|
||
|
}
|
||
|
if (this.rotationState.cameraUpdateOriginal) {
|
||
|
this.ref.update = this.rotationState.cameraUpdateOriginal;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
if (!this.rotationState.movePlayerOriginal || !this.rotationState.cameraUpdateOriginal) {
|
||
|
this.rotationState.movePlayerOriginal = bitsy.movePlayer;
|
||
|
var thisCamera = this;
|
||
|
b3d.patch(bitsy, 'movePlayer', function () {
|
||
|
if (thisCamera.rotationState.isTweening) {
|
||
|
// prevent any movement by resetting bitsy direction when camera is rotating
|
||
|
bitsy.curPlayerDirection = bitsy.Direction.None;
|
||
|
} else if (bitsy.curPlayerDirection === bitsy.Direction.Left || bitsy.curPlayerDirection === bitsy.Direction.Right) {
|
||
|
// if it isn't, check if it should start rotating
|
||
|
thisCamera.rotationState.isTweening = true;
|
||
|
var dir = bitsy.curPlayerDirection === bitsy.Direction.Left ? 1 : -1;
|
||
|
thisCamera.rotationState.tweenStartingRotation = thisCamera.ref.alpha;
|
||
|
thisCamera.rotationState.tweenStartingTime = bitsy.prevTime;
|
||
|
thisCamera.rotationState.tweenRotationAmount = dir * thisCamera.useLeftAndRightToRotateByAngle;
|
||
|
bitsy.curPlayerDirection = bitsy.Direction.None;
|
||
|
}
|
||
|
});
|
||
|
// tween camera rotation
|
||
|
b3d.patch(thisCamera.ref, 'update', null, function () {
|
||
|
var rotationState = thisCamera.rotationState;
|
||
|
var tweenFunction = b3d.tweenFunctions[thisCamera.rotationTweenFunction] || b3d.tweenFunctions['linear'];
|
||
|
var tweenPercent = Math.min(tweenFunction(((bitsy.prevTime - rotationState.tweenStartingTime) / thisCamera.rotationTweenTime)), 1);
|
||
|
if (rotationState.isTweening) {
|
||
|
var tweenPercent = Math.min(tweenFunction(((bitsy.prevTime - rotationState.tweenStartingTime) / thisCamera.rotationTweenTime)), 1);
|
||
|
thisCamera.ref.alpha = rotationState.tweenStartingRotation + (rotationState.tweenRotationAmount * tweenPercent);
|
||
|
if (tweenPercent === 1) rotationState.isTweening = false;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
b3d.lockPointer = function () {
|
||
|
b3d.sceneCanvas.requestPointerLock = b3d.sceneCanvas.requestPointerLock || b3d.sceneCanvas.msRequestPointerLock || b3d.sceneCanvas.mozRequestPointerLock || b3d.sceneCanvas.webkitRequestPointerLock;
|
||
|
if (b3d.sceneCanvas.requestPointerLock) {
|
||
|
b3d.sceneCanvas.requestPointerLock();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
b3d.parseSize = function (sizeStr) {
|
||
|
if (!sizeStr) return;
|
||
|
var match;
|
||
|
var parsed;
|
||
|
if (match = sizeStr.match(/^auto/)) {
|
||
|
parsed = { type: 'auto' };
|
||
|
} else if (match = sizeStr.match(/^(\d+)x(\d+)/)) {
|
||
|
parsed = { type: 'fixed', width: match[1], height: match[2] };
|
||
|
} else if (match = sizeStr.match(/^(\d+):(\d+)/)) {
|
||
|
parsed = { type: 'ratio', width: match[1], height: match[2] };
|
||
|
} else if (match = sizeStr.match(/^\d+/)) {
|
||
|
parsed = { type: 'factor', value: match[0] };
|
||
|
} else {
|
||
|
console.error(`invalid size option: ${sizeStr}`);
|
||
|
parsed = { type: 'invalid' };
|
||
|
}
|
||
|
// include serialized version
|
||
|
parsed.serialized = sizeStr;
|
||
|
return parsed;
|
||
|
};
|
||
|
|
||
|
b3d.applyEngineAndCanvasSize = function (engineSizeArg, canvasSizeArg) {
|
||
|
// only apply them in exported game: editor canvas should have fixed styling and resolution
|
||
|
if (bitsy.isPlayerEmbeddedInEditor) {
|
||
|
b3d.engine.resize();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var engineSize = b3d.parseSize(engineSizeArg) || b3d.parseSize(b3d.settings.engineSize);
|
||
|
var canvasSize = b3d.parseSize(canvasSizeArg) || b3d.parseSize(b3d.settings.canvasSize);
|
||
|
|
||
|
// todo: implement 'factor' size for engine and 'ratio' size for canvas
|
||
|
// for now only accept 'fixed' and 'auto' as valid types for both engine and canvas
|
||
|
if (!engineSize || ['fixed', 'auto'].indexOf(engineSize.type) === -1) {
|
||
|
console.warn(`engine size "${engineSize.serialized}" is invalid. resetting to auto`);
|
||
|
engineSize = b3d.parseSize('auto');
|
||
|
}
|
||
|
if (!canvasSize || ['fixed', 'auto'].indexOf(canvasSize.type) === -1) {
|
||
|
console.warn(`canvas size "${canvasSize.serialized}" is invalid. resetting to auto`);
|
||
|
canvasSize = b3d.parseSize('auto');
|
||
|
}
|
||
|
|
||
|
// set engine and canvas size in the settings for consistency
|
||
|
b3d.settings.engineSize = engineSize.serialized;
|
||
|
b3d.settings.canvasSize = canvasSize.serialized;
|
||
|
|
||
|
switch (canvasSize.type) {
|
||
|
case 'fixed':
|
||
|
b3d.sceneCanvas.style.width = canvasSize.width + 'px';
|
||
|
b3d.sceneCanvas.style.height = canvasSize.height + 'px';
|
||
|
b3d.sceneCanvas.style.maxHeight = 'initial';
|
||
|
b3d.sceneCanvas.style.maxWidth = 'initial';
|
||
|
break;
|
||
|
case 'auto':
|
||
|
if (engineSize.type === 'fixed') {
|
||
|
if (parseInt(engineSize.width) >= parseInt(engineSize.height)) {
|
||
|
b3d.sceneCanvas.style.width = '100vw';
|
||
|
b3d.sceneCanvas.style.height = 'initial';
|
||
|
b3d.sceneCanvas.style.maxHeight = '100vh';
|
||
|
} else {
|
||
|
b3d.sceneCanvas.style.height = '100vh';
|
||
|
b3d.sceneCanvas.style.width = 'initial';
|
||
|
b3d.sceneCanvas.style.maxWidth = '100vw';
|
||
|
}
|
||
|
} else {
|
||
|
b3d.sceneCanvas.style.width = '100vw';
|
||
|
b3d.sceneCanvas.style.height = '100vh';
|
||
|
}
|
||
|
break;
|
||
|
case 'ratio':
|
||
|
if (engineSize.type === 'fixed') {
|
||
|
console.warning('canvas size can only be set as aspect ratio when engine size is not fixed');
|
||
|
b3d.applyEngineAndCanvasSize(engineSizeArg, 'auto');
|
||
|
return;
|
||
|
} else {
|
||
|
// todo: implement setting canvas dimensions as aspect ratio
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (engineSize.type) {
|
||
|
case 'fixed':
|
||
|
b3d.engine.setSize(parseInt(engineSize.width), parseInt(engineSize.height));
|
||
|
break;
|
||
|
case 'auto':
|
||
|
b3d.engine.resize();
|
||
|
break;
|
||
|
case 'factor':
|
||
|
// todo: impelement setting engine resolution as a screen resolution with the downscale factor
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// make sure orthographic camera preserves aspect ratio correctly
|
||
|
if (b3d.mainCamera) b3d.mainCamera.recalculateOrthoBounds();
|
||
|
};
|
||
|
|
||
|
document.addEventListener('DOMContentLoaded', function() {
|
||
|
// patch bitsy with bitsy 3d functions
|
||
|
// ensure compatibilty with hacks in exported game by using kitsy when it's included
|
||
|
if (bitsy.EditMode === undefined) {
|
||
|
smartPatch('startExportedGame', null, function () {
|
||
|
b3d.init();
|
||
|
});
|
||
|
smartPatch('update', null, function () {
|
||
|
b3d.update();
|
||
|
b3d.render();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var py;
|
||
|
smartPatch('dialogRenderer.DrawTextbox',
|
||
|
function () {
|
||
|
py = bitsy.player().y;
|
||
|
bitsy.player().y = b3d.settings.positionDialogBoxAtTheTop ? bitsy.mapsize : 0;
|
||
|
}, function () {
|
||
|
bitsy.player().y = py;
|
||
|
});
|
||
|
|
||
|
smartPatch('updateAnimation', null, function () {
|
||
|
if (bitsy.animationCounter === 0) {
|
||
|
Object.values(b3d.animatedMaterials).forEach(function (entry) {
|
||
|
var drawing = entry[0];
|
||
|
var mat = entry[1];
|
||
|
if (drawing.animation.isAnimated) {
|
||
|
mat.diffuseTexture.uOffset = drawing.animation.frameIndex / drawing.animation.frameCount;
|
||
|
// unfreeze material to pass updated values to the shader when rendering this frame
|
||
|
mat.unfreeze();
|
||
|
}
|
||
|
});
|
||
|
// keep track of whether we updated animations, to freeze materials after rendering this frame
|
||
|
b3d.didUpdateAnimations = true;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// adjust movement direction relative to the camera
|
||
|
smartPatch('movePlayer',
|
||
|
function () {
|
||
|
var rotationTable = {};
|
||
|
rotationTable[bitsy.Direction.Up] = bitsy.Direction.Left;
|
||
|
rotationTable[bitsy.Direction.Left] = bitsy.Direction.Down;
|
||
|
rotationTable[bitsy.Direction.Down] = bitsy.Direction.Right;
|
||
|
rotationTable[bitsy.Direction.Right] = bitsy.Direction.Up;
|
||
|
rotationTable[bitsy.Direction.None] = bitsy.Direction.None;
|
||
|
|
||
|
b3d.rawDirection = bitsy.curPlayerDirection;
|
||
|
|
||
|
var rotatedDirection = bitsy.curPlayerDirection;
|
||
|
var ray = b3d.curActiveCamera.ref.getForwardRay().direction;
|
||
|
var ray2 = new BABYLON.Vector2(ray.x, ray.z);
|
||
|
ray2.normalize();
|
||
|
var a = (Math.atan2(ray2.y, ray2.x) / Math.PI + 1) * 2 + 0.5;
|
||
|
if (a < 0) {
|
||
|
a += 4;
|
||
|
}
|
||
|
for (var i = 0; i < a; ++i) {
|
||
|
rotatedDirection = rotationTable[rotatedDirection];
|
||
|
}
|
||
|
bitsy.curPlayerDirection = rotatedDirection;
|
||
|
},
|
||
|
function () {
|
||
|
bitsy.curPlayerDirection = b3d.rawDirection;
|
||
|
});
|
||
|
|
||
|
smartPatch('reset_cur_game', null, b3d.reInit3dData);
|
||
|
|
||
|
function tryAddingToKitsyQueue(key, kind, func) {
|
||
|
if (window.kitsy) {
|
||
|
var queue;
|
||
|
if (kind === 'before') {
|
||
|
queue = window.kitsy.queuedBeforeScripts;
|
||
|
} else if (kind === 'after') {
|
||
|
queue = window.kitsy.queuedAfterScripts;
|
||
|
}
|
||
|
if (queue) {
|
||
|
queue[key] = queue[key] || [];
|
||
|
queue[key].push(func);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function smartPatch (key, before, after) {
|
||
|
var patchScope = key.split('.').length > 1 ? bitsy[key.split('.')[0]] : bitsy;
|
||
|
var patchName = key.split('.').length > 1 ? key.split('.')[1] : key;
|
||
|
if (before) tryAddingToKitsyQueue(key, 'before', before) || b3d.patch(patchScope, patchName, before, null);
|
||
|
if (after) tryAddingToKitsyQueue(key, 'after', after) || b3d.patch(patchScope, patchName, null, after);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// helper function to patch functions
|
||
|
b3d.patch = function (scope, name, before, after) {
|
||
|
var original = scope[name];
|
||
|
var patched = function () {
|
||
|
if (before) before.apply(scope, arguments);
|
||
|
var output = original.apply(scope, arguments);
|
||
|
if (after) after.apply(scope, arguments);
|
||
|
return output;
|
||
|
}
|
||
|
scope[name] = patched;
|
||
|
};
|
||
|
|
||
|
b3d.init = function () {
|
||
|
if (bitsy.isPlayerEmbeddedInEditor) {
|
||
|
b3d.sceneCanvas = document.getElementById('sceneCanvas');
|
||
|
b3d.textCanvas = document.getElementById('textCanvas');
|
||
|
} else {
|
||
|
// if not in the editor, do the setup specific for exported game
|
||
|
// hide the original canvas and add a stylesheet
|
||
|
// to make the 3D render in its place
|
||
|
bitsy.canvas.parentElement.removeChild(bitsy.canvas);
|
||
|
var style = `
|
||
|
canvas {
|
||
|
-ms-interpolation-mode: nearest-neighbor;
|
||
|
image-rendering: -moz-crisp-edges;
|
||
|
image-rendering: pixelated;
|
||
|
}
|
||
|
canvas:focus {
|
||
|
outline: none;
|
||
|
}
|
||
|
#gameContainer {
|
||
|
position: absolute;
|
||
|
display: inline-grid; /*to prevent it from growing a few pixels taller than sceneCanvas*/
|
||
|
top: 50%;
|
||
|
left: 50%;
|
||
|
transform: translate(-50%, -50%);
|
||
|
}
|
||
|
#sceneCanvas {
|
||
|
position: static;
|
||
|
object-fit: contain;
|
||
|
width: 100vw;
|
||
|
max-height: 100vh;
|
||
|
}
|
||
|
#textCanvas {
|
||
|
position: absolute;
|
||
|
object-fit: contain;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
width: 100%;
|
||
|
height: 100%;
|
||
|
background: none;
|
||
|
pointer-events: none;
|
||
|
}`;
|
||
|
var sheet = document.createElement('style');
|
||
|
sheet.textContent = style;
|
||
|
document.head.appendChild(sheet);
|
||
|
|
||
|
var gameContainer = document.createElement('div');
|
||
|
gameContainer.id = 'gameContainer';
|
||
|
document.body.appendChild(gameContainer);
|
||
|
|
||
|
b3d.sceneCanvas = document.createElement('canvas');
|
||
|
b3d.sceneCanvas.id = 'sceneCanvas';
|
||
|
gameContainer.appendChild(b3d.sceneCanvas);
|
||
|
|
||
|
b3d.textCanvas = document.createElement('canvas');
|
||
|
b3d.textCanvas.id = 'textCanvas';
|
||
|
gameContainer.appendChild(b3d.textCanvas);
|
||
|
b3d.textContext = b3d.textCanvas.getContext('2d');
|
||
|
}
|
||
|
|
||
|
b3d.engine = new BABYLON.Engine(b3d.sceneCanvas, false);
|
||
|
b3d.scene = new BABYLON.Scene(b3d.engine);
|
||
|
b3d.scene.ambientColor = new BABYLON.Color3(1, 1, 1);
|
||
|
b3d.scene.freezeActiveMeshes();
|
||
|
|
||
|
// optimization: this gives noticeable boost in very large scenes
|
||
|
b3d.scene.blockMaterialDirtyMechanism = true;
|
||
|
|
||
|
// set up text canvas
|
||
|
b3d.textCanvas.width = bitsy.canvas.width;
|
||
|
b3d.textCanvas.height = bitsy.canvas.height;
|
||
|
b3d.textContext = b3d.textCanvas.getContext('2d');
|
||
|
bitsy.dialogRenderer.AttachContext(b3d.textContext);
|
||
|
|
||
|
// create basic resources
|
||
|
b3d.meshTemplates = b3d.initMeshTemplates();
|
||
|
|
||
|
// material
|
||
|
b3d.baseMat = new BABYLON.StandardMaterial('base material', b3d.scene);
|
||
|
b3d.baseMat.ambientColor = new BABYLON.Color3(1, 1, 1);
|
||
|
b3d.baseMat.maxSimultaneousLights = 0;
|
||
|
b3d.baseMat.freeze();
|
||
|
|
||
|
// create transform node that will copy avatar's position
|
||
|
// prevents crashes when used as a camera target when avatar mesh is a billboard
|
||
|
b3d.avatarNode = new BABYLON.TransformNode('avatarNode');
|
||
|
|
||
|
// initialize the following objects by parsing serialized data:
|
||
|
// * b3d.meshConfig
|
||
|
// * b3d.roomsInStack
|
||
|
// * b3d.stackPosOfRoom
|
||
|
// * b3d.camera
|
||
|
// * b3d.settings
|
||
|
b3d.parseData();
|
||
|
|
||
|
// watch for browser/canvas resize events
|
||
|
window.addEventListener("resize", function () {
|
||
|
if (b3d.settings.engineSize === 'auto' || b3d.settings.canvasSize === 'auto') {
|
||
|
b3d.applyEngineAndCanvasSize();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// watch for locking/unlocking the pointer
|
||
|
document.addEventListener('pointerlockchange', function () {
|
||
|
if (document.pointerLockElement || document.mozPointerLockElement) {
|
||
|
b3d.isPointerLocked = true;
|
||
|
} else {
|
||
|
b3d.isPointerLocked = false;
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// return true if data was parsed successfully and false if it was initiazlied with default values
|
||
|
b3d.parseDataFromDialog = function () {
|
||
|
var serialized = bitsy.dialog['DATA3D'] && bitsy.dialog['DATA3D'].src;
|
||
|
var parsed;
|
||
|
if (serialized) {
|
||
|
// remove bitsy multiline dialog tokens if there are any
|
||
|
serialized = serialized.replace('"""\n', '');
|
||
|
serialized = serialized.replace('\n"""', '');
|
||
|
var parsed = JSON.parse(serialized);
|
||
|
}
|
||
|
|
||
|
// parse mesh config
|
||
|
// b3d.meshConfig should contain configuration for every drawing
|
||
|
[].concat(Object.values(bitsy.tile), Object.values(bitsy.sprite), Object.values(bitsy.item)).forEach(function (drawing) {
|
||
|
var parsedConfig = parsed && parsed.mesh[drawing.drw] || {};
|
||
|
b3d.meshConfig[drawing.drw] = b3d.parseMesh(drawing, parsedConfig);
|
||
|
});
|
||
|
|
||
|
// parse stacks
|
||
|
if (parsed && parsed.stack) {
|
||
|
Object.entries(parsed.stack).forEach(function (entry) {
|
||
|
var stackId = entry[0];
|
||
|
var roomList = entry[1];
|
||
|
roomList.forEach(function (room) {
|
||
|
b3d.registerRoomInStack(room.id, stackId, room.pos);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
b3d.settings = JSON.parse(JSON.stringify(b3d.defaultSettings));
|
||
|
if (parsed && parsed.settings) {
|
||
|
Object.keys(b3d.defaultSettings).forEach(function (key) {
|
||
|
if (parsed.settings[key] !== null && parsed.settings[key] !== undefined) {
|
||
|
b3d.settings[key] = parsed.settings[key];
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
b3d.applySettings();
|
||
|
|
||
|
// load camera from serialized data or create a default camera
|
||
|
// camera can be either a string specifying a preset or an object with custom camera configuration
|
||
|
if (parsed && parsed.camera) {
|
||
|
if (typeof parsed.camera === 'string') {
|
||
|
b3d.curCameraPreset = b3d.cameraPresets[parsed.camera] ? parsed.camera : b3d.defaultCameraPreset;
|
||
|
b3d.mainCamera = b3d.createCamera(b3d.cameraPresets[b3d.curCameraPreset]);
|
||
|
} else if (typeof parsed.camera === 'object') {
|
||
|
b3d.curCameraPreset = null;
|
||
|
b3d.mainCamera = b3d.createCamera(parsed.camera);
|
||
|
}
|
||
|
} else {
|
||
|
b3d.curCameraPreset = b3d.defaultCameraPreset;
|
||
|
b3d.mainCamera = b3d.createCamera(b3d.cameraPresets[b3d.defaultCameraPreset]);
|
||
|
}
|
||
|
b3d.mainCamera.activate();
|
||
|
|
||
|
return Boolean(serialized);
|
||
|
}; // b3d.parseDataFromDialog ()
|
||
|
|
||
|
b3d.parseData = b3d.parseDataFromDialog;
|
||
|
|
||
|
b3d.reInit3dData = function () {
|
||
|
// clear all caches to force all drawings to reset during the update
|
||
|
b3d.clearCaches(Object.values(b3d.caches));
|
||
|
|
||
|
// since there is no way to tell what exactly was changed, reset everything
|
||
|
// reset stack objects
|
||
|
b3d.roomsInStack = {};
|
||
|
b3d.stackPosOfRoom = {};
|
||
|
b3d.meshConfig = {};
|
||
|
|
||
|
// delete camera
|
||
|
b3d.mainCamera.deactivate();
|
||
|
b3d.mainCamera.ref.dispose();
|
||
|
b3d.mainCamera = null;
|
||
|
|
||
|
// reload data
|
||
|
b3d.parseData();
|
||
|
};
|
||
|
|
||
|
// all objects will have drawing, type, transparency, hidden and alpha set by b3d.getDefaultMeshProps,
|
||
|
// and other properties are optional
|
||
|
b3d.parseMesh = function (drawing, parsedConfig) {
|
||
|
var config = b3d.getDefaultMeshProps(drawing);
|
||
|
config.type = parsedConfig.type || config.type;
|
||
|
config.transparency = parsedConfig.hasOwnProperty('transparency') ? parsedConfig.transparency : config.transparency;
|
||
|
config.transform = parsedConfig.transform && b3d.transformFromArray(parsedConfig.transform.split(','));
|
||
|
config.replacement = parsedConfig.replacement && b3d.getDrawingFromDrw(parsedConfig.replacement);
|
||
|
config.hidden = parsedConfig.hasOwnProperty('hidden') ? parsedConfig.hidden : config.hidden;
|
||
|
config.alpha = parsedConfig.hasOwnProperty('alpha') ? parsedConfig.alpha : config.alpha;
|
||
|
if (parsedConfig.children && parsedConfig.children.length > 0) {
|
||
|
config.children = [];
|
||
|
parsedConfig.children.forEach(function (c) {
|
||
|
var childDrw;
|
||
|
var childConfig;
|
||
|
if (typeof c === 'object' && c.drw) {
|
||
|
childDrw = c.drw;
|
||
|
childConfig = b3d.parseMesh(b3d.getDrawingFromDrw(childDrw), c);
|
||
|
} else if (typeof c === 'string') {
|
||
|
childDrw = c;
|
||
|
childConfig = b3d.parseMesh(b3d.getDrawingFromDrw(childDrw), {});
|
||
|
}
|
||
|
if (childConfig) {
|
||
|
config.children.push(childConfig);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return config;
|
||
|
};
|
||
|
|
||
|
b3d.applySettings = function () {
|
||
|
bitsy.playerHoldToMoveInterval = b3d.settings.movementHoldInterval;
|
||
|
bitsy.playerSecondStepInterval = b3d.settings.movementSecondStepInterval;
|
||
|
|
||
|
b3d.applyEngineAndCanvasSize();
|
||
|
|
||
|
// apply fog settings
|
||
|
b3d.scene.fogStart = b3d.settings.fogStart;
|
||
|
b3d.scene.fogEnd = b3d.settings.fogEnd;
|
||
|
b3d.scene.fogMode = b3d.settings.enableFog ? BABYLON.Scene.FOGMODE_LINEAR : BABYLON.Scene.FOGMODE_NONE;
|
||
|
};
|
||
|
|
||
|
// create a camera from serialized data
|
||
|
b3d.createCamera = function (camData) {
|
||
|
if (!camData) {
|
||
|
return;
|
||
|
} else if (!camData.type) {
|
||
|
console.error("couldn't create camera: camera type wasn't specified");
|
||
|
return;
|
||
|
} else if (!b3d.cameraDataModel.cameraTypes[camData.type]) {
|
||
|
console.error(`couldn't create camera: camera type '${camData.type}' isn't supported"`);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var camera = {};
|
||
|
|
||
|
// define read-only camera type
|
||
|
Object.defineProperty(camera, 'type', {
|
||
|
configurable: false,
|
||
|
enumerable: true,
|
||
|
writable: false,
|
||
|
value: camData.type,
|
||
|
});
|
||
|
|
||
|
// camera.ref will hold a reference to babylonjs camera
|
||
|
Object.defineProperty(camera, 'ref', {
|
||
|
configurable: false,
|
||
|
enumerable: false,
|
||
|
writable: false,
|
||
|
value: new b3d.cameraDataModel.cameraTypes[camData.type].class(),
|
||
|
});
|
||
|
|
||
|
// set up value properties
|
||
|
[].concat(
|
||
|
Object.entries(b3d.cameraDataModel.commonProperties.value || {}),
|
||
|
Object.entries(b3d.cameraDataModel.cameraTypes[camData.type].value || {}),
|
||
|
)
|
||
|
.forEach(function (entry) {
|
||
|
var k = entry[0];
|
||
|
var v = entry[1];
|
||
|
// if property is controllable by direct user input, we should keep a separate version of it
|
||
|
var isControllable = b3d.cameraDataModel.controllableProperties.indexOf(k) !== -1;
|
||
|
if (isControllable) {
|
||
|
var internalValue;
|
||
|
Object.defineProperty(camera, k, {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return internalValue; },
|
||
|
set: function (a) {
|
||
|
internalValue = a;
|
||
|
this.ref[k] = a;
|
||
|
},
|
||
|
});
|
||
|
// define special properties that need custom setters
|
||
|
} else if (k === 'mode') {
|
||
|
var internalValue;
|
||
|
Object.defineProperty(camera, 'mode', {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return internalValue; },
|
||
|
set: function (a) {
|
||
|
internalValue = a;
|
||
|
if (a === 'perspective') {
|
||
|
this.ref.mode = BABYLON.Camera.PERSPECTIVE_CAMERA;
|
||
|
} else if (a === 'orthographic') {
|
||
|
this.ref.mode = BABYLON.Camera.ORTHOGRAPHIC_CAMERA;
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
} else if (k === 'orthoSize') {
|
||
|
Object.defineProperty(camera, 'recalculateOrthoBounds', {
|
||
|
// adjust orthographic boundaries according to the orthoSize and aspect ratio
|
||
|
configurable: false,
|
||
|
enumerable: false,
|
||
|
writable: false,
|
||
|
value: function () {
|
||
|
// figure out aspect ratio
|
||
|
var widthFactor = 1;
|
||
|
var heightFactor = 1;
|
||
|
var ratio = this.ref.getEngine().getRenderWidth() / this.ref.getEngine().getRenderHeight();
|
||
|
if (ratio >= 1) {
|
||
|
widthFactor = ratio;
|
||
|
} else {
|
||
|
heightFactor = 1 / ratio;
|
||
|
}
|
||
|
// divide orthoSize by two for each dimension
|
||
|
this.ref.orthoLeft = -(this.orthoSize * widthFactor) / 2;
|
||
|
this.ref.orthoRight = (this.orthoSize * widthFactor) / 2;
|
||
|
this.ref.orthoTop = (this.orthoSize * heightFactor) / 2;
|
||
|
this.ref.orthoBottom = -(this.orthoSize * heightFactor) / 2;
|
||
|
},
|
||
|
});
|
||
|
var internalValue;
|
||
|
Object.defineProperty(camera, 'orthoSize', {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return internalValue; },
|
||
|
set: function (a) {
|
||
|
internalValue = a;
|
||
|
this.recalculateOrthoBounds();
|
||
|
},
|
||
|
});
|
||
|
// define regular properties
|
||
|
} else {
|
||
|
Object.defineProperty(camera, k, {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return this.ref[k]; },
|
||
|
set: function (a) { this.ref[k] = a; },
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// set properties
|
||
|
if (camData[k] !== undefined) {
|
||
|
camera[k] = camData[k];
|
||
|
} else {
|
||
|
camera[k] = v;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// set up vector properties
|
||
|
[].concat(
|
||
|
Object.entries(b3d.cameraDataModel.commonProperties.vector3 || {}),
|
||
|
Object.entries(b3d.cameraDataModel.cameraTypes[camData.type].vector3 || {}),
|
||
|
)
|
||
|
.forEach(function (entry) {
|
||
|
var k = entry[0];
|
||
|
var v = entry[1];
|
||
|
var isControllable = b3d.cameraDataModel.controllableProperties.indexOf(k) !== -1;
|
||
|
var internalVectorObject = {};
|
||
|
camera.ref[k] = new BABYLON.Vector3();
|
||
|
Object.keys(camera.ref[k]).forEach(function (vectorKey) {
|
||
|
if (isControllable) {
|
||
|
var val;
|
||
|
Object.defineProperty(internalVectorObject, vectorKey, {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return val; },
|
||
|
set: function (a) { val = camera.ref[k][vectorKey] = a; },
|
||
|
});
|
||
|
} else {
|
||
|
Object.defineProperty(internalVectorObject, vectorKey, {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return camera.ref[k][vectorKey]; },
|
||
|
set: function (a) { camera.ref[k][vectorKey] = a; },
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
camera[k] = internalVectorObject;
|
||
|
if (camData[k]) {
|
||
|
b3d.deepCopyObjectState(camera[k], camData[k]);
|
||
|
} else {
|
||
|
b3d.deepCopyObjectState(camera[k], v);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// set up traits
|
||
|
// local variable to store internal trait values for this camera
|
||
|
var traits = {};
|
||
|
|
||
|
[].concat(
|
||
|
Object.entries(b3d.cameraDataModel.commonProperties.trait || {}),
|
||
|
Object.entries(b3d.cameraDataModel.cameraTypes[camData.type].trait || {}),
|
||
|
)
|
||
|
.forEach(function (entry) {
|
||
|
var k = entry[0];
|
||
|
var v = entry[1];
|
||
|
traits[k] = null;
|
||
|
Object.defineProperty(camera, k, {
|
||
|
configurable: true,
|
||
|
enumerable: true,
|
||
|
get: function () { return traits[k]; },
|
||
|
set: function (a) {
|
||
|
traits[k] = a;
|
||
|
// if camera is currently active, invoke trait effect immediately
|
||
|
if (b3d.curActiveCamera === this) {
|
||
|
b3d.cameraDataModel.traitEffects[k].call(this, a);
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
if (camData[k] !== undefined) {
|
||
|
camera[k] = camData[k];
|
||
|
} else {
|
||
|
camera[k] = v;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// define methods
|
||
|
Object.defineProperty(camera, 'activate', {
|
||
|
configurable: false,
|
||
|
enumerable: false,
|
||
|
writable: false,
|
||
|
value: function () {
|
||
|
if (b3d.curActiveCamera) {
|
||
|
b3d.curActiveCamera.deactivate();
|
||
|
}
|
||
|
|
||
|
b3d.curActiveCamera = this;
|
||
|
b3d.scene.activeCameras = [];
|
||
|
b3d.scene.activeCamera = this.ref;
|
||
|
|
||
|
// enable trait effects
|
||
|
Object.keys(traits).forEach(function (t) {
|
||
|
if (traits[t]) {
|
||
|
b3d.cameraDataModel.traitEffects[t].call(this, true);
|
||
|
}
|
||
|
}, this);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
Object.defineProperty(camera, 'deactivate', {
|
||
|
configurable: false,
|
||
|
enumerable: false,
|
||
|
writable: false,
|
||
|
value: function () {
|
||
|
// disable trait effects
|
||
|
Object.keys(traits).forEach(function (t) {
|
||
|
if (traits[t]) {
|
||
|
b3d.cameraDataModel.traitEffects[t].call(this, false);
|
||
|
}
|
||
|
}, this);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
Object.defineProperty(camera, 'resetRef', {
|
||
|
configurable: false,
|
||
|
enumerable: false,
|
||
|
writable: false,
|
||
|
value: function () {
|
||
|
b3d.deepCopyObjectState(this.ref, this, b3d.cameraDataModel.controllableProperties);
|
||
|
},
|
||
|
});
|
||
|
|
||
|
return camera;
|
||
|
};
|
||
|
|
||
|
b3d.getDefaultMeshProps = function (drawing) {
|
||
|
return {
|
||
|
drawing: drawing,
|
||
|
type: b3d.getDefaultMeshType(drawing),
|
||
|
transparency: b3d.getDefaultTransparency(drawing),
|
||
|
hidden: false,
|
||
|
alpha: 1,
|
||
|
};
|
||
|
};
|
||
|
|
||
|
b3d.transformFromArray = function (arr) {
|
||
|
return BABYLON.Matrix.Compose(
|
||
|
// scale
|
||
|
new BABYLON.Vector3(
|
||
|
Number(arr[0]) || 1,
|
||
|
Number(arr[1]) || 1,
|
||
|
Number(arr[2]) || 1
|
||
|
),
|
||
|
// rotation
|
||
|
BABYLON.Quaternion.FromEulerAngles(
|
||
|
(Number(arr[3]) || 0) * Math.PI / 180,
|
||
|
(Number(arr[4]) || 0) * Math.PI / 180,
|
||
|
(Number(arr[5]) || 0) * Math.PI / 180
|
||
|
),
|
||
|
// translation
|
||
|
new BABYLON.Vector3(
|
||
|
Number(arr[6]) || 0,
|
||
|
Number(arr[7]) || 0,
|
||
|
Number(arr[8]) || 0
|
||
|
),
|
||
|
);
|
||
|
};
|
||
|
|
||
|
// helper function
|
||
|
// finds drawing object by its full id i.g. 'SPR_A'
|
||
|
b3d.getDrawingFromDrw = function (drw) {
|
||
|
var map;
|
||
|
var typeAndId = drw.split('_');
|
||
|
switch (typeAndId[0]) {
|
||
|
case 'TIL':
|
||
|
map = bitsy.tile;
|
||
|
break;
|
||
|
case 'SPR':
|
||
|
map = bitsy.sprite;
|
||
|
break;
|
||
|
case 'ITM':
|
||
|
map = bitsy.item;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return map[ typeAndId[1] ];
|
||
|
};
|
||
|
|
||
|
b3d.registerRoomInStack = function (roomId, stackId, pos) {
|
||
|
b3d.roomsInStack[stackId] = b3d.roomsInStack[stackId] || [];
|
||
|
// add room to the list if it is not already there
|
||
|
if (b3d.roomsInStack[stackId].indexOf(roomId) === -1) {
|
||
|
b3d.roomsInStack[stackId].push(roomId);
|
||
|
}
|
||
|
// add or update position of the room in the stack
|
||
|
b3d.stackPosOfRoom[roomId] = {
|
||
|
stack: stackId,
|
||
|
pos: pos,
|
||
|
};
|
||
|
};
|
||
|
|
||
|
b3d.unregisterRoomFromStack = function (roomId) {
|
||
|
if (!b3d.stackPosOfRoom[roomId]) return;
|
||
|
var stackId = b3d.stackPosOfRoom[roomId].stack;
|
||
|
b3d.roomsInStack[stackId].splice(b3d.roomsInStack[stackId].indexOf(roomId), 1);
|
||
|
delete b3d.stackPosOfRoom[roomId];
|
||
|
// delete the stack if it became empty
|
||
|
if (b3d.roomsInStack[stackId].length === 0) {
|
||
|
delete b3d.roomsInStack[stackId];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
b3d.serializeDataAsDialog = function () {
|
||
|
// serialize stack data
|
||
|
var stackSerialized = {};
|
||
|
Object.entries(b3d.roomsInStack).forEach(function (entry) {
|
||
|
var stackId = entry[0];
|
||
|
var roomList = entry[1];
|
||
|
stackSerialized[stackId] = stackSerialized[stackId] || [];
|
||
|
roomList.forEach(function (roomId) {
|
||
|
stackSerialized[stackId].push({
|
||
|
id: roomId,
|
||
|
pos: b3d.stackPosOfRoom[roomId].pos,
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// serialize mesh data
|
||
|
var meshSerialized = {};
|
||
|
|
||
|
Object.entries(b3d.meshConfig).forEach(function (entry) {
|
||
|
var id = entry[0]
|
||
|
var config = entry[1];
|
||
|
|
||
|
var configSerialized = b3d.serializeMesh(config);
|
||
|
|
||
|
if (Object.values(configSerialized).length > 0) {
|
||
|
meshSerialized[id] = configSerialized;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
var result = JSON.stringify({
|
||
|
camera: b3d.curCameraPreset || b3d.mainCamera,
|
||
|
settings: b3d.settings,
|
||
|
mesh: meshSerialized,
|
||
|
stack: stackSerialized
|
||
|
}, null, 2);
|
||
|
// console.log(result);
|
||
|
bitsy.dialog['DATA3D'] = {
|
||
|
src:'"""\n' + result + '\n"""',
|
||
|
name: null,
|
||
|
};
|
||
|
}; // b3d.serializeDataAsDialog
|
||
|
|
||
|
b3d.serializeData = b3d.serializeDataAsDialog;
|
||
|
|
||
|
b3d.serializeMesh = function (meshConfig) {
|
||
|
var drawing = meshConfig.drawing;
|
||
|
|
||
|
var configSerialized = {};
|
||
|
|
||
|
if (meshConfig.type !== b3d.getDefaultMeshType(drawing)) {
|
||
|
configSerialized.type = meshConfig.type;
|
||
|
}
|
||
|
if (meshConfig.transform && !meshConfig.transform.isIdentity()) {
|
||
|
configSerialized.transform = b3d.serializeTransform(meshConfig.transform).join(',');
|
||
|
}
|
||
|
if (meshConfig.transparency !== b3d.getDefaultTransparency(drawing)) {
|
||
|
configSerialized.transparency = meshConfig.transparency;
|
||
|
}
|
||
|
if (meshConfig.replacement) {
|
||
|
configSerialized.replacement = meshConfig.replacement.drw;
|
||
|
}
|
||
|
if (meshConfig.hidden) {
|
||
|
configSerialized.hidden = meshConfig.hidden;
|
||
|
}
|
||
|
if (meshConfig.hasOwnProperty('alpha') && meshConfig.alpha !== 1) {
|
||
|
configSerialized.alpha = meshConfig.alpha;
|
||
|
}
|
||
|
if (meshConfig.children && meshConfig.children.length > 0) {
|
||
|
configSerialized.children = [];
|
||
|
meshConfig.children.forEach(function (childConfig) {
|
||
|
var childConfigSerialized = b3d.serializeMesh(childConfig);
|
||
|
childConfigSerialized.drw = childConfig.drawing.drw;
|
||
|
configSerialized.children.push(childConfigSerialized);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return configSerialized;
|
||
|
};
|
||
|
|
||
|
b3d.serializeTransform = function (transform) {
|
||
|
// serialize transform matrix as an array:
|
||
|
// [ scaleX, scaleY, scaleZ,
|
||
|
// rotationX, rotationY, rotationZ,
|
||
|
// translationX, translationY, translationZ ]
|
||
|
var scale = new BABYLON.Vector3();
|
||
|
var rotation = new BABYLON.Quaternion();
|
||
|
var translation = new BABYLON.Vector3();
|
||
|
|
||
|
transform.decompose(scale, rotation, translation);
|
||
|
|
||
|
return [].concat(
|
||
|
scale.asArray(),
|
||
|
rotation.toEulerAngles().asArray().map(function(n){return n * 180 / Math.PI}),
|
||
|
translation.asArray())
|
||
|
.map(function (n) {
|
||
|
// adjust weird offsets that are apparently caused by float imprecision
|
||
|
// it should be consistent with the editor input validation
|
||
|
// that only allows 5 digits after the decimal point
|
||
|
return Math.round(n * 100000) / 100000;
|
||
|
});
|
||
|
};
|
||
|
|
||
|
b3d.initMeshTemplates = function () {
|
||
|
var meshTemplates = {};
|
||
|
// box and towers
|
||
|
for (var i = 1; i <= bitsy.mapsize; ++i) {
|
||
|
var boxMesh = BABYLON.MeshBuilder.CreateBox('tower' + i, {
|
||
|
size: 1,
|
||
|
height: i,
|
||
|
faceUV: [
|
||
|
new BABYLON.Vector4(0, 0, 1, i), // "back"
|
||
|
new BABYLON.Vector4(0, 0, 1, i), // "front"
|
||
|
new BABYLON.Vector4(0, 0, 1, i), // "right"
|
||
|
new BABYLON.Vector4(0, 0, 1, i), // "left"
|
||
|
new BABYLON.Vector4(0, 0, 1, 1), // "top"
|
||
|
new BABYLON.Vector4(0, 0, 1, 1), // "bottom"
|
||
|
],
|
||
|
wrap: true,
|
||
|
}, b3d.scene);
|
||
|
var uvs = boxMesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
|
||
|
boxMesh.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
|
||
|
boxMesh.isVisible = false;
|
||
|
boxMesh.doNotSyncBoundingInfo = true;
|
||
|
// adjust template position so that the instances will be displated correctly
|
||
|
b3d.transformGeometry(boxMesh, BABYLON.Matrix.Translation(0.0, i / 2 - 0.5, 0.0));
|
||
|
meshTemplates['tower' + i] = boxMesh;
|
||
|
}
|
||
|
meshTemplates.box = meshTemplates.tower1;
|
||
|
|
||
|
// floor
|
||
|
var floorMesh = BABYLON.MeshBuilder.CreatePlane(`floor`, {
|
||
|
width: 1,
|
||
|
height: 1,
|
||
|
}, b3d.scene);
|
||
|
// adjust template position so that the instances will be displated correctly
|
||
|
b3d.transformGeometry(floorMesh, BABYLON.Matrix.Translation(0.0, 0.0, 0.5));
|
||
|
// have to transform geometry instead of using regular rotation
|
||
|
// or it will mess up children transforms when using combine tag
|
||
|
b3d.transformGeometry(floorMesh, BABYLON.Matrix.RotationX(Math.PI/2));
|
||
|
floorMesh.isVisible = false;
|
||
|
floorMesh.doNotSyncBoundingInfo = true;
|
||
|
meshTemplates.floor = floorMesh;
|
||
|
|
||
|
// plane
|
||
|
var planeMesh = BABYLON.MeshBuilder.CreatePlane('plane', {
|
||
|
width: 1,
|
||
|
height: 1,
|
||
|
sideOrientation: BABYLON.Mesh.DOUBLESIDE,
|
||
|
frontUVs: new BABYLON.Vector4(0, 1, 1, 0),
|
||
|
backUVs: new BABYLON.Vector4(0, 1, 1, 0),
|
||
|
}, b3d.scene);
|
||
|
// in case of rotation have to transform geometry or it will affect positions of its children
|
||
|
b3d.transformGeometry(planeMesh, BABYLON.Matrix.RotationX(Math.PI));
|
||
|
planeMesh.isVisible = false;
|
||
|
meshTemplates.plane = planeMesh;
|
||
|
planeMesh.doNotSyncBoundingInfo = true;
|
||
|
meshTemplates.billboard = planeMesh.clone('billboard');
|
||
|
|
||
|
// wedge
|
||
|
var wedgeMesh = new BABYLON.Mesh("wedgeMesh", b3d.scene);
|
||
|
var wedgeMeshPos = [
|
||
|
-1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 1, 0, 1, 1, // 0,1,2, 3,4,5,
|
||
|
-1, 0, 1, -1, 0, 0, 0, 1, 0, 0, 1, 1, // 6,7,8,9
|
||
|
0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, // 10,11,12,13
|
||
|
0, 0, 1, 0, 0, 0, -1, 0, 0, -1, 0, 1 // 14,15,16,17
|
||
|
];
|
||
|
var wedgeMeshInd = [
|
||
|
0, 1, 2, 3, 4, 5, //triangles on the front and the back
|
||
|
6, 7, 8, 8, 9, 6, // tris that make up the sliding face at the top
|
||
|
10, 11, 12, 12, 13, 10, // right face
|
||
|
14, 15, 16, 16, 17, 14 // bottom face
|
||
|
];
|
||
|
var wedgeMeshUvs = [
|
||
|
0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
|
||
|
0, 0, 1, 0, 1, 1, 0, 1,
|
||
|
0, 0, 1, 0, 1, 1, 0, 1,
|
||
|
0, 0, 1, 0, 1, 1, 0, 1
|
||
|
];
|
||
|
var wedgeMeshVertData = new BABYLON.VertexData();
|
||
|
wedgeMeshVertData.positions = wedgeMeshPos;
|
||
|
wedgeMeshVertData.indices = wedgeMeshInd;
|
||
|
wedgeMeshVertData.uvs = wedgeMeshUvs;
|
||
|
|
||
|
var translation = BABYLON.Matrix.Translation(0.5, -0.5, -0.5);
|
||
|
wedgeMeshVertData.transform(translation);
|
||
|
|
||
|
wedgeMeshVertData.applyToMesh(wedgeMesh);
|
||
|
wedgeMesh.isVisible = false; // but newly created copies and instances will be visible by default
|
||
|
wedgeMesh.doNotSyncBoundingInfo = true;
|
||
|
|
||
|
meshTemplates.wedge = wedgeMesh;
|
||
|
|
||
|
// add empty mesh
|
||
|
meshTemplates.empty = new BABYLON.Mesh('empty', b3d.scene);
|
||
|
|
||
|
return meshTemplates;
|
||
|
}; // b3d.initMeshTemplates()
|
||
|
|
||
|
|
||
|
// to adjust vertices on the mesh
|
||
|
b3d.transformGeometry = function (mesh, matrix) {
|
||
|
var vertData = BABYLON.VertexData.ExtractFromMesh(mesh);
|
||
|
vertData.transform(matrix);
|
||
|
vertData.applyToMesh(mesh);
|
||
|
};
|
||
|
|
||
|
// cache helper
|
||
|
b3d.getCache = function (cacheName, make) {
|
||
|
var cache = {};
|
||
|
b3d.caches[cacheName] = cache;
|
||
|
return function (id, args) {
|
||
|
var cached = cache[id];
|
||
|
if (cached) {
|
||
|
return cached;
|
||
|
}
|
||
|
cached = cache[id] = make.apply(undefined, args);
|
||
|
return cached;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
b3d.getTextureFromCache = b3d.getCache('tex', function(drawing, pal, transparency, alpha) {
|
||
|
var numFrames = drawing.animation.isAnimated? drawing.animation.frameCount: 1;
|
||
|
var imageSource = bitsy.renderer.GetImageSource(drawing.drw);
|
||
|
var frameWidth = imageSource[0][0].length;
|
||
|
var frameHeight = imageSource[0].length;
|
||
|
|
||
|
// get the colors
|
||
|
var bg = bitsy.palette[pal].colors[0].slice();
|
||
|
bg[3] = transparency? 0: Math.round(alpha * 255);
|
||
|
var fg = bitsy.palette[pal].colors[drawing.col].slice();
|
||
|
fg[3] = Math.round(alpha * 255);
|
||
|
|
||
|
var tex = new BABYLON.DynamicTexture(drawing.drw, {
|
||
|
width: frameWidth * numFrames,
|
||
|
height: frameHeight,
|
||
|
}, b3d.scene, false, BABYLON.Texture.NEAREST_NEAREST_MIPNEAREST);
|
||
|
|
||
|
tex.wrapU = tex.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
|
||
|
tex.uScale = 1 / numFrames;
|
||
|
if (transparency || alpha < 1) tex.hasAlpha = true;
|
||
|
|
||
|
var ctx = tex.getContext();
|
||
|
var imageData = ctx.getImageData(0, 0, frameWidth * numFrames, frameHeight);
|
||
|
for (var frameIndex = 0; frameIndex < numFrames; frameIndex++) {
|
||
|
var curFrame = imageSource[frameIndex];
|
||
|
for (var y = 0; y < curFrame.length; y++) {
|
||
|
for (var x = 0; x < curFrame[y].length; x++) {
|
||
|
// position of the red component of the pixel at a given coordinate
|
||
|
var i = y * (frameWidth * numFrames * 4) + ((frameWidth * frameIndex) + x) * 4;
|
||
|
// choose background or foreground color
|
||
|
var col = curFrame[y][x] === 0? bg: fg;
|
||
|
// iterate through red, green, blue and alpha components
|
||
|
// and put them into image data
|
||
|
for (var c = 0; c < col.length; c++) {
|
||
|
imageData.data[i + c] = col[c];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ctx.putImageData(imageData, 0, 0);
|
||
|
tex.update();
|
||
|
return tex;
|
||
|
});
|
||
|
|
||
|
b3d.getTexture = function (drawing, pal, transparency, alpha) {
|
||
|
// apply drawing replacement
|
||
|
var altDrawing = b3d.meshConfig[drawing.drw].replacement;
|
||
|
drawing = altDrawing && altDrawing || drawing;
|
||
|
|
||
|
var drw = drawing.drw;
|
||
|
var col = drawing.col;
|
||
|
var key = `${drw},${col},${pal},${transparency},${alpha}`;
|
||
|
return b3d.getTextureFromCache(key, [drawing, pal, transparency, alpha]);
|
||
|
};
|
||
|
|
||
|
b3d.getMaterialFromCache = b3d.getCache('mat', function (drawing, pal, transparency, alpha, key) {
|
||
|
var mat = b3d.baseMat.clone();
|
||
|
mat.diffuseTexture = b3d.getTexture(drawing, pal, transparency, alpha);
|
||
|
if (drawing.animation.isAnimated) {
|
||
|
// make sure it's listed in the collection of animated materials, update the reference if needed
|
||
|
if (b3d.animatedMaterials[key]) {
|
||
|
b3d.animatedMaterials[key][0] = drawing;
|
||
|
b3d.animatedMaterials[key][1] = mat;
|
||
|
} else {
|
||
|
b3d.animatedMaterials[key] = [drawing, mat];
|
||
|
}
|
||
|
}
|
||
|
if (alpha < 1) {
|
||
|
mat.useAlphaFromDiffuseTexture = true;
|
||
|
}
|
||
|
return mat;
|
||
|
});
|
||
|
|
||
|
b3d.getMaterial = function (drawing, pal, transparency, alpha) {
|
||
|
var drw = drawing.drw;
|
||
|
var col = drawing.col;
|
||
|
var key = `${drw},${col},${pal},${transparency},${alpha}`;
|
||
|
return b3d.getMaterialFromCache(key, [drawing, pal, transparency, alpha, key]);
|
||
|
};
|
||
|
|
||
|
b3d.getMeshFromCache = b3d.getCache('mesh', function (drawing, pal, config, hidden) {
|
||
|
var mesh;
|
||
|
if (hidden) {
|
||
|
mesh = b3d.meshTemplates.empty.clone();
|
||
|
} else {
|
||
|
mesh = b3d.meshTemplates[config.type].clone();
|
||
|
}
|
||
|
mesh.makeGeometryUnique();
|
||
|
mesh.isVisible = false;
|
||
|
mesh.material = b3d.getMaterial(drawing, pal, config.transparency, config.alpha);
|
||
|
// enable vertical tiling for towers
|
||
|
if (config.type.startsWith('tower')) {
|
||
|
mesh.material.diffuseTexture.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
|
||
|
}
|
||
|
return mesh;
|
||
|
});
|
||
|
|
||
|
b3d.getMesh = function (drawing, pal, config) {
|
||
|
var hidden = b3d.isObjectHidden(config);
|
||
|
// if this object doesn't have children and should be hidden and isn't a sprite, it will be null and won't be added at all
|
||
|
if (hidden && !config.children && drawing.room === undefined) {
|
||
|
return null;
|
||
|
}
|
||
|
var drw = drawing.drw;
|
||
|
var col = drawing.col;
|
||
|
// include type in the key to account for cases when drawings that link to
|
||
|
// the same 'drw' need to have different types when using with other hacks
|
||
|
var key = `${drw},${col},${pal},${config.type},${config.transparency},${config.alpha},${hidden}`;
|
||
|
return b3d.getMeshFromCache(key, [drawing, pal, config, hidden]);
|
||
|
};
|
||
|
|
||
|
b3d.clearCaches = function (cachesArr, drw, col, pal) {
|
||
|
var r = new RegExp(`${drw || '\\D\\D\\D_\\w+?'},${col || '\\d*?'},${pal || '\\d*'}`);
|
||
|
cachesArr.forEach(function(cache) {
|
||
|
Object.keys(cache)
|
||
|
.filter(function(key) {return r.test(key);})
|
||
|
.forEach(function(key) {
|
||
|
cache[key].dispose();
|
||
|
delete cache[key];
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
b3d.clearCachesPalette = function (pal) {
|
||
|
b3d.clearCaches(Object.values(b3d.caches), null, null, pal);
|
||
|
};
|
||
|
|
||
|
b3d.clearCachesTexture = function (drw) {
|
||
|
b3d.clearCaches(Object.values(b3d.caches), drw, null, null);
|
||
|
};
|
||
|
|
||
|
b3d.clearCachesMesh = function (drw) {
|
||
|
b3d.clearCaches([b3d.caches.mesh], drw, null, null);
|
||
|
};
|
||
|
|
||
|
b3d.update = function () {
|
||
|
// console.log("update called");
|
||
|
b3d.curStack = b3d.stackPosOfRoom[bitsy.curRoom] && b3d.stackPosOfRoom[bitsy.curRoom].stack || null;
|
||
|
var didChangeScene = b3d.curStack? b3d.curStack !== b3d.lastStack: bitsy.curRoom !== b3d.lastRoom;
|
||
|
var editorMode = bitsy.isPlayerEmbeddedInEditor && !bitsy.isPlayMode;
|
||
|
|
||
|
// sprite changes
|
||
|
Object.entries(b3d.sprites).forEach(function (entry) {
|
||
|
var id = entry[0];
|
||
|
var mesh = entry[1];
|
||
|
var s = bitsy.sprite[id];
|
||
|
if (s && b3d.isRoomVisible(s.room)) {
|
||
|
// if the sprite still exists, is in the current room or in the current stack
|
||
|
// update sprite's position
|
||
|
mesh.bitsyOrigin.x = s.x;
|
||
|
mesh.bitsyOrigin.y = s.y;
|
||
|
mesh.bitsyOrigin.roomId = s.room;
|
||
|
|
||
|
var targetX = s.x;
|
||
|
var targetZ = bitsy.mapsize - 1 - s.y;
|
||
|
var targetY = b3d.curStack && b3d.stackPosOfRoom[s.room].pos || 0;
|
||
|
|
||
|
b3d.spriteLastPos[id] = b3d.spriteLastPos[id] || new BABYLON.Vector3(targetX, targetY, targetZ);
|
||
|
var lastPos = b3d.spriteLastPos[id];
|
||
|
|
||
|
if (!editorMode &&
|
||
|
!lastPos.equalsToFloats(targetX, targetY, targetZ) &&
|
||
|
lastPos.subtractFromFloats(targetX, targetY, targetZ).length() <= b3d.settings.tweenDistance) {
|
||
|
// add a tween from current position
|
||
|
b3d.tweens[id] = {
|
||
|
from: mesh.position.clone(),
|
||
|
to: new BABYLON.Vector3(targetX, targetY, targetZ),
|
||
|
start: bitsy.prevTime,
|
||
|
};
|
||
|
} else {
|
||
|
// otherwise move the sprite immediately
|
||
|
mesh.position.x = targetX;
|
||
|
mesh.position.z = targetZ;
|
||
|
mesh.position.y = targetY;
|
||
|
}
|
||
|
// remember current position
|
||
|
lastPos.copyFromFloats(targetX, targetY, targetZ);
|
||
|
} else {
|
||
|
// otherwise remove the sprite
|
||
|
mesh.dispose();
|
||
|
mesh = null;
|
||
|
delete b3d.sprites[id];
|
||
|
delete b3d.tweens[id];
|
||
|
delete b3d.spriteLastPos[id];
|
||
|
}
|
||
|
});
|
||
|
Object.values(bitsy.sprite).filter(function (s) {
|
||
|
// go through bitsy sprites and get those that should be currently displayed
|
||
|
return b3d.isRoomVisible(s.room);
|
||
|
}).forEach(function (s) {
|
||
|
b3d.sprites[s.id] = b3d.updateObject(b3d.sprites[s.id], s, s.room, s.x, s.y);
|
||
|
});
|
||
|
// remove existing tweens when changing the scene
|
||
|
if (didChangeScene || editorMode) {
|
||
|
Object.keys(b3d.tweens).forEach(function(k){
|
||
|
delete b3d.tweens[k];
|
||
|
});
|
||
|
}
|
||
|
// apply tweens
|
||
|
if (!editorMode) {
|
||
|
Object.entries(b3d.tweens).forEach(function (entry) {
|
||
|
var id = entry[0];
|
||
|
var tween = entry[1];
|
||
|
var t = (bitsy.prevTime - tween.start) / b3d.settings.tweenDuration;
|
||
|
if (t < 1) {
|
||
|
BABYLON.Vector3.LerpToRef(
|
||
|
tween.from,
|
||
|
tween.to,
|
||
|
b3d.tweenFunctions[b3d.settings.tweenFunction](t),
|
||
|
b3d.sprites[id].position
|
||
|
);
|
||
|
} else {
|
||
|
delete b3d.tweens[id];
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
// copy avatar's position into avatarNode
|
||
|
if (b3d.avatarRef && b3d.avatarRef.position) {
|
||
|
b3d.avatarNode.position = b3d.avatarRef.position;
|
||
|
}
|
||
|
|
||
|
// item changes
|
||
|
// delete irrelevant b3d.items
|
||
|
Object.entries(b3d.items).forEach(function (entry) {
|
||
|
var roomId = entry[0].slice(0, entry[0].indexOf(','));
|
||
|
if (b3d.isRoomVisible(roomId)) {
|
||
|
// if this item is in the current stack
|
||
|
// check if it is still listed in its room
|
||
|
// if so keep it as it is and return
|
||
|
if (bitsy.room[roomId].items.find(function (item) {
|
||
|
return `${roomId},${item.id},${item.x},${item.y}` === entry[0];
|
||
|
})) {
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (entry[1]) {
|
||
|
entry[1].dispose();
|
||
|
}
|
||
|
entry[1] = null;
|
||
|
delete b3d.items[entry[0]];
|
||
|
});
|
||
|
|
||
|
// make/update relevant b3d.items
|
||
|
(b3d.roomsInStack[b3d.curStack] || [bitsy.curRoom]).forEach(function (roomId) {
|
||
|
bitsy.room[roomId].items.forEach(function (roomItem) {
|
||
|
var key = `${roomId},${roomItem.id},${roomItem.x},${roomItem.y}`;
|
||
|
b3d.items[key] = b3d.updateObject(b3d.items[key], bitsy.item[roomItem.id], roomId, roomItem.x, roomItem.y);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// updated b3d.tiles logic
|
||
|
// first clear the b3d.tiles from rooms that should not be currently displayed
|
||
|
Object.keys(b3d.tiles)
|
||
|
.filter(function(roomId) { return !b3d.isRoomVisible(roomId) })
|
||
|
.forEach(function(roomId) {
|
||
|
b3d.tiles[roomId].forEach(function (row) {
|
||
|
row.forEach(function (tileMesh) {
|
||
|
if (tileMesh !== null) {
|
||
|
tileMesh.dispose();
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
delete b3d.tiles[roomId];
|
||
|
});
|
||
|
|
||
|
// iterate throught tilemaps of rooms in the current stack
|
||
|
// and update 3d b3d.scene objects accordingly
|
||
|
(b3d.roomsInStack[b3d.curStack] || [bitsy.curRoom]).forEach(function (roomId) {
|
||
|
if (!b3d.tiles[roomId]) {
|
||
|
// generate empty 2d array for meshes
|
||
|
b3d.tiles[roomId] = bitsy.room[roomId].tilemap.map(function(row) {
|
||
|
return row.map(function(tileId) {
|
||
|
return null;
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
bitsy.room[roomId].tilemap.forEach(function(row, y) {
|
||
|
row.forEach(function(tileId, x) {
|
||
|
b3d.tiles[roomId][y][x] = b3d.updateObject(b3d.tiles[roomId][y][x], bitsy.tile[tileId], roomId, x, y);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
// bg changes
|
||
|
b3d.scene.clearColor = b3d.getColor(b3d.settings.clearColor);
|
||
|
b3d.scene.fogColor = b3d.getColor(b3d.settings.fogColor);
|
||
|
|
||
|
b3d.lastStack = b3d.curStack;
|
||
|
b3d.lastRoom = bitsy.curRoom;
|
||
|
|
||
|
// clear out the text context when not in use
|
||
|
if (!bitsy.dialogBuffer.IsActive() || (bitsy.isPlayerEmbeddedInEditor && !bitsy.isPlayMode)) {
|
||
|
if (b3d.dialogDirty) {
|
||
|
b3d.textContext.clearRect(0, 0, b3d.textCanvas.width, b3d.textCanvas.height);
|
||
|
b3d.dialogDirty = false;
|
||
|
}
|
||
|
} else {
|
||
|
b3d.dialogDirty = true;
|
||
|
}
|
||
|
}; // b3d.update()
|
||
|
|
||
|
b3d.render = function () {
|
||
|
// clear scene when rendering title/endings
|
||
|
// using a FOV hack here instead of the engine's clear function
|
||
|
// in order to ensure post-processing isn't overridden
|
||
|
var fov = b3d.curActiveCamera.ref.fov;
|
||
|
if ((!isPlayerEmbeddedInEditor || isPlayMode) && (bitsy.isNarrating || bitsy.isEnding)) {
|
||
|
b3d.curActiveCamera.ref.fov = 0;
|
||
|
}
|
||
|
b3d.scene.render();
|
||
|
|
||
|
// if we updated animations this frame, make sure to freeze animated materials again
|
||
|
if (b3d.didUpdateAnimations) {
|
||
|
Object.values(b3d.animatedMaterials).forEach(function (entry) {
|
||
|
entry[1].freeze();
|
||
|
});
|
||
|
b3d.didUpdateAnimations = false;
|
||
|
};
|
||
|
b3d.curActiveCamera.ref.fov = fov;
|
||
|
};
|
||
|
|
||
|
b3d.updateObject = function (oldObject, drawing, roomId, x, y) {
|
||
|
// consider that drawing can be undefined and oldObject could be undefined
|
||
|
var newObject = null;
|
||
|
if (drawing) {
|
||
|
// if this object doesn't have children and should be hidden, it will be null and won't be added at all
|
||
|
newObject = b3d.getMesh(drawing, bitsy.curPal(), b3d.meshConfig[drawing.drw]);
|
||
|
}
|
||
|
if (oldObject !== newObject && (newObject !== (oldObject && oldObject.sourceMesh))) {
|
||
|
if (oldObject) {
|
||
|
oldObject.dispose();
|
||
|
oldObject = null;
|
||
|
}
|
||
|
if (newObject) {
|
||
|
newObject = b3d.addMeshInstance(newObject, drawing, roomId, x, y);
|
||
|
return newObject;
|
||
|
} else {
|
||
|
return oldObject;
|
||
|
}
|
||
|
} else if (drawing && oldObject) {
|
||
|
b3d.updateChildren(drawing, oldObject);
|
||
|
return oldObject;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
b3d.isObjectHidden = function (config) {
|
||
|
return config.hidden && (bitsy.EditMode === undefined || b3d.curActiveCamera === b3d.mainCamera);
|
||
|
};
|
||
|
|
||
|
b3d.isRoomVisible = function (roomId) {
|
||
|
// true if the room is the current room or we are in the stack and the room is not a stray room and is in the current stack
|
||
|
return roomId === bitsy.curRoom || b3d.curStack && b3d.stackPosOfRoom[roomId] && b3d.stackPosOfRoom[roomId].stack === b3d.curStack;
|
||
|
};
|
||
|
|
||
|
b3d.addMeshInstance = function (mesh, drawing, roomId, x, y) {
|
||
|
var instance = mesh.createInstance();
|
||
|
instance.position.x = x;
|
||
|
instance.position.z = bitsy.mapsize - 1 - y;
|
||
|
instance.position.y = b3d.stackPosOfRoom[roomId] && b3d.stackPosOfRoom[roomId].pos || 0;
|
||
|
|
||
|
// 3d editor addition:
|
||
|
// bitsyOrigin property to correctly determine corresponding bitsy drawing when mouse-picking
|
||
|
instance.bitsyOrigin = {
|
||
|
drawing: drawing,
|
||
|
x: x,
|
||
|
y: y,
|
||
|
roomId: roomId,
|
||
|
};
|
||
|
|
||
|
b3d.meshExtraSetup(drawing, instance, b3d.meshConfig[drawing.drw]);
|
||
|
|
||
|
return instance;
|
||
|
};
|
||
|
|
||
|
b3d.getColor = function (colorId) {
|
||
|
var col = bitsy.palette[bitsy.curPal()].colors[colorId];
|
||
|
return new BABYLON.Color3(
|
||
|
col[0] / 255,
|
||
|
col[1] / 255,
|
||
|
col[2] / 255
|
||
|
);
|
||
|
};
|
||
|
|
||
|
b3d.addChildren = function (drawing, mesh) {
|
||
|
// make sure the mesh we are about to add children to doesn't have a parent on its own to avoid ifinite loops
|
||
|
if (!mesh.parent && b3d.meshConfig[drawing.drw].children) {
|
||
|
// add specified drawings to the b3d.scene as child meshes
|
||
|
b3d.meshConfig[drawing.drw].children.forEach(function(childConfig) {
|
||
|
var childDrawing = childConfig.drawing;
|
||
|
var childMesh = b3d.getMesh(childDrawing, bitsy.curPal(), childConfig);
|
||
|
if (childMesh){
|
||
|
childMesh = childMesh.createInstance();
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
childMesh.position.x = mesh.position.x;
|
||
|
childMesh.position.y = mesh.position.y;
|
||
|
childMesh.position.z = mesh.position.z;
|
||
|
childMesh.setParent(mesh);
|
||
|
b3d.meshExtraSetup(childDrawing, childMesh, childConfig);
|
||
|
// for editor version of the 3d hack allow all child meshes to move with their parent
|
||
|
childMesh.unfreezeWorldMatrix();
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
b3d.updateChildren = function (parentDrawing, parentMesh) {
|
||
|
var childrenConfigs = b3d.meshConfig[parentDrawing.drw].children;
|
||
|
if (!childrenConfigs || !parentMesh) return;
|
||
|
var childMeshes = parentMesh.getChildren();
|
||
|
childrenConfigs.forEach(function (config, i) {
|
||
|
var oldMesh = childMeshes[i];
|
||
|
var newMesh = null;
|
||
|
newMesh = b3d.getMesh(config.drawing, bitsy.curPal(), config);
|
||
|
if (oldMesh !== newMesh && (newMesh !== (oldMesh && oldMesh.sourceMesh))) {
|
||
|
if (oldMesh) {
|
||
|
oldMesh.dispose();
|
||
|
}
|
||
|
if (newMesh) {
|
||
|
newMesh = newMesh.createInstance();
|
||
|
newMesh.position.x = parentMesh.position.x;
|
||
|
newMesh.position.y = parentMesh.position.y;
|
||
|
newMesh.position.z = parentMesh.position.z;
|
||
|
newMesh.setParent(parentMesh);
|
||
|
b3d.meshExtraSetup(config.drawing, newMesh, config);
|
||
|
newMesh.unfreezeWorldMatrix();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
b3d.getDefaultTransparency = function (drawing) {
|
||
|
return !drawing.drw.includes('TIL');
|
||
|
};
|
||
|
|
||
|
b3d.getDefaultMeshType = function (drawing) {
|
||
|
if (drawing.id === bitsy.playerId) {
|
||
|
return 'plane';
|
||
|
}
|
||
|
if (drawing.drw.startsWith('ITM')) {
|
||
|
return 'plane';
|
||
|
}
|
||
|
if (drawing.drw.startsWith('SPR')) {
|
||
|
return 'billboard';
|
||
|
}
|
||
|
if (drawing.isWall) {
|
||
|
return 'box';
|
||
|
}
|
||
|
return 'floor';
|
||
|
};
|
||
|
|
||
|
b3d.getBillboardMode = function () {
|
||
|
return BABYLON.TransformNode.BILLBOARDMODE_Y | BABYLON.TransformNode.BILLBOARDMODE_Z;
|
||
|
};
|
||
|
|
||
|
b3d.meshExtraSetup = function (drawing, mesh, meshConfig) {
|
||
|
b3d.addChildren(drawing, mesh);
|
||
|
if (meshConfig.transform) {
|
||
|
mesh.setPreTransformMatrix(meshConfig.transform);
|
||
|
if (drawing === bitsy.player()) {
|
||
|
b3d.avatarNode.setPreTransformMatrix(meshConfig.transform);
|
||
|
}
|
||
|
}
|
||
|
if (mesh.sourceMesh && mesh.sourceMesh.source.name === 'billboard') {
|
||
|
mesh.billboardMode = b3d.getBillboardMode();
|
||
|
} else if (!drawing.drw.startsWith('SPR')) {
|
||
|
mesh.freezeWorldMatrix();
|
||
|
}
|
||
|
if (drawing === bitsy.player()) {
|
||
|
b3d.avatarRef = mesh;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
b3d.deepCopyObjectState = function (target, source, filter) {
|
||
|
var propertyList = filter || Object.keys(source);
|
||
|
propertyList.forEach(function (p) {
|
||
|
if (!(p in target) || !(p in source)) {
|
||
|
return;
|
||
|
} else if (typeof target[p] === 'object' && typeof source[p] === 'object') {
|
||
|
b3d.deepCopyObjectState(target[p], source[p]);
|
||
|
} else {
|
||
|
target[p] = source[p];
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
b3d.cameraStateSnapshot = {
|
||
|
propertyList: ['alpha', 'beta', 'radius', 'fov', 'target', 'inertia'],
|
||
|
take: function () {
|
||
|
var obj = {};
|
||
|
this.propertyList.forEach(function (p) {
|
||
|
obj[p] = b3d.scene.activeCamera[p];
|
||
|
});
|
||
|
return JSON.stringify(obj);
|
||
|
},
|
||
|
apply: function (snapshot) {
|
||
|
var obj = JSON.parse(snapshot);
|
||
|
b3d.deepCopyObjectState(b3d.scene.activeCamera, obj);
|
||
|
},
|
||
|
};
|
||
|
|
||
|
</script>
|
||
|
|
||
|
</head>
|
||
|
|
||
|
|
||
|
<!-- DOCUMENT BODY -->
|
||
|
<body onload='startExportedGame()'>
|
||
|
<!-- GAME CANVAS -->
|
||
|
<canvas id='game'></canvas>
|
||
|
</body>
|
||
|
|
||
|
|
||
|
</html>
|