Initial
@@ -0,0 +1,6 @@
|
||||
node_modules
|
||||
package.json
|
||||
package-lock.json
|
||||
autosave/
|
||||
\#*
|
||||
*~
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Dominic Szablewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Q1K3 - A JS13k GAME
|
||||
|
||||
My entry for the 2021 [js13k](https://js13kgames.com/) competition.
|
||||
|
||||
Play here: https://phoboslab.org/q1k3/
|
||||
|
||||
### Controls
|
||||
- Movement: WASD or Arrow Keys
|
||||
- Attack: Left Mouse Button
|
||||
- Jump: Space or Right Mouse Button
|
||||
- Switch Weapon: Q/E or Mousewheel
|
||||
|
||||
### Features
|
||||
- 2 Levels
|
||||
- 5 Types of enemies
|
||||
- 3 Weapons
|
||||
- 30 different textures
|
||||
- Music from Andy Lösch: [no-fate](http://no-fate.net/)
|
||||
- Dynamic lighting
|
||||
- Doors(!)
|
||||
- Somewhat robust collision detection, even for fast moving objects
|
||||
- Enemy AI with line of sight checks. No pathfinding, but still does a reasonable job following the player
|
||||
- "Spacial" Audio (Stero separation and falloff by distance)
|
||||
- Maps build with [TrenchBroom](https://trenchbroom.github.io/)
|
||||
- A map compiler written in C (used during build)
|
||||
|
||||
### Libs used
|
||||
- [Tiny Texture Tumbler](https://github.com/phoboslab/ttt) for texture generation
|
||||
- A minified fork of [Sonant-X](https://github.com/nicolas-van/sonant-x) for sounds and music
|
||||
|
||||
|
||||
### License
|
||||
MIT Licensed
|
||||
|
||||
Please be aware that this projects makes use of Sonant-X (albeit heavily modified)
|
||||
which is published under the zlib license.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib boulder.mtl
|
||||
o Cube2
|
||||
#7 vertices, 8 faces
|
||||
v -1.76671199 -1.11166500 -1.27988643
|
||||
v -0.66717809 -1.13106144 0.80598548
|
||||
v -0.75547184 0.39059562 -1.03424222
|
||||
v 1.71502654 -1.25440865 -1.89713495
|
||||
v 1.00000000 -1.00000000 1.00000000
|
||||
v 0.43931125 8.8170497e-2 -1.22055291
|
||||
v 0.42936450 0.36758775 0.33316664
|
||||
g Cube2_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 6// 4//
|
||||
f 2// 3// 1//
|
||||
f 2// 7// 3//
|
||||
f 3// 6// 1//
|
||||
f 3// 7// 6//
|
||||
f 4// 6// 5//
|
||||
f 5// 6// 7//
|
||||
f 5// 7// 2//
|
||||
@@ -0,0 +1,25 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib box.mtl
|
||||
o Cube1
|
||||
#8 vertices, 10 faces
|
||||
v -1.00000000 -1.00000000 -1.00000000
|
||||
v -1.00000000 -1.00000000 1.00000000
|
||||
v -1.00000000 1.00000000 -1.00000000
|
||||
v -1.00000000 1.00000000 1.00000000
|
||||
v 1.00000000 -1.00000000 -1.00000000
|
||||
v 1.00000000 -1.00000000 1.00000000
|
||||
v 1.00000000 1.00000000 -1.00000000
|
||||
v 1.00000000 1.00000000 1.00000000
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 2// 3// 1//
|
||||
f 2// 4// 3//
|
||||
f 2// 8// 4//
|
||||
f 3// 5// 1//
|
||||
f 3// 7// 5//
|
||||
f 3// 8// 7//
|
||||
f 4// 8// 3//
|
||||
f 5// 8// 6//
|
||||
f 6// 8// 2//
|
||||
f 7// 8// 5//
|
||||
@@ -0,0 +1,33 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib grenade.mtl
|
||||
o Cylinder1
|
||||
#10 vertices, 16 faces
|
||||
v -1.50000000 1.00000000 0.0000000e+0
|
||||
v -1.50000000 0.30901699 0.95105652
|
||||
v -1.50000000 -0.80901699 0.58778525
|
||||
v -1.50000000 -0.80901699 -0.58778525
|
||||
v -1.50000000 0.30901699 -0.95105652
|
||||
v 1.50000000 1.00000000 0.0000000e+0
|
||||
v 1.50000000 0.30901699 0.95105652
|
||||
v 1.50000000 -0.80901699 0.58778525
|
||||
v 1.50000000 -0.80901699 -0.58778525
|
||||
v 1.50000000 0.30901699 -0.95105652
|
||||
g Cylinder1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 4// 2//
|
||||
f 1// 6// 5//
|
||||
f 2// 4// 3//
|
||||
f 2// 6// 1//
|
||||
f 2// 8// 7//
|
||||
f 3// 8// 2//
|
||||
f 4// 8// 3//
|
||||
f 4// 10// 9//
|
||||
f 5// 4// 1//
|
||||
f 5// 6// 10//
|
||||
f 5// 10// 4//
|
||||
f 6// 9// 10//
|
||||
f 7// 6// 2//
|
||||
f 7// 8// 6//
|
||||
f 9// 6// 8//
|
||||
f 9// 8// 4//
|
||||
@@ -0,0 +1,54 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib hound.mtl
|
||||
o Cube1
|
||||
#17 vertices, 30 faces
|
||||
v -0.27414249 0.20231664 1.59224039
|
||||
v 0.24584539 0.20231664 1.59224039
|
||||
v -0.34489706 0.68997600 -5.9876242e-2
|
||||
v 0.31659996 0.68997600 -5.9876242e-2
|
||||
v -0.44658541 0.30520433 -1.66534505
|
||||
v 0.41828831 0.30520433 -1.66534505
|
||||
v -1.4148550e-2 -0.39042135 0.70643627
|
||||
v -1.4148550e-2 -6.9785484e-2 -2.34491358
|
||||
v -1.4148550e-2 -0.23375148 -0.42106184
|
||||
v -0.43375565 -1.00192308 -1.66343399
|
||||
v 0.40545855 -1.00192308 -1.66343399
|
||||
v -0.60915295 -0.99285579 0.59310583
|
||||
v 0.58085585 -0.99285579 0.59310583
|
||||
v -1.4148550e-2 -9.7830546e-3 -1.28127565
|
||||
v -1.4148550e-2 -5.9388855e-2 0.21094748
|
||||
v -0.45093850 0.58881440 1.65639487
|
||||
v 0.42264140 0.58881440 1.65639487
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 7// 2//
|
||||
f 1// 17// 16//
|
||||
f 2// 7// 17//
|
||||
f 2// 17// 1//
|
||||
f 3// 5// 9//
|
||||
f 3// 12// 7//
|
||||
f 3// 17// 4//
|
||||
f 4// 6// 3//
|
||||
f 4// 13// 9//
|
||||
f 4// 17// 7//
|
||||
f 5// 3// 6//
|
||||
f 5// 6// 8//
|
||||
f 6// 11// 8//
|
||||
f 7// 13// 4//
|
||||
f 7// 15// 13//
|
||||
f 7// 16// 3//
|
||||
f 8// 10// 5//
|
||||
f 8// 14// 10//
|
||||
f 9// 5// 10//
|
||||
f 9// 6// 4//
|
||||
f 9// 12// 3//
|
||||
f 9// 14// 11//
|
||||
f 9// 15// 12//
|
||||
f 10// 14// 9//
|
||||
f 11// 6// 9//
|
||||
f 11// 14// 8//
|
||||
f 12// 15// 7//
|
||||
f 13// 15// 9//
|
||||
f 16// 7// 1//
|
||||
f 16// 17// 3//
|
||||
@@ -0,0 +1,54 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib hound_run_1.mtl
|
||||
o Cube1
|
||||
#17 vertices, 30 faces
|
||||
v -0.27414249 0.20231664 1.59224039
|
||||
v 0.24584539 0.20231664 1.59224039
|
||||
v -0.34489706 0.68997600 -5.9876242e-2
|
||||
v 0.31659996 0.68997600 -5.9876242e-2
|
||||
v -0.44658541 0.30520433 -1.66534505
|
||||
v 0.41828831 0.30520433 -1.66534505
|
||||
v -1.4148550e-2 -0.39042135 0.70643627
|
||||
v -1.4148550e-2 -6.9785484e-2 -2.34491358
|
||||
v -1.4148550e-2 -0.23375148 -0.42106184
|
||||
v -0.43375565 -0.93382778 -0.95044611
|
||||
v 0.40545855 -0.83101396 -0.66615665
|
||||
v -0.60915295 -0.95696320 0.16541373
|
||||
v 0.58085585 -0.81540550 -7.0403956e-2
|
||||
v -1.4148550e-2 -9.7830546e-3 -1.28127565
|
||||
v -1.4148550e-2 -5.9388855e-2 0.21094748
|
||||
v -0.45093850 0.58881440 1.65639487
|
||||
v 0.42264140 0.58881440 1.65639487
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 7// 2//
|
||||
f 1// 17// 16//
|
||||
f 2// 7// 17//
|
||||
f 2// 17// 1//
|
||||
f 3// 5// 9//
|
||||
f 3// 12// 7//
|
||||
f 3// 17// 4//
|
||||
f 4// 6// 3//
|
||||
f 4// 13// 9//
|
||||
f 4// 17// 7//
|
||||
f 5// 3// 6//
|
||||
f 5// 6// 8//
|
||||
f 6// 11// 8//
|
||||
f 7// 13// 4//
|
||||
f 7// 15// 13//
|
||||
f 7// 16// 3//
|
||||
f 8// 10// 5//
|
||||
f 8// 14// 10//
|
||||
f 9// 5// 10//
|
||||
f 9// 6// 4//
|
||||
f 9// 12// 3//
|
||||
f 9// 14// 11//
|
||||
f 9// 15// 12//
|
||||
f 10// 14// 9//
|
||||
f 11// 6// 9//
|
||||
f 11// 14// 8//
|
||||
f 12// 15// 7//
|
||||
f 13// 15// 9//
|
||||
f 16// 7// 1//
|
||||
f 16// 17// 3//
|
||||
@@ -0,0 +1,54 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib hound_run_2.mtl
|
||||
o Cube1
|
||||
#17 vertices, 30 faces
|
||||
v -0.27414249 0.32374765 1.53588567
|
||||
v 0.24584539 0.32374765 1.53588567
|
||||
v -0.34489706 0.87178707 -2.8008988e-2
|
||||
v 0.31659996 0.87178707 -2.8008988e-2
|
||||
v -0.44658541 0.48701540 -1.63347780
|
||||
v 0.41828831 0.48701540 -1.63347780
|
||||
v -1.4148550e-2 -0.20861028 0.73830352
|
||||
v -1.4148550e-2 0.11202559 -2.31304633
|
||||
v -1.4148550e-2 -5.1940403e-2 -0.38919459
|
||||
v -0.43375565 -0.70455128 -2.48896361
|
||||
v 0.40545855 -0.68576637 -2.05640756
|
||||
v -0.60915295 -0.59619234 1.41092021
|
||||
v 0.58085585 -0.54855918 1.19422288
|
||||
v -1.4148550e-2 0.17202802 -1.24940840
|
||||
v -1.4148550e-2 0.12242222 0.24281474
|
||||
v -0.45093850 0.71024542 1.60004015
|
||||
v 0.42264140 0.71024542 1.60004015
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 7// 2//
|
||||
f 1// 17// 16//
|
||||
f 2// 7// 17//
|
||||
f 2// 17// 1//
|
||||
f 3// 5// 9//
|
||||
f 3// 12// 7//
|
||||
f 3// 17// 4//
|
||||
f 4// 6// 3//
|
||||
f 4// 13// 9//
|
||||
f 4// 17// 7//
|
||||
f 5// 3// 6//
|
||||
f 5// 6// 8//
|
||||
f 6// 11// 8//
|
||||
f 7// 13// 4//
|
||||
f 7// 15// 13//
|
||||
f 7// 16// 3//
|
||||
f 8// 10// 5//
|
||||
f 8// 14// 10//
|
||||
f 9// 5// 10//
|
||||
f 9// 6// 4//
|
||||
f 9// 12// 3//
|
||||
f 9// 14// 11//
|
||||
f 9// 15// 12//
|
||||
f 10// 14// 9//
|
||||
f 11// 6// 9//
|
||||
f 11// 14// 8//
|
||||
f 12// 15// 7//
|
||||
f 13// 15// 9//
|
||||
f 16// 7// 1//
|
||||
f 16// 17// 3//
|
||||
@@ -0,0 +1,46 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib nailgun.mtl
|
||||
o Cube1
|
||||
#17 vertices, 22 faces
|
||||
v -0.49808545 7.0738526e-4 -0.35027558
|
||||
v 0.73207036 7.0738526e-4 -0.35027558
|
||||
v -0.49808545 7.0738526e-4 0.23452442
|
||||
v 0.73207036 7.0738526e-4 0.23452442
|
||||
v 0.73207036 -0.70631483 -5.7875579e-2
|
||||
v 0.93949391 -0.16061271 0.49790863
|
||||
v -1.14322716 -0.16061271 0.49790863
|
||||
v 0.93949391 0.26298729 0.49790863
|
||||
v -1.14322716 0.26298729 0.49790863
|
||||
v 0.93949391 3.7539161e-2 9.6285961e-2
|
||||
v -1.14322716 3.7539161e-2 9.6285961e-2
|
||||
v 0.93949391 -0.16061271 -0.61738635
|
||||
v -1.14322716 -0.16061271 -0.61738635
|
||||
v 0.93949391 0.26298729 -0.61738635
|
||||
v -1.14322716 0.26298729 -0.61738635
|
||||
v 0.93949391 3.7539161e-2 -0.21576367
|
||||
v -1.14322716 3.7539161e-2 -0.21576367
|
||||
g Cube1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 3// 2//
|
||||
f 1// 5// 3//
|
||||
f 2// 5// 1//
|
||||
f 3// 4// 2//
|
||||
f 3// 5// 4//
|
||||
f 4// 5// 2//
|
||||
f 6// 8// 7//
|
||||
f 6// 10// 8//
|
||||
f 7// 10// 6//
|
||||
f 7// 11// 10//
|
||||
f 8// 9// 7//
|
||||
f 8// 10// 9//
|
||||
f 9// 11// 7//
|
||||
f 10// 11// 9//
|
||||
f 12// 15// 14//
|
||||
f 12// 17// 13//
|
||||
f 13// 15// 12//
|
||||
f 13// 17// 15//
|
||||
f 14// 16// 12//
|
||||
f 14// 17// 16//
|
||||
f 15// 17// 14//
|
||||
f 16// 17// 12//
|
||||
@@ -0,0 +1,55 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib q.mtl
|
||||
o entity0_brush3
|
||||
#25 vertices, 23 faces
|
||||
v -1.47660400 0.89508300 -2.93151200
|
||||
v -4.41993200 2.36674700 -2.93151100
|
||||
v 1.46672400 0.89508300 -2.93151200
|
||||
v 4.41005200 2.36674700 -2.93151100
|
||||
v 1.46672400 -2.78407800 -2.93151200
|
||||
v 1.46672400 -7.19907000 -2.93151200
|
||||
v 7.35338000 -0.57658200 -2.93151200
|
||||
v 10.29670800 -2.78407800 -2.93151200
|
||||
v 7.35338000 -0.57658200 2.95514500
|
||||
v 5.88171600 15.61172400 -2.93151100
|
||||
v 11.03254000 6.78173800 -2.93151100
|
||||
v 11.03254000 6.78173800 2.95514500
|
||||
v 13.24003700 7.51757000 -2.93151100
|
||||
v -7.36326000 -0.57658200 -2.93151200
|
||||
v -10.30658800 -2.78407800 -2.93151200
|
||||
v -7.36326000 -0.57658200 2.95514500
|
||||
v -1.47660400 -7.19907000 -2.93151200
|
||||
v -1.47660400 -2.78407800 -2.93151200
|
||||
v -13.24991700 7.51757000 -2.93151100
|
||||
v -11.04242000 6.78173800 2.95514500
|
||||
v -11.04242000 6.78173800 -2.93151100
|
||||
v -5.89159600 15.61172400 -2.93151100
|
||||
v -1.47660400 -9.40656600 -2.93151200
|
||||
v -4.9400000e-3 -18.23655100 -2.93151200
|
||||
v 1.46672400 -9.40656600 -2.93151200
|
||||
g entity0_brush3_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 4// 3//
|
||||
f 1// 25// 23//
|
||||
f 2// 4// 1//
|
||||
f 3// 25// 1//
|
||||
f 5// 7// 6//
|
||||
f 5// 9// 7//
|
||||
f 7// 8// 6//
|
||||
f 7// 11// 8//
|
||||
f 9// 11// 7//
|
||||
f 9// 12// 11//
|
||||
f 10// 13// 11//
|
||||
f 11// 12// 10//
|
||||
f 11// 13// 8//
|
||||
f 14// 17// 15//
|
||||
f 14// 18// 17//
|
||||
f 14// 20// 16//
|
||||
f 14// 21// 20//
|
||||
f 15// 21// 14//
|
||||
f 16// 18// 14//
|
||||
f 19// 21// 15//
|
||||
f 19// 22// 21//
|
||||
f 21// 22// 20//
|
||||
f 23// 25// 24//
|
||||
@@ -0,0 +1,27 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib torch.mtl
|
||||
o cone2
|
||||
#4 vertices, 3 faces
|
||||
v 0.56160000 0.93902222 4.8672177e-17
|
||||
v -0.28080000 0.93902222 0.48635987
|
||||
v -0.28080000 0.93902222 -0.48635987
|
||||
v 0.0000000e+0 2.15875556 0.0000000e+0
|
||||
g cone2_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 4// 2//
|
||||
f 2// 4// 3//
|
||||
f 3// 4// 1//
|
||||
o cone1
|
||||
#4 vertices, 4 faces
|
||||
v 1.00000000 1.00000000 0.0000000e+0
|
||||
v -0.50000000 1.00000000 0.86602540
|
||||
v -0.50000000 1.00000000 -0.86602540
|
||||
v 0.0000000e+0 -1.00000000 0.0000000e+0
|
||||
g cone1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 5// 7// 6//
|
||||
f 5// 8// 7//
|
||||
f 6// 8// 5//
|
||||
f 7// 8// 6//
|
||||
@@ -0,0 +1,27 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib torch2.mtl
|
||||
o cone2
|
||||
#4 vertices, 3 faces
|
||||
v 0.56160000 0.93902222 4.8672177e-17
|
||||
v -0.28080000 0.93902222 0.48635987
|
||||
v -0.28080000 0.93902222 -0.48635987
|
||||
v 0.37141710 2.34754042 -0.37242647
|
||||
g cone2_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 4// 2//
|
||||
f 2// 4// 3//
|
||||
f 3// 4// 1//
|
||||
o cone1
|
||||
#4 vertices, 4 faces
|
||||
v 1.00000000 1.00000000 0.0000000e+0
|
||||
v -0.50000000 1.00000000 0.86602540
|
||||
v -0.50000000 1.00000000 -0.86602540
|
||||
v 0.0000000e+0 -1.00000000 0.0000000e+0
|
||||
g cone1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 5// 7// 6//
|
||||
f 5// 8// 7//
|
||||
f 6// 8// 5//
|
||||
f 7// 8// 6//
|
||||
@@ -0,0 +1,27 @@
|
||||
# Exported from Wings 3D 2.1.7
|
||||
mtllib torch_3.mtl
|
||||
o cone2
|
||||
#4 vertices, 3 faces
|
||||
v 0.56160000 0.93902222 4.8672177e-17
|
||||
v -0.28080000 0.93902222 0.48635987
|
||||
v -0.28080000 0.93902222 -0.48635987
|
||||
v 0.10185419 1.89578758 0.31045814
|
||||
g cone2_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 4// 2//
|
||||
f 2// 4// 3//
|
||||
f 3// 4// 1//
|
||||
o cone1
|
||||
#4 vertices, 4 faces
|
||||
v 1.00000000 1.00000000 0.0000000e+0
|
||||
v -0.50000000 1.00000000 0.86602540
|
||||
v -0.50000000 1.00000000 -0.86602540
|
||||
v 0.0000000e+0 -1.00000000 0.0000000e+0
|
||||
g cone1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 5// 7// 6//
|
||||
f 5// 8// 7//
|
||||
f 6// 8// 5//
|
||||
f 7// 8// 6//
|
||||
@@ -0,0 +1,111 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib unit_fire.mtl
|
||||
o idle
|
||||
#36 vertices, 68 faces
|
||||
v -9.7072365e-2 0.56526052 0.14813200
|
||||
v -5.1174828e-3 0.58241863 3.6241454e-2
|
||||
v -7.3432045e-2 0.41571136 8.8730558e-2
|
||||
v -2.7773366e-3 0.38195589 0.18768463
|
||||
v -0.16457846 0.28956454 0.14866615
|
||||
v -0.22256966 0.36820969 6.5821860e-2
|
||||
v -2.2042426e-3 0.20761891 0.17635056
|
||||
v -0.16376325 0.24789118 2.7255653e-2
|
||||
v -3.2828151e-3 -5.9558653e-2 -3.2466908e-2
|
||||
v -0.11705512 -1.8998070e-2 0.10033982
|
||||
v -5.2468113e-2 -0.37762396 0.11261478
|
||||
v -0.12733850 -0.38368582 0.11398771
|
||||
v -0.11232770 -0.31817914 4.0267488e-2
|
||||
v -0.18392516 0.29905284 0.36931274
|
||||
v -0.21375240 0.22504257 0.28526370
|
||||
v -0.16363894 0.20062898 0.33478576
|
||||
v -3.1666221e-3 0.58110829 0.22659559
|
||||
v -4.3491030e-3 0.40731243 4.3715603e-2
|
||||
v -1.6209207e-3 -0.12923391 0.10318519
|
||||
v -0.13664447 0.22269181 0.71114277
|
||||
v -6.2110567e-2 -0.72441694 1.6821488e-2
|
||||
v -4.2262828e-3 0.60741476 0.13309524
|
||||
v 8.9237988e-2 0.56599678 0.14622765
|
||||
v 6.5570994e-2 0.41626067 8.7309755e-2
|
||||
v 7.8519940e-2 0.28988820 0.20138750
|
||||
v 0.14416942 0.38159031 0.14693994
|
||||
v 0.17385655 0.30958720 9.0735796e-2
|
||||
v 8.1999016e-2 -1.8089508e-2 9.1851922e-2
|
||||
v 5.1369741e-2 -0.37721362 0.11155341
|
||||
v 0.12629811 -0.38268350 0.11139519
|
||||
v 0.10926638 -0.31730344 3.8002490e-2
|
||||
v 4.7935402e-2 0.20296119 0.35368779
|
||||
v 9.7607717e-2 0.13718946 0.30493926
|
||||
v 2.5761572e-2 0.15405508 0.25758703
|
||||
v -0.28779708 0.20832952 0.44720995
|
||||
v 6.1792415e-2 -0.72392731 1.5555028e-2
|
||||
g idle_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 22// 2//
|
||||
f 2// 3// 1//
|
||||
f 2// 24// 18//
|
||||
f 3// 4// 1//
|
||||
f 3// 8// 6//
|
||||
f 4// 23// 17//
|
||||
f 5// 3// 6//
|
||||
f 5// 4// 3//
|
||||
f 5// 10// 7//
|
||||
f 6// 8// 15//
|
||||
f 6// 14// 5//
|
||||
f 7// 4// 5//
|
||||
f 7// 25// 4//
|
||||
f 7// 28// 25//
|
||||
f 8// 9// 10//
|
||||
f 8// 14// 16//
|
||||
f 8// 18// 9//
|
||||
f 9// 13// 10//
|
||||
f 9// 29// 19//
|
||||
f 10// 5// 8//
|
||||
f 10// 19// 7//
|
||||
f 11// 10// 12//
|
||||
f 11// 12// 21//
|
||||
f 11// 19// 10//
|
||||
f 11// 21// 13//
|
||||
f 12// 10// 13//
|
||||
f 13// 9// 11//
|
||||
f 13// 21// 12//
|
||||
f 14// 6// 15//
|
||||
f 14// 8// 5//
|
||||
f 15// 20// 14//
|
||||
f 16// 15// 8//
|
||||
f 16// 20// 15//
|
||||
f 17// 1// 4//
|
||||
f 17// 22// 1//
|
||||
f 17// 23// 22//
|
||||
f 18// 3// 2//
|
||||
f 18// 8// 3//
|
||||
f 18// 26// 27//
|
||||
f 18// 27// 9//
|
||||
f 19// 11// 9//
|
||||
f 19// 28// 7//
|
||||
f 20// 16// 14//
|
||||
f 22// 23// 2//
|
||||
f 23// 4// 24//
|
||||
f 23// 24// 2//
|
||||
f 24// 4// 25//
|
||||
f 25// 27// 32//
|
||||
f 25// 32// 26//
|
||||
f 26// 18// 24//
|
||||
f 26// 24// 25//
|
||||
f 27// 25// 28//
|
||||
f 27// 26// 34//
|
||||
f 28// 9// 27//
|
||||
f 28// 19// 29//
|
||||
f 28// 31// 9//
|
||||
f 29// 9// 31//
|
||||
f 30// 28// 29//
|
||||
f 30// 36// 31//
|
||||
f 31// 28// 30//
|
||||
f 31// 36// 29//
|
||||
f 32// 34// 35//
|
||||
f 32// 35// 33//
|
||||
f 33// 26// 32//
|
||||
f 33// 34// 26//
|
||||
f 33// 35// 34//
|
||||
f 34// 32// 27//
|
||||
f 36// 30// 29//
|
||||
@@ -0,0 +1,111 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib u42-idle.mtl
|
||||
o idle
|
||||
#36 vertices, 68 faces
|
||||
v -9.7072365e-2 0.56526052 0.14813200
|
||||
v -5.1174828e-3 0.58241863 3.6241454e-2
|
||||
v -7.3432045e-2 0.41571136 8.8730558e-2
|
||||
v -2.7773366e-3 0.38195589 0.18768463
|
||||
v -0.16457846 0.28956454 0.14866615
|
||||
v -0.22256966 0.36820969 6.5821860e-2
|
||||
v -2.2042426e-3 0.20761891 0.17635056
|
||||
v -0.12240829 0.27200369 1.9776168e-2
|
||||
v -3.2828151e-3 -5.9558653e-2 -3.2466908e-2
|
||||
v -0.11705512 -1.8998070e-2 0.10033982
|
||||
v -5.2468113e-2 -0.37762396 0.11261478
|
||||
v -0.12733850 -0.38368582 0.11398771
|
||||
v -0.11232770 -0.31817914 4.0267488e-2
|
||||
v -0.26195311 6.1200154e-2 8.9171027e-2
|
||||
v -0.27269328 7.0984903e-2 2.8453086e-2
|
||||
v -0.19946210 8.9864434e-2 3.4271377e-3
|
||||
v -3.1666221e-3 0.58110829 0.22659559
|
||||
v -4.3491030e-3 0.40731243 4.3715603e-2
|
||||
v -1.6209207e-3 -0.12923391 0.10318519
|
||||
v -0.26237064 -0.27025472 0.23936610
|
||||
v -6.2110567e-2 -0.72441694 1.6821488e-2
|
||||
v -4.2262828e-3 0.60741476 0.13309524
|
||||
v 8.9237988e-2 0.56599678 0.14622765
|
||||
v 6.5570994e-2 0.41626067 8.7309755e-2
|
||||
v 0.15891751 0.29084293 0.14535957
|
||||
v 0.21457992 0.36993722 6.1353587e-2
|
||||
v 0.11426169 0.27293896 1.7357074e-2
|
||||
v 0.11285624 -1.8089508e-2 9.7989805e-2
|
||||
v 5.1369741e-2 -0.37721362 0.11155341
|
||||
v 0.12629811 -0.38268350 0.11139519
|
||||
v 0.10926638 -0.31730344 3.8002490e-2
|
||||
v 0.25685736 6.3250386e-2 8.3868066e-2
|
||||
v 0.26627654 7.3114801e-2 2.2944069e-2
|
||||
v 0.19240220 9.1413002e-2 -5.7825739e-4
|
||||
v 0.26296420 -0.26817871 0.23399645
|
||||
v 6.1792415e-2 -0.72392731 1.5555028e-2
|
||||
g idle_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 22// 2//
|
||||
f 2// 3// 1//
|
||||
f 2// 24// 18//
|
||||
f 3// 4// 1//
|
||||
f 3// 8// 6//
|
||||
f 4// 23// 17//
|
||||
f 5// 3// 6//
|
||||
f 5// 4// 3//
|
||||
f 5// 10// 7//
|
||||
f 6// 8// 15//
|
||||
f 6// 14// 5//
|
||||
f 7// 4// 5//
|
||||
f 7// 25// 4//
|
||||
f 7// 28// 25//
|
||||
f 8// 9// 10//
|
||||
f 8// 14// 16//
|
||||
f 8// 18// 9//
|
||||
f 9// 13// 10//
|
||||
f 9// 29// 19//
|
||||
f 10// 5// 8//
|
||||
f 10// 19// 7//
|
||||
f 11// 10// 12//
|
||||
f 11// 12// 21//
|
||||
f 11// 19// 10//
|
||||
f 11// 21// 13//
|
||||
f 12// 10// 13//
|
||||
f 13// 9// 11//
|
||||
f 13// 21// 12//
|
||||
f 14// 6// 15//
|
||||
f 14// 8// 5//
|
||||
f 15// 20// 14//
|
||||
f 16// 15// 8//
|
||||
f 16// 20// 15//
|
||||
f 17// 1// 4//
|
||||
f 17// 22// 1//
|
||||
f 17// 23// 22//
|
||||
f 18// 3// 2//
|
||||
f 18// 8// 3//
|
||||
f 18// 26// 27//
|
||||
f 18// 27// 9//
|
||||
f 19// 11// 9//
|
||||
f 19// 28// 7//
|
||||
f 20// 16// 14//
|
||||
f 22// 23// 2//
|
||||
f 23// 4// 24//
|
||||
f 23// 24// 2//
|
||||
f 24// 4// 25//
|
||||
f 25// 27// 32//
|
||||
f 25// 32// 26//
|
||||
f 26// 18// 24//
|
||||
f 26// 24// 25//
|
||||
f 27// 25// 28//
|
||||
f 27// 26// 34//
|
||||
f 28// 9// 27//
|
||||
f 28// 19// 29//
|
||||
f 28// 31// 9//
|
||||
f 29// 9// 31//
|
||||
f 30// 28// 29//
|
||||
f 30// 36// 31//
|
||||
f 31// 28// 30//
|
||||
f 31// 36// 29//
|
||||
f 32// 34// 35//
|
||||
f 32// 35// 33//
|
||||
f 33// 26// 32//
|
||||
f 33// 34// 26//
|
||||
f 33// 35// 34//
|
||||
f 34// 32// 27//
|
||||
f 36// 30// 29//
|
||||
@@ -0,0 +1,111 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib u42-run-1.mtl
|
||||
o run_1
|
||||
#36 vertices, 68 faces
|
||||
v -9.5272919e-2 0.58320065 0.23895644
|
||||
v -3.3180374e-3 0.62435371 0.13350350
|
||||
v -7.1632599e-2 0.45021114 0.14836243
|
||||
v -9.7789112e-4 0.39568245 0.23756984
|
||||
v -0.17307984 0.32466544 0.13174644
|
||||
v -0.20495298 0.42235179 5.5243521e-2
|
||||
v -2.6982217e-2 0.25733845 0.18552924
|
||||
v -9.5805943e-2 0.33183820 1.9155900e-2
|
||||
v -3.2828150e-3 1.1936972e-2 -2.9445966e-2
|
||||
v -0.11705512 5.2497554e-2 0.10336076
|
||||
v -5.5121527e-2 -0.21726415 0.30762026
|
||||
v -0.12999191 -0.21814619 0.31377274
|
||||
v -0.11393341 -0.25917247 0.23816510
|
||||
v -0.23980691 0.24937442 -6.0965392e-2
|
||||
v -0.23273167 0.23590209 -0.12151453
|
||||
v -0.15540189 0.25233529 -0.13129183
|
||||
v -1.3671766e-3 0.58155046 0.31898745
|
||||
v -2.5496575e-3 0.45183419 0.10259941
|
||||
v -1.6209207e-3 -5.7738288e-2 0.10620614
|
||||
v -0.22503228 -2.6466381e-2 0.19543165
|
||||
v -6.2140773e-2 -0.49248177 0.54917297
|
||||
v -2.4268373e-3 0.62761985 0.23347747
|
||||
v 9.1037433e-2 0.58433460 0.23725856
|
||||
v 6.7370439e-2 0.45105716 0.14709568
|
||||
v 0.13784712 0.30642002 0.21923207
|
||||
v 0.21521175 0.39769622 0.17346542
|
||||
v 0.13166854 0.31848984 8.3160476e-2
|
||||
v 0.11285624 5.3406116e-2 0.10101075
|
||||
v 5.6280724e-2 -0.26007502 -2.0635962e-2
|
||||
v 0.13120909 -0.26515311 -2.2674963e-2
|
||||
v 0.11417736 -0.17843586 -6.8947620e-2
|
||||
v 0.21505817 0.24739267 0.31347123
|
||||
v 0.24150950 0.20354683 0.27775525
|
||||
v 0.18039399 0.17439735 0.24201011
|
||||
v 8.5574373e-2 0.14637362 0.54237953
|
||||
v 8.9212783e-2 -0.30204016 -0.43882211
|
||||
g run_1_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 22// 2//
|
||||
f 2// 3// 1//
|
||||
f 2// 24// 18//
|
||||
f 3// 4// 1//
|
||||
f 3// 8// 6//
|
||||
f 4// 23// 17//
|
||||
f 5// 3// 6//
|
||||
f 5// 4// 3//
|
||||
f 5// 10// 7//
|
||||
f 6// 8// 15//
|
||||
f 6// 14// 5//
|
||||
f 7// 4// 5//
|
||||
f 7// 25// 4//
|
||||
f 7// 28// 25//
|
||||
f 8// 9// 10//
|
||||
f 8// 14// 16//
|
||||
f 8// 18// 9//
|
||||
f 9// 13// 10//
|
||||
f 9// 29// 19//
|
||||
f 10// 5// 8//
|
||||
f 10// 19// 7//
|
||||
f 11// 10// 12//
|
||||
f 11// 12// 21//
|
||||
f 11// 19// 10//
|
||||
f 11// 21// 13//
|
||||
f 12// 10// 13//
|
||||
f 13// 9// 11//
|
||||
f 13// 21// 12//
|
||||
f 14// 6// 15//
|
||||
f 14// 8// 5//
|
||||
f 15// 20// 14//
|
||||
f 16// 15// 8//
|
||||
f 16// 20// 15//
|
||||
f 17// 1// 4//
|
||||
f 17// 22// 1//
|
||||
f 17// 23// 22//
|
||||
f 18// 3// 2//
|
||||
f 18// 8// 3//
|
||||
f 18// 26// 27//
|
||||
f 18// 27// 9//
|
||||
f 19// 11// 9//
|
||||
f 19// 28// 7//
|
||||
f 20// 16// 14//
|
||||
f 22// 23// 2//
|
||||
f 23// 4// 24//
|
||||
f 23// 24// 2//
|
||||
f 24// 4// 25//
|
||||
f 25// 27// 32//
|
||||
f 25// 32// 26//
|
||||
f 26// 18// 24//
|
||||
f 26// 24// 25//
|
||||
f 27// 25// 28//
|
||||
f 27// 26// 34//
|
||||
f 28// 9// 27//
|
||||
f 28// 19// 29//
|
||||
f 29// 9// 31//
|
||||
f 30// 9// 28//
|
||||
f 30// 28// 29//
|
||||
f 30// 36// 31//
|
||||
f 31// 9// 30//
|
||||
f 31// 36// 29//
|
||||
f 32// 34// 35//
|
||||
f 32// 35// 33//
|
||||
f 33// 26// 32//
|
||||
f 33// 34// 26//
|
||||
f 33// 35// 34//
|
||||
f 34// 32// 27//
|
||||
f 36// 30// 29//
|
||||
@@ -0,0 +1,111 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib u42-run-2.mtl
|
||||
o run_2
|
||||
#36 vertices, 68 faces
|
||||
v -9.4991472e-2 0.52373540 0.23964533
|
||||
v -3.0365897e-3 0.56488846 0.13419239
|
||||
v -7.1351151e-2 0.39074589 0.14905133
|
||||
v -6.9644348e-4 0.33621720 0.23825873
|
||||
v -0.17267823 0.26520019 0.15406434
|
||||
v -0.21436437 0.36288654 8.2434335e-2
|
||||
v -2.0762743e-2 0.19787320 0.18810538
|
||||
v -0.11093143 0.27237295 3.2264433e-2
|
||||
v -3.0013674e-3 -4.7528279e-2 -2.8757072e-2
|
||||
v -0.11677367 -6.9676967e-3 0.10404965
|
||||
v -6.1941435e-2 -0.36213984 0.21486963
|
||||
v -0.13681182 -0.36634357 0.21944779
|
||||
v -0.12075331 -0.35747908 0.13388442
|
||||
v -0.27214113 0.16564009 1.8179960e-2
|
||||
v -0.27311477 0.14229232 -3.9713862e-2
|
||||
v -0.19775045 0.15521696 -6.2045768e-2
|
||||
v -1.0857290e-3 0.52208521 0.31967635
|
||||
v -2.2682098e-3 0.39236894 0.10328831
|
||||
v -1.3394730e-3 -0.11720354 0.10689503
|
||||
v -0.21276320 -3.2220363e-2 0.25209224
|
||||
v -9.3144493e-2 -0.70483668 0.17970538
|
||||
v -2.1453897e-3 0.56815460 0.23416636
|
||||
v 9.1318881e-2 0.52486934 0.23794745
|
||||
v 6.7651887e-2 0.39159191 0.14778457
|
||||
v 0.14707201 0.24695477 0.19977100
|
||||
v 0.21772350 0.33823097 0.14419908
|
||||
v 0.12299816 0.25902459 6.5703468e-2
|
||||
v 0.11313769 -6.0591343e-3 0.10169964
|
||||
v 5.6562172e-2 -0.34172597 8.3847930e-2
|
||||
v 0.13149054 -0.34717436 8.4357499e-2
|
||||
v 0.11445881 -0.29122596 3.5440300e-3
|
||||
v 0.25704387 0.13904658 0.16957344
|
||||
v 0.27855275 8.9755721e-2 0.13786319
|
||||
v 0.21325613 5.6754116e-2 0.11528535
|
||||
v 0.15532922 -3.1631277e-2 0.40939898
|
||||
v 8.9494231e-2 -0.52086355 -0.28286119
|
||||
g run_2_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 22// 2//
|
||||
f 2// 3// 1//
|
||||
f 2// 24// 18//
|
||||
f 3// 4// 1//
|
||||
f 3// 8// 6//
|
||||
f 4// 23// 17//
|
||||
f 5// 3// 6//
|
||||
f 5// 4// 3//
|
||||
f 5// 10// 7//
|
||||
f 6// 8// 15//
|
||||
f 6// 14// 5//
|
||||
f 7// 4// 5//
|
||||
f 7// 25// 4//
|
||||
f 7// 28// 25//
|
||||
f 8// 9// 10//
|
||||
f 8// 14// 16//
|
||||
f 8// 18// 9//
|
||||
f 9// 13// 10//
|
||||
f 9// 29// 19//
|
||||
f 10// 5// 8//
|
||||
f 10// 19// 7//
|
||||
f 11// 10// 12//
|
||||
f 11// 12// 21//
|
||||
f 11// 19// 10//
|
||||
f 11// 21// 13//
|
||||
f 12// 10// 13//
|
||||
f 13// 9// 11//
|
||||
f 13// 21// 12//
|
||||
f 14// 6// 15//
|
||||
f 14// 8// 5//
|
||||
f 15// 20// 14//
|
||||
f 16// 15// 8//
|
||||
f 16// 20// 15//
|
||||
f 17// 1// 4//
|
||||
f 17// 22// 1//
|
||||
f 17// 23// 22//
|
||||
f 18// 3// 2//
|
||||
f 18// 8// 3//
|
||||
f 18// 26// 27//
|
||||
f 18// 27// 9//
|
||||
f 19// 11// 9//
|
||||
f 19// 28// 7//
|
||||
f 20// 16// 14//
|
||||
f 22// 23// 2//
|
||||
f 23// 4// 24//
|
||||
f 23// 24// 2//
|
||||
f 24// 4// 25//
|
||||
f 25// 27// 32//
|
||||
f 25// 32// 26//
|
||||
f 26// 18// 24//
|
||||
f 26// 24// 25//
|
||||
f 27// 25// 28//
|
||||
f 27// 26// 34//
|
||||
f 28// 9// 27//
|
||||
f 28// 19// 29//
|
||||
f 29// 9// 31//
|
||||
f 30// 9// 28//
|
||||
f 30// 28// 29//
|
||||
f 30// 36// 31//
|
||||
f 31// 9// 30//
|
||||
f 31// 36// 29//
|
||||
f 32// 34// 35//
|
||||
f 32// 35// 33//
|
||||
f 33// 26// 32//
|
||||
f 33// 34// 26//
|
||||
f 33// 35// 34//
|
||||
f 34// 32// 27//
|
||||
f 36// 30// 29//
|
||||
@@ -0,0 +1,111 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib u42-run-3.mtl
|
||||
o run_3
|
||||
#36 vertices, 68 faces
|
||||
v -9.7534954e-2 0.58537971 0.23727152
|
||||
v -5.5800717e-3 0.62207596 0.13434820
|
||||
v -7.3894633e-2 0.44530355 0.15807461
|
||||
v -3.2399255e-3 0.39839816 0.25151563
|
||||
v -0.14811650 0.30785729 0.23172695
|
||||
v -0.22184769 0.39518773 0.17386227
|
||||
v 2.9874070e-2 0.25219372 0.18896602
|
||||
v -0.13324204 0.30880016 9.5796106e-2
|
||||
v -3.0261434e-3 1.2834357e-2 -2.8933793e-2
|
||||
v -0.10962990 5.0988036e-2 0.10517160
|
||||
v -4.1698825e-2 -0.26559037 -1.8795665e-2
|
||||
v -0.11656921 -0.27177960 -1.9365307e-2
|
||||
v -0.10155841 -0.18668084 -6.9205025e-2
|
||||
v -0.24752637 0.24555925 0.31401265
|
||||
v -0.27201893 0.22587890 0.26943932
|
||||
v -0.20708582 0.17323236 0.24465303
|
||||
v -3.6292110e-3 0.58033840 0.31604327
|
||||
v -4.8116918e-3 0.45317336 0.10171045
|
||||
v 4.8726959e-5 -5.7632780e-2 0.10082565
|
||||
v -0.15387665 0.14921342 0.53804817
|
||||
v -8.6656471e-2 -0.30440046 -0.43683459
|
||||
v -4.6888717e-3 0.62918786 0.22811015
|
||||
v 8.8775399e-2 0.58636824 0.23548505
|
||||
v 6.5108405e-2 0.45331084 0.14611670
|
||||
v 0.17212974 0.33058228 0.13766338
|
||||
v 0.20940429 0.42167997 5.5669264e-2
|
||||
v 0.10220107 0.32864714 2.0166273e-2
|
||||
v 0.11389002 5.2669771e-2 9.9938702e-2
|
||||
v 5.2010784e-2 -0.22039388 0.29971756
|
||||
v 0.12924803 -0.21231946 0.30276019
|
||||
v 0.11527123 -0.26319363 0.23743150
|
||||
v 0.22868222 0.25165315 -6.1196965e-2
|
||||
v 0.22720815 0.23037277 -0.11930067
|
||||
v 0.15008199 0.25256058 -0.13060470
|
||||
v 0.21252622 -3.0157464e-2 0.20240516
|
||||
v 6.2049086e-2 -0.49335414 0.55060042
|
||||
g run_3_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 22// 2//
|
||||
f 2// 3// 1//
|
||||
f 2// 24// 18//
|
||||
f 3// 4// 1//
|
||||
f 3// 8// 6//
|
||||
f 4// 23// 17//
|
||||
f 5// 3// 6//
|
||||
f 5// 4// 3//
|
||||
f 5// 10// 7//
|
||||
f 6// 8// 15//
|
||||
f 6// 14// 5//
|
||||
f 7// 4// 5//
|
||||
f 7// 25// 4//
|
||||
f 7// 28// 25//
|
||||
f 8// 9// 10//
|
||||
f 8// 14// 16//
|
||||
f 8// 18// 9//
|
||||
f 9// 13// 10//
|
||||
f 9// 29// 19//
|
||||
f 10// 5// 8//
|
||||
f 10// 19// 7//
|
||||
f 11// 10// 12//
|
||||
f 11// 12// 21//
|
||||
f 11// 19// 10//
|
||||
f 11// 21// 13//
|
||||
f 12// 10// 13//
|
||||
f 13// 9// 11//
|
||||
f 13// 21// 12//
|
||||
f 14// 6// 15//
|
||||
f 14// 8// 5//
|
||||
f 15// 20// 14//
|
||||
f 16// 15// 8//
|
||||
f 16// 20// 15//
|
||||
f 17// 1// 4//
|
||||
f 17// 22// 1//
|
||||
f 17// 23// 22//
|
||||
f 18// 3// 2//
|
||||
f 18// 8// 3//
|
||||
f 18// 27// 9//
|
||||
f 19// 11// 9//
|
||||
f 19// 28// 7//
|
||||
f 20// 16// 14//
|
||||
f 22// 23// 2//
|
||||
f 23// 4// 24//
|
||||
f 23// 24// 2//
|
||||
f 24// 4// 25//
|
||||
f 24// 27// 18//
|
||||
f 25// 27// 32//
|
||||
f 25// 32// 26//
|
||||
f 26// 24// 25//
|
||||
f 26// 27// 24//
|
||||
f 27// 25// 28//
|
||||
f 27// 33// 34//
|
||||
f 28// 9// 27//
|
||||
f 28// 19// 29//
|
||||
f 28// 31// 9//
|
||||
f 29// 9// 31//
|
||||
f 30// 28// 29//
|
||||
f 30// 36// 31//
|
||||
f 31// 28// 30//
|
||||
f 31// 36// 29//
|
||||
f 32// 34// 35//
|
||||
f 32// 35// 33//
|
||||
f 33// 26// 32//
|
||||
f 33// 27// 26//
|
||||
f 33// 35// 34//
|
||||
f 34// 32// 27//
|
||||
f 36// 30// 29//
|
||||
@@ -0,0 +1,111 @@
|
||||
# Exported from Wings 3D 2.1.5
|
||||
mtllib u42-run-4.mtl
|
||||
o run_4
|
||||
#36 vertices, 68 faces
|
||||
v -8.7448640e-2 0.52260968 0.23811789
|
||||
v 1.1106415e-2 0.56619990 0.13601636
|
||||
v -5.6652628e-2 0.39253244 0.14723325
|
||||
v 4.7983532e-3 0.33685461 0.23791788
|
||||
v -0.14201056 0.24676130 0.19890273
|
||||
v -0.21395473 0.33766742 0.14321628
|
||||
v 1.5828108e-2 0.25132493 0.18909199
|
||||
v -0.11559322 0.25643607 6.3974881e-2
|
||||
v 5.8659423e-3 -4.6614671e-2 -2.8852696e-2
|
||||
v -0.12367586 5.0119248e-2 0.10529757
|
||||
v -5.9869043e-2 -0.34160511 8.3280232e-2
|
||||
v -0.13473943 -0.34779433 8.2710589e-2
|
||||
v -0.11085266 -0.29407513 4.8260947e-3
|
||||
v -0.25132952 0.13731816 0.17143274
|
||||
v -0.27232641 8.9198561e-2 0.13324630
|
||||
v -0.20953794 5.7890222e-2 0.11187209
|
||||
v 5.7439754e-3 0.52158520 0.32087826
|
||||
v 1.4994713e-2 0.38418936 0.11355618
|
||||
v 9.5050338e-3 -0.11737256 9.6571469e-2
|
||||
v -0.15147117 -2.8967763e-2 0.40656236
|
||||
v -8.6836875e-2 -0.51910125 -0.27711023
|
||||
v 8.1007774e-3 0.56742535 0.23507916
|
||||
v 0.10858180 0.52745008 0.23670572
|
||||
v 7.4975063e-2 0.38772831 0.14527201
|
||||
v 0.17898781 0.26745693 0.15584951
|
||||
v 0.22056911 0.36000702 8.3859511e-2
|
||||
v 0.11885495 0.26917230 2.9631907e-2
|
||||
v 9.9844063e-2 4.2294354e-2 9.3354108e-2
|
||||
v 6.9120406e-2 -0.36382724 0.20320527
|
||||
v 0.14171710 -0.36592997 0.21060239
|
||||
v 0.12317708 -0.35863673 0.13900796
|
||||
v 0.27620662 0.16435731 1.6758612e-2
|
||||
v 0.28008560 0.14336818 -3.9632239e-2
|
||||
v 0.20394231 0.15390316 -6.2704812e-2
|
||||
v 0.21981481 -3.0190650e-2 0.24883182
|
||||
v 9.2836181e-2 -0.69912263 0.18131087
|
||||
g run_4_default
|
||||
usemtl default
|
||||
s 1
|
||||
f 1// 22// 2//
|
||||
f 2// 3// 1//
|
||||
f 2// 24// 18//
|
||||
f 3// 4// 1//
|
||||
f 3// 8// 6//
|
||||
f 4// 23// 17//
|
||||
f 5// 3// 6//
|
||||
f 5// 4// 3//
|
||||
f 5// 10// 7//
|
||||
f 6// 8// 15//
|
||||
f 6// 14// 5//
|
||||
f 7// 4// 5//
|
||||
f 7// 25// 4//
|
||||
f 7// 28// 25//
|
||||
f 8// 9// 10//
|
||||
f 8// 14// 16//
|
||||
f 8// 18// 9//
|
||||
f 9// 13// 10//
|
||||
f 9// 29// 19//
|
||||
f 10// 5// 8//
|
||||
f 10// 19// 7//
|
||||
f 11// 10// 12//
|
||||
f 11// 12// 21//
|
||||
f 11// 19// 10//
|
||||
f 11// 21// 13//
|
||||
f 12// 10// 13//
|
||||
f 13// 9// 11//
|
||||
f 13// 21// 12//
|
||||
f 14// 6// 15//
|
||||
f 14// 8// 5//
|
||||
f 15// 20// 14//
|
||||
f 16// 15// 8//
|
||||
f 16// 20// 15//
|
||||
f 17// 1// 4//
|
||||
f 17// 22// 1//
|
||||
f 17// 23// 22//
|
||||
f 18// 3// 2//
|
||||
f 18// 8// 3//
|
||||
f 18// 26// 27//
|
||||
f 18// 27// 9//
|
||||
f 19// 11// 9//
|
||||
f 19// 28// 7//
|
||||
f 20// 16// 14//
|
||||
f 22// 23// 2//
|
||||
f 23// 4// 24//
|
||||
f 23// 24// 2//
|
||||
f 24// 4// 25//
|
||||
f 25// 27// 32//
|
||||
f 25// 32// 26//
|
||||
f 26// 18// 24//
|
||||
f 26// 24// 25//
|
||||
f 27// 25// 28//
|
||||
f 27// 26// 34//
|
||||
f 28// 9// 27//
|
||||
f 28// 19// 29//
|
||||
f 29// 9// 31//
|
||||
f 30// 9// 28//
|
||||
f 30// 28// 29//
|
||||
f 30// 36// 31//
|
||||
f 31// 9// 30//
|
||||
f 31// 36// 29//
|
||||
f 32// 34// 35//
|
||||
f 32// 35// 33//
|
||||
f 33// 26// 32//
|
||||
f 33// 34// 26//
|
||||
f 33// 35// 34//
|
||||
f 34// 32// 27//
|
||||
f 36// 30// 29//
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
@@ -0,0 +1,124 @@
|
||||
set -e
|
||||
|
||||
# Compile the pack_map
|
||||
gcc -std=c99 pack_map.c -lm -o pack_map
|
||||
|
||||
# Pack maps
|
||||
./pack_map assets/maps/m1.map build/m1.plb
|
||||
./pack_map assets/maps/m2.map build/m2.plb
|
||||
|
||||
# Concat all maps into one file
|
||||
cat \
|
||||
build/m1.plb \
|
||||
build/m2.plb \
|
||||
> build/l
|
||||
|
||||
# Pack models
|
||||
php pack_model.php assets/models/boulder.obj build/boulder.rmf
|
||||
php pack_model.php assets/models/q.obj build/q.rmf
|
||||
php pack_model.php assets/models/grenade.obj build/grenade.rmf
|
||||
php pack_model.php \
|
||||
assets/models/hound_run_1.obj \
|
||||
assets/models/hound_run_2.obj \
|
||||
build/hound.rmf
|
||||
php pack_model.php \
|
||||
assets/models/unit_idle.obj \
|
||||
assets/models/unit_run_1.obj \
|
||||
assets/models/unit_run_2.obj \
|
||||
assets/models/unit_run_3.obj \
|
||||
assets/models/unit_run_4.obj \
|
||||
assets/models/unit_fire.obj \
|
||||
build/unit.rmf
|
||||
|
||||
php pack_model.php assets/models/box.obj build/box.rmf
|
||||
php pack_model.php assets/models/nailgun.obj build/nailgun.rmf
|
||||
php pack_model.php \
|
||||
assets/models/torch_1.obj \
|
||||
assets/models/torch_2.obj \
|
||||
assets/models/torch_3.obj \
|
||||
build/torch.rmf
|
||||
|
||||
# Concat all models into one file
|
||||
cat \
|
||||
build/boulder.rmf \
|
||||
build/unit.rmf \
|
||||
build/grenade.rmf \
|
||||
build/q.rmf \
|
||||
build/hound.rmf \
|
||||
build/box.rmf \
|
||||
build/nailgun.rmf \
|
||||
build/torch.rmf \
|
||||
> build/m
|
||||
|
||||
|
||||
# Concat js Source
|
||||
cat \
|
||||
source/wrap_pre.js \
|
||||
source/document.js \
|
||||
source/textures.js \
|
||||
source/music.js \
|
||||
source/audio.js \
|
||||
source/input.js \
|
||||
source/ttt.js \
|
||||
source/math_utils.js \
|
||||
source/renderer.js \
|
||||
source/model.js \
|
||||
source/map.js \
|
||||
source/entity.js \
|
||||
source/entity_player.js \
|
||||
source/entity_door.js \
|
||||
source/entity_light.js \
|
||||
source/entity_torch.js \
|
||||
source/entity_barrel.js \
|
||||
source/entity_particle.js \
|
||||
source/entity_projectile_grenade.js \
|
||||
source/entity_projectile_nail.js \
|
||||
source/entity_projectile_plasma.js \
|
||||
source/entity_projectile_gib.js \
|
||||
source/entity_projectile_shell.js \
|
||||
source/entity_enemy.js \
|
||||
source/entity_enemy_grunt.js \
|
||||
source/entity_enemy_enforcer.js \
|
||||
source/entity_enemy_ogre.js \
|
||||
source/entity_enemy_zombie.js \
|
||||
source/entity_enemy_hound.js \
|
||||
source/entity_pickup.js \
|
||||
source/entity_pickup_key.js \
|
||||
source/entity_pickup_nailgun.js \
|
||||
source/entity_pickup_grenadelauncher.js \
|
||||
source/entity_pickup_health.js \
|
||||
source/entity_pickup_nails.js \
|
||||
source/entity_pickup_grenades.js \
|
||||
source/entity_trigger_level.js \
|
||||
source/weapons.js \
|
||||
source/game.js \
|
||||
source/main.js \
|
||||
source/wrap_post.js \
|
||||
> build/game.js
|
||||
|
||||
|
||||
# Compress WebGL calls, remove DEBUG[...]
|
||||
php pack_js.php build/game.js > build/game.packed.js
|
||||
|
||||
# Uglify JS
|
||||
npx uglify-js build/game.packed.js \
|
||||
--compress --mangle toplevel -c --beautify --mangle-props regex=/^_/ \
|
||||
-o build/game.min.beauty.js
|
||||
|
||||
npx uglify-js build/game.packed.js \
|
||||
--compress --mangle toplevel --mangle-props regex=/^_/ \
|
||||
-o build/game.min.js
|
||||
|
||||
npx roadroller -Zab14 -Zlr1113 -Zmd16 -Zpr14 -S0,1,2,3,6,7,13,21,25,50,235,333 build/game.min.js -o build/game.roadrolled.js
|
||||
|
||||
# Embed source into HTML
|
||||
sed -e '/GAME_SOURCE/{r build/game.roadrolled.js' -e 'd}' source/html_template.html > build/index.html
|
||||
|
||||
# Build ZIP
|
||||
rm -f -- build/game.zip
|
||||
cd build
|
||||
zip game.zip index.html l m
|
||||
cd ..
|
||||
|
||||
advzip -z -4 build/game.zip
|
||||
ls -la build/
|
||||
@@ -0,0 +1 @@
|
||||
dummy
|
||||
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Q1K3</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="d"></div>
|
||||
<script type="text/javascript" src="source/document.js"></script>
|
||||
<script type="text/javascript" src="source/ttt.js"></script>
|
||||
<script type="text/javascript" src="source/audio.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/math_utils.js"></script>
|
||||
<script type="text/javascript" src="source/model.js"></script>
|
||||
<script type="text/javascript" src="source/map.js"></script>
|
||||
<script type="text/javascript" src="source/renderer.js"></script>
|
||||
<script type="text/javascript" src="source/input.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/weapons.js"></script>
|
||||
<script type="text/javascript" src="source/entity.js"></script>
|
||||
<script type="text/javascript" src="source/entity_player.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/entity_light.js"></script>
|
||||
<script type="text/javascript" src="source/entity_torch.js"></script>
|
||||
<script type="text/javascript" src="source/entity_door.js"></script>
|
||||
<script type="text/javascript" src="source/entity_barrel.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/entity_particle.js"></script>
|
||||
<script type="text/javascript" src="source/entity_projectile_grenade.js"></script>
|
||||
<script type="text/javascript" src="source/entity_projectile_nail.js"></script>
|
||||
<script type="text/javascript" src="source/entity_projectile_shell.js"></script>
|
||||
<script type="text/javascript" src="source/entity_projectile_plasma.js"></script>
|
||||
<script type="text/javascript" src="source/entity_projectile_gib.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/entity_enemy.js"></script>
|
||||
<script type="text/javascript" src="source/entity_enemy_grunt.js"></script>
|
||||
<script type="text/javascript" src="source/entity_enemy_enforcer.js"></script>
|
||||
<script type="text/javascript" src="source/entity_enemy_ogre.js"></script>
|
||||
<script type="text/javascript" src="source/entity_enemy_zombie.js"></script>
|
||||
<script type="text/javascript" src="source/entity_enemy_hound.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/entity_pickup.js"></script>
|
||||
<script type="text/javascript" src="source/entity_pickup_key.js"></script>
|
||||
<script type="text/javascript" src="source/entity_pickup_nailgun.js"></script>
|
||||
<script type="text/javascript" src="source/entity_pickup_grenadelauncher.js"></script>
|
||||
<script type="text/javascript" src="source/entity_pickup_health.js"></script>
|
||||
<script type="text/javascript" src="source/entity_pickup_nails.js"></script>
|
||||
<script type="text/javascript" src="source/entity_pickup_grenades.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/entity_trigger_level.js"></script>
|
||||
|
||||
<script type="text/javascript" src="source/textures.js"></script>
|
||||
<script type="text/javascript" src="source/music.js"></script>
|
||||
<script type="text/javascript" src="source/game.js"></script>
|
||||
<script type="text/javascript" src="source/main.js"></script>
|
||||
</body></html>
|
||||
@@ -0,0 +1,449 @@
|
||||
<?php
|
||||
$WEBGL_REPLACE = [
|
||||
'ACTIVE_ATTRIBUTES' => 35721,
|
||||
'ACTIVE_ATTRIBUTE_MAX_LENGTH' => 35722,
|
||||
'ACTIVE_TEXTURE' => 34016,
|
||||
'ACTIVE_UNIFORMS' => 35718,
|
||||
'ACTIVE_UNIFORM_MAX_LENGTH' => 35719,
|
||||
'ALIASED_LINE_WIDTH_RANGE' => 33902,
|
||||
'ALIASED_POINT_SIZE_RANGE' => 33901,
|
||||
'ALPHA' => 6406,
|
||||
'ALPHA_BITS' => 3413,
|
||||
'ALWAYS' => 519,
|
||||
'ARRAY_BUFFER' => 34962,
|
||||
'ARRAY_BUFFER_BINDING' => 34964,
|
||||
'ATTACHED_SHADERS' => 35717,
|
||||
'BACK' => 1029,
|
||||
'BLEND' => 3042,
|
||||
'BLEND_COLOR' => 32773,
|
||||
'BLEND_DST_ALPHA' => 32970,
|
||||
'BLEND_DST_RGB' => 32968,
|
||||
'BLEND_EQUATION' => 32777,
|
||||
'BLEND_EQUATION_ALPHA' => 34877,
|
||||
'BLEND_EQUATION_RGB' => 32777,
|
||||
'BLEND_SRC_ALPHA' => 32971,
|
||||
'BLEND_SRC_RGB' => 32969,
|
||||
'BLUE_BITS' => 3412,
|
||||
'BOOL' => 35670,
|
||||
'BOOL_VEC2' => 35671,
|
||||
'BOOL_VEC3' => 35672,
|
||||
'BOOL_VEC4' => 35673,
|
||||
'BROWSER_DEFAULT_WEBGL' => 37444,
|
||||
'BUFFER_SIZE' => 34660,
|
||||
'BUFFER_USAGE' => 34661,
|
||||
'BYTE' => 5120,
|
||||
'CCW' => 2305,
|
||||
'CLAMP_TO_EDGE' => 33071,
|
||||
'COLOR_ATTACHMENT0' => 36064,
|
||||
'COLOR_BUFFER_BIT' => 16384,
|
||||
'COLOR_CLEAR_VALUE' => 3106,
|
||||
'COLOR_WRITEMASK' => 3107,
|
||||
'COMPILE_STATUS' => 35713,
|
||||
'COMPRESSED_TEXTURE_FORMATS' => 34467,
|
||||
'CONSTANT_ALPHA' => 32771,
|
||||
'CONSTANT_COLOR' => 32769,
|
||||
'CONTEXT_LOST_WEBGL' => 37442,
|
||||
'CULL_FACE' => 2884,
|
||||
'CULL_FACE_MODE' => 2885,
|
||||
'CURRENT_PROGRAM' => 35725,
|
||||
'CURRENT_VERTEX_ATTRIB' => 34342,
|
||||
'CW' => 2304,
|
||||
'DECR' => 7683,
|
||||
'DECR_WRAP' => 34056,
|
||||
'DELETE_STATUS' => 35712,
|
||||
'DEPTH_ATTACHMENT' => 36096,
|
||||
'DEPTH_BITS' => 3414,
|
||||
'DEPTH_BUFFER_BIT' => 256,
|
||||
'DEPTH_CLEAR_VALUE' => 2931,
|
||||
'DEPTH_COMPONENT' => 6402,
|
||||
'DEPTH_COMPONENT16' => 33189,
|
||||
'DEPTH_FUNC' => 2932,
|
||||
'DEPTH_RANGE' => 2928,
|
||||
'DEPTH_STENCIL' => 34041,
|
||||
'DEPTH_STENCIL_ATTACHMENT' => 33306,
|
||||
'DEPTH_TEST' => 2929,
|
||||
'DEPTH_WRITEMASK' => 2930,
|
||||
'DITHER' => 3024,
|
||||
'DONT_CARE' => 4352,
|
||||
'DST_ALPHA' => 772,
|
||||
'DST_COLOR' => 774,
|
||||
'DYNAMIC_DRAW' => 35048,
|
||||
'ELEMENT_ARRAY_BUFFER' => 34963,
|
||||
'ELEMENT_ARRAY_BUFFER_BINDING' => 34965,
|
||||
'EQUAL' => 514,
|
||||
'FASTEST' => 4353,
|
||||
'FLOAT' => 5126,
|
||||
'FLOAT_MAT2' => 35674,
|
||||
'FLOAT_MAT3' => 35675,
|
||||
'FLOAT_MAT4' => 35676,
|
||||
'FLOAT_VEC2' => 35664,
|
||||
'FLOAT_VEC3' => 35665,
|
||||
'FLOAT_VEC4' => 35666,
|
||||
'FRAGMENT_SHADER' => 35632,
|
||||
'FRAMEBUFFER' => 36160,
|
||||
'FRAMEBUFFER_ATTACHMENT_OBJECT_NAME' => 36049,
|
||||
'FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE' => 36048,
|
||||
'FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE' => 36051,
|
||||
'FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL' => 36050,
|
||||
'FRAMEBUFFER_BINDING' => 36006,
|
||||
'FRAMEBUFFER_COMPLETE' => 36053,
|
||||
'FRAMEBUFFER_INCOMPLETE_ATTACHMENT' => 36054,
|
||||
'FRAMEBUFFER_INCOMPLETE_DIMENSIONS' => 36057,
|
||||
'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT' => 36055,
|
||||
'FRAMEBUFFER_UNSUPPORTED' => 36061,
|
||||
'FRONT' => 1028,
|
||||
'FRONT_AND_BACK' => 1032,
|
||||
'FRONT_FACE' => 2886,
|
||||
'FUNC_ADD' => 32774,
|
||||
'FUNC_REVERSE_SUBTRACT' => 32779,
|
||||
'FUNC_SUBTRACT' => 32778,
|
||||
'GENERATE_MIPMAP_HINT' => 33170,
|
||||
'GEQUAL' => 518,
|
||||
'GREATER' => 516,
|
||||
'GREEN_BITS' => 3411,
|
||||
'HIGH_FLOAT' => 36338,
|
||||
'HIGH_INT' => 36341,
|
||||
'INCR' => 7682,
|
||||
'INCR_WRAP' => 34055,
|
||||
'INFO_LOG_LENGTH' => 35716,
|
||||
'INT' => 5124,
|
||||
'INT_VEC2' => 35667,
|
||||
'INT_VEC3' => 35668,
|
||||
'INT_VEC4' => 35669,
|
||||
'INVALID_ENUM' => 1280,
|
||||
'INVALID_FRAMEBUFFER_OPERATION' => 1286,
|
||||
'INVALID_OPERATION' => 1282,
|
||||
'INVALID_VALUE' => 1281,
|
||||
'INVERT' => 5386,
|
||||
'KEEP' => 7680,
|
||||
'LEQUAL' => 515,
|
||||
'LESS' => 513,
|
||||
'LINEAR' => 9729,
|
||||
'LINEAR_MIPMAP_LINEAR' => 9987,
|
||||
'LINEAR_MIPMAP_NEAREST' => 9985,
|
||||
'LINES' => 1,
|
||||
'LINE_LOOP' => 2,
|
||||
'LINE_STRIP' => 3,
|
||||
'LINE_WIDTH' => 2849,
|
||||
'LINK_STATUS' => 35714,
|
||||
'LOW_FLOAT' => 36336,
|
||||
'LOW_INT' => 36339,
|
||||
'LUMINANCE' => 6409,
|
||||
'LUMINANCE_ALPHA' => 6410,
|
||||
'MAX_COMBINED_TEXTURE_IMAGE_UNITS' => 35661,
|
||||
'MAX_CUBE_MAP_TEXTURE_SIZE' => 34076,
|
||||
'MAX_FRAGMENT_UNIFORM_VECTORS' => 36349,
|
||||
'MAX_RENDERBUFFER_SIZE' => 34024,
|
||||
'MAX_TEXTURE_IMAGE_UNITS' => 34930,
|
||||
'MAX_TEXTURE_SIZE' => 3379,
|
||||
'MAX_VARYING_VECTORS' => 36348,
|
||||
'MAX_VERTEX_ATTRIBS' => 34921,
|
||||
'MAX_VERTEX_TEXTURE_IMAGE_UNITS' => 35660,
|
||||
'MAX_VERTEX_UNIFORM_VECTORS' => 36347,
|
||||
'MAX_VIEWPORT_DIMS' => 3386,
|
||||
'MEDIUM_FLOAT' => 36337,
|
||||
'MEDIUM_INT' => 36340,
|
||||
'MIRRORED_REPEAT' => 33648,
|
||||
'NEAREST' => 9728,
|
||||
'NEAREST_MIPMAP_LINEAR' => 9986,
|
||||
'NEAREST_MIPMAP_NEAREST' => 9984,
|
||||
'NEVER' => 512,
|
||||
'NICEST' => 4354,
|
||||
'NONE' => 0,
|
||||
'NOTEQUAL' => 517,
|
||||
'NO_ERROR' => 0,
|
||||
'NUM_COMPRESSED_TEXTURE_FORMATS' => 34466,
|
||||
'ONE' => 1,
|
||||
'ONE_MINUS_CONSTANT_ALPHA' => 32772,
|
||||
'ONE_MINUS_CONSTANT_COLOR' => 32770,
|
||||
'ONE_MINUS_DST_ALPHA' => 773,
|
||||
'ONE_MINUS_DST_COLOR' => 775,
|
||||
'ONE_MINUS_SRC_ALPHA' => 771,
|
||||
'ONE_MINUS_SRC_COLOR' => 769,
|
||||
'OUT_OF_MEMORY' => 1285,
|
||||
'PACK_ALIGNMENT' => 3333,
|
||||
'POINTS' => 0,
|
||||
'POLYGON_OFFSET_FACTOR' => 32824,
|
||||
'POLYGON_OFFSET_FILL' => 32823,
|
||||
'POLYGON_OFFSET_UNITS' => 10752,
|
||||
'RED_BITS' => 3410,
|
||||
'RENDERBUFFER' => 36161,
|
||||
'RENDERBUFFER_ALPHA_SIZE' => 36179,
|
||||
'RENDERBUFFER_BINDING' => 36007,
|
||||
'RENDERBUFFER_BLUE_SIZE' => 36178,
|
||||
'RENDERBUFFER_DEPTH_SIZE' => 36180,
|
||||
'RENDERBUFFER_GREEN_SIZE' => 36177,
|
||||
'RENDERBUFFER_HEIGHT' => 36163,
|
||||
'RENDERBUFFER_INTERNAL_FORMAT' => 36164,
|
||||
'RENDERBUFFER_RED_SIZE' => 36176,
|
||||
'RENDERBUFFER_STENCIL_SIZE' => 36181,
|
||||
'RENDERBUFFER_WIDTH' => 36162,
|
||||
'RENDERER' => 7937,
|
||||
'REPEAT' => 10497,
|
||||
'REPLACE' => 7681,
|
||||
'RGB' => 6407,
|
||||
'RGB5_A1' => 32855,
|
||||
'RGB565' => 36194,
|
||||
'RGBA' => 6408,
|
||||
'RGBA4' => 32854,
|
||||
'SAMPLER_2D' => 35678,
|
||||
'SAMPLER_CUBE' => 35680,
|
||||
'SAMPLES' => 32937,
|
||||
'SAMPLE_ALPHA_TO_COVERAGE' => 32926,
|
||||
'SAMPLE_BUFFERS' => 32936,
|
||||
'SAMPLE_COVERAGE' => 32928,
|
||||
'SAMPLE_COVERAGE_INVERT' => 32939,
|
||||
'SAMPLE_COVERAGE_VALUE' => 32938,
|
||||
'SCISSOR_BOX' => 3088,
|
||||
'SCISSOR_TEST' => 3089,
|
||||
'SHADER_COMPILER' => 36346,
|
||||
'SHADER_SOURCE_LENGTH' => 35720,
|
||||
'SHADER_TYPE' => 35663,
|
||||
'SHADING_LANGUAGE_VERSION' => 35724,
|
||||
'SHORT' => 5122,
|
||||
'SRC_ALPHA' => 770,
|
||||
'SRC_ALPHA_SATURATE' => 776,
|
||||
'SRC_COLOR' => 768,
|
||||
'STATIC_DRAW' => 35044,
|
||||
'STENCIL_ATTACHMENT' => 36128,
|
||||
'STENCIL_BACK_FAIL' => 34817,
|
||||
'STENCIL_BACK_FUNC' => 34816,
|
||||
'STENCIL_BACK_PASS_DEPTH_FAIL' => 34818,
|
||||
'STENCIL_BACK_PASS_DEPTH_PASS' => 34819,
|
||||
'STENCIL_BACK_REF' => 36003,
|
||||
'STENCIL_BACK_VALUE_MASK' => 36004,
|
||||
'STENCIL_BACK_WRITEMASK' => 36005,
|
||||
'STENCIL_BITS' => 3415,
|
||||
'STENCIL_BUFFER_BIT' => 1024,
|
||||
'STENCIL_CLEAR_VALUE' => 2961,
|
||||
'STENCIL_FAIL' => 2964,
|
||||
'STENCIL_FUNC' => 2962,
|
||||
'STENCIL_INDEX' => 6401,
|
||||
'STENCIL_INDEX8' => 36168,
|
||||
'STENCIL_PASS_DEPTH_FAIL' => 2965,
|
||||
'STENCIL_PASS_DEPTH_PASS' => 2966,
|
||||
'STENCIL_REF' => 2967,
|
||||
'STENCIL_TEST' => 2960,
|
||||
'STENCIL_VALUE_MASK' => 2963,
|
||||
'STENCIL_WRITEMASK' => 2968,
|
||||
'STREAM_DRAW' => 35040,
|
||||
'SUBPIXEL_BITS' => 3408,
|
||||
'TEXTURE' => 5890,
|
||||
'TEXTURE0' => 33984,
|
||||
'TEXTURE1' => 33985,
|
||||
'TEXTURE2' => 33986,
|
||||
'TEXTURE3' => 33987,
|
||||
'TEXTURE4' => 33988,
|
||||
'TEXTURE5' => 33989,
|
||||
'TEXTURE6' => 33990,
|
||||
'TEXTURE7' => 33991,
|
||||
'TEXTURE8' => 33992,
|
||||
'TEXTURE9' => 33993,
|
||||
'TEXTURE10' => 33994,
|
||||
'TEXTURE11' => 33995,
|
||||
'TEXTURE12' => 33996,
|
||||
'TEXTURE13' => 33997,
|
||||
'TEXTURE14' => 33998,
|
||||
'TEXTURE15' => 33999,
|
||||
'TEXTURE16' => 34000,
|
||||
'TEXTURE17' => 34001,
|
||||
'TEXTURE18' => 34002,
|
||||
'TEXTURE19' => 34003,
|
||||
'TEXTURE20' => 34004,
|
||||
'TEXTURE21' => 34005,
|
||||
'TEXTURE22' => 34006,
|
||||
'TEXTURE23' => 34007,
|
||||
'TEXTURE24' => 34008,
|
||||
'TEXTURE25' => 34009,
|
||||
'TEXTURE26' => 34010,
|
||||
'TEXTURE27' => 34011,
|
||||
'TEXTURE28' => 34012,
|
||||
'TEXTURE29' => 34013,
|
||||
'TEXTURE30' => 34014,
|
||||
'TEXTURE31' => 34015,
|
||||
'TEXTURE_2D' => 3553,
|
||||
'TEXTURE_BINDING_2D' => 32873,
|
||||
'TEXTURE_BINDING_CUBE_MAP' => 34068,
|
||||
'TEXTURE_CUBE_MAP' => 34067,
|
||||
'TEXTURE_CUBE_MAP_NEGATIVE_X' => 34070,
|
||||
'TEXTURE_CUBE_MAP_NEGATIVE_Y' => 34072,
|
||||
'TEXTURE_CUBE_MAP_NEGATIVE_Z' => 34074,
|
||||
'TEXTURE_CUBE_MAP_POSITIVE_X' => 34069,
|
||||
'TEXTURE_CUBE_MAP_POSITIVE_Y' => 34071,
|
||||
'TEXTURE_CUBE_MAP_POSITIVE_Z' => 34073,
|
||||
'TEXTURE_MAG_FILTER' => 10240,
|
||||
'TEXTURE_MIN_FILTER' => 10241,
|
||||
'TEXTURE_WRAP_S' => 10242,
|
||||
'TEXTURE_WRAP_T' => 10243,
|
||||
'TRIANGLES' => 4,
|
||||
'TRIANGLE_FAN' => 6,
|
||||
'TRIANGLE_STRIP' => 5,
|
||||
'UNPACK_ALIGNMENT' => 3317,
|
||||
'UNPACK_COLORSPACE_CONVERSION_WEBGL' => 37443,
|
||||
'UNPACK_FLIP_Y_WEBGL' => 37440,
|
||||
'UNPACK_PREMULTIPLY_ALPHA_WEBGL' => 37441,
|
||||
'UNSIGNED_BYTE' => 5121,
|
||||
'UNSIGNED_INT' => 5125,
|
||||
'UNSIGNED_SHORT' => 5123,
|
||||
'UNSIGNED_SHORT_4_4_4_4' => 32819,
|
||||
'UNSIGNED_SHORT_5_5_5_1' => 32820,
|
||||
'UNSIGNED_SHORT_5_6_5' => 33635,
|
||||
'VALIDATE_STATUS' => 35715,
|
||||
'VENDOR' => 7936,
|
||||
'VERSION' => 7938,
|
||||
'VERTEX_ATTRIB_ARRAY_BUFFER_BINDING' => 34975,
|
||||
'VERTEX_ATTRIB_ARRAY_ENABLED' => 34338,
|
||||
'VERTEX_ATTRIB_ARRAY_NORMALIZED' => 34922,
|
||||
'VERTEX_ATTRIB_ARRAY_POINTER' => 34373,
|
||||
'VERTEX_ATTRIB_ARRAY_SIZE' => 34339,
|
||||
'VERTEX_ATTRIB_ARRAY_STRIDE' => 34340,
|
||||
'VERTEX_ATTRIB_ARRAY_TYPE' => 34341,
|
||||
'VERTEX_SHADER' => 35633,
|
||||
'VIEWPORT' => 2978,
|
||||
'ZERO' => 0,
|
||||
|
||||
'activeTexture' => "gl.acT",
|
||||
'attachShader' => "gl.atS",
|
||||
'bindAttribLocation' => "gl.biAL",
|
||||
'bindBuffer' => "gl.biB",
|
||||
'bindFramebuffer' => "gl.biF",
|
||||
'bindRenderbuffer' => "gl.biR",
|
||||
'bindTexture' => "gl.biT",
|
||||
'blendColor' => "gl.blC",
|
||||
'blendEquation' => "gl.blE",
|
||||
'blendEquationSeparate' => "gl.blES",
|
||||
'blendFunc' => "gl.blF",
|
||||
'blendFuncSeparate' => "gl.blFS",
|
||||
'bufferData' => "gl.buD",
|
||||
'bufferSubData' => "gl.buSD",
|
||||
'checkFramebufferStatus' => "gl.chFS",
|
||||
'clear' => "gl.cl",
|
||||
'clearColor' => "gl.clC",
|
||||
'clearDepth' => "gl.clD",
|
||||
'clearStencil' => "gl.clS",
|
||||
'colorMask' => "gl.coM",
|
||||
'compileShader' => "gl.coS",
|
||||
'compressedTexImage2D' => "gl.coTI2D",
|
||||
'compressedTexSubImage2D' => "gl.coTSI2D",
|
||||
'copyTexImage2D' => "gl.coTI2D",
|
||||
'copyTexSubImage2D' => "gl.coTSI2D",
|
||||
'createBuffer' => "gl.crB",
|
||||
'createFramebuffer' => "gl.crF",
|
||||
'createProgram' => "gl.crP",
|
||||
'createRenderbuffer' => "gl.crR",
|
||||
'createShader' => "gl.crS",
|
||||
'createTexture' => "gl.crT",
|
||||
'cullFace' => "gl.cuF",
|
||||
'deleteBuffer' => "gl.deB",
|
||||
'deleteFramebuffer' => "gl.deF",
|
||||
'deleteProgram' => "gl.deP",
|
||||
'deleteRenderbuffer' => "gl.deR",
|
||||
'deleteShader' => "gl.deS",
|
||||
'deleteTexture' => "gl.deT",
|
||||
'depthFunc' => "gl.deF",
|
||||
'depthMask' => "gl.deM",
|
||||
'depthRange' => "gl.deR",
|
||||
'detachShader' => "gl.deS",
|
||||
'disable' => "gl.di",
|
||||
'disableVertexAttribArray' => "gl.diVAA",
|
||||
'drawArrays' => "gl.drA",
|
||||
'drawElements' => "gl.drE",
|
||||
'enable' => "gl.en",
|
||||
'enableVertexAttribArray' => "gl.enVAA",
|
||||
'finish' => "gl.fi",
|
||||
'flush' => "gl.fl",
|
||||
'framebufferRenderbuffer' => "gl.frR",
|
||||
'framebufferTexture2D' => "gl.frT2D",
|
||||
'frontFace' => "gl.frF",
|
||||
'generateMipmap' => "gl.geM",
|
||||
'getActiveAttrib' => "gl.geAA",
|
||||
'getActiveUniform' => "gl.geAU",
|
||||
'getAttachedShaders' => "gl.geAS",
|
||||
'getAttribLocation' => "gl.geAL",
|
||||
'getBufferParameter' => "gl.geBP",
|
||||
'getContextAttributes' => "gl.geCA",
|
||||
'getError' => "gl.geE",
|
||||
'getExtension' => "gl.geE",
|
||||
'getFramebufferAttachmentParameter' => "gl.geFAP",
|
||||
'getParameter' => "gl.geP",
|
||||
'getProgramParameter' => "gl.gePP",
|
||||
'getProgramInfoLog' => "gl.gePIL",
|
||||
'getRenderbufferParameter' => "gl.geRP",
|
||||
'getShaderParameter' => "gl.geSP",
|
||||
'getShaderInfoLog' => "gl.geSIL",
|
||||
'getShaderPrecisionFormat' => "gl.geSPF",
|
||||
'getShaderSource' => "gl.geSS",
|
||||
'getSupportedExtensions' => "gl.geSE",
|
||||
'getTexParameter' => "gl.geTP",
|
||||
'getUniform' => "gl.geU",
|
||||
'getUniformLocation' => "gl.geUL",
|
||||
'getVertexAttrib' => "gl.geVA",
|
||||
'getVertexAttribOffset' => "gl.geVAO",
|
||||
'hint' => "gl.hi",
|
||||
'isBuffer' => "gl.isB",
|
||||
'isContextLost' => "gl.isCL",
|
||||
'isEnabled' => "gl.isE",
|
||||
'isFramebuffer' => "gl.isF",
|
||||
'isProgram' => "gl.isP",
|
||||
'isRenderbuffer' => "gl.isR",
|
||||
'isShader' => "gl.isS",
|
||||
'isTexture' => "gl.isT",
|
||||
'lineWidth' => "gl.liW",
|
||||
'linkProgram' => "gl.liP",
|
||||
'pixelStorei' => "gl.piS",
|
||||
'polygonOffset' => "gl.poO",
|
||||
'readPixels' => "gl.reP",
|
||||
'renderbufferStorage' => "gl.reS",
|
||||
'sampleCoverage' => "gl.saC",
|
||||
'scissor' => "gl.sc",
|
||||
'shaderSource' => "gl.shS",
|
||||
'stencilFunc' => "gl.stF",
|
||||
'stencilFuncSeparate' => "gl.stFS",
|
||||
'stencilMask' => "gl.stM",
|
||||
'stencilMaskSeparate' => "gl.stMS",
|
||||
'stencilOp' => "gl.stO",
|
||||
'stencilOpSeparate' => "gl.stOS",
|
||||
'texParameterf' => "gl.teP",
|
||||
'texParameteri' => "gl.teP",
|
||||
'texImage2D' => "gl.teI2D",
|
||||
'texSubImage2D' => "gl.teSI2D",
|
||||
'uniform1f' => "gl.un1f",
|
||||
'uniform1fv' => "gl.un1fv",
|
||||
'uniform1i' => "gl.un1i",
|
||||
'uniform1iv' => "gl.un1iv",
|
||||
'uniform2f' => "gl.un2f",
|
||||
'uniform2fv' => "gl.un2fv",
|
||||
'uniform2i' => "gl.un2i",
|
||||
'uniform2iv' => "gl.un2iv",
|
||||
'uniform3f' => "gl.un3f",
|
||||
'uniform3fv' => "gl.un3fv",
|
||||
'uniform3i' => "gl.un3i",
|
||||
'uniform3iv' => "gl.un3iv",
|
||||
'uniform4f' => "gl.un4f",
|
||||
'uniform4fv' => "gl.un4fv",
|
||||
'uniform4i' => "gl.un4i",
|
||||
'uniform4iv' => "gl.un4iv",
|
||||
'uniformMatrix2fv' => "gl.unM2fv",
|
||||
'uniformMatrix3fv' => "gl.unM3fv",
|
||||
'uniformMatrix4fv' => "gl.unM4fv",
|
||||
'useProgram' => "gl.usP",
|
||||
'validateProgram' => "gl.vaP",
|
||||
'vertexAttrib1f' => "gl.veA1f",
|
||||
'vertexAttrib1fv' => "gl.veA1fv",
|
||||
'vertexAttrib2f' => "gl.veA2f",
|
||||
'vertexAttrib2fv' => "gl.veA2fv",
|
||||
'vertexAttrib3f' => "gl.veA3f",
|
||||
'vertexAttrib3fv' => "gl.veA3fv",
|
||||
'vertexAttrib4f' => "gl.veA4f",
|
||||
'vertexAttrib4fv' => "gl.veA4fv",
|
||||
'vertexAttribPointer' => "gl.veAP",
|
||||
'viewport' => "gl.vi"
|
||||
];
|
||||
|
||||
$js = file_get_contents($argv[1]);
|
||||
foreach ($WEBGL_REPLACE as $search => $replace) {
|
||||
$js = preg_replace('/\bgl\.'.$search.'\b/', $replace, $js);
|
||||
}
|
||||
$js = preg_replace('/\/\*DEBUG\[.*?\/\*\]\*\//sm', '', $js);
|
||||
echo $js;
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
|
||||
$script = array_shift($argv);
|
||||
|
||||
|
||||
/* Convert Wavefront OBJ to Retarded Model Format (RMF)
|
||||
|
||||
struct {
|
||||
u8 num_frames;
|
||||
u8 num_verts; // per frame
|
||||
u8 num_indices;
|
||||
struct {
|
||||
u8 x, y, z;
|
||||
} verts[num_frames * num_verts];
|
||||
struct {
|
||||
u8 a_address_inc, b_index, c_index;
|
||||
} indices[num_indices];
|
||||
} rmf_data;
|
||||
*/
|
||||
|
||||
if (count($argv) < 2 || !file_exists($argv[0])) {
|
||||
die("Usage: php model_packer.php frame1.obj frame2.obj... outfile.rmf\n");
|
||||
}
|
||||
|
||||
$infiles = array_slice($argv, 0, -1);
|
||||
$verts = [];
|
||||
$indices = [];
|
||||
$max = -INF;
|
||||
|
||||
// Find vertices in all files
|
||||
foreach ($infiles as $file) {
|
||||
if (!file_exists($file)) {
|
||||
die("Couldn't load $file\n");
|
||||
}
|
||||
echo "Loading $file\n";
|
||||
foreach (file($file) as $line) {
|
||||
if (preg_match('#^v (.*?) (.*?) (.*?)$#', $line, $m)) {
|
||||
$v = [(float)$m[1], (float)$m[2], (float)$m[3]];
|
||||
$verts[] = $v;
|
||||
$max = max($max, abs($v[0]), abs($v[1]), abs($v[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find indices in first file (we assume the layout is the same in all
|
||||
// subsequent animation frames).
|
||||
foreach (file($infiles[0]) as $line) {
|
||||
if (preg_match('#^f (\d+).*?(\d+).*?(\d+).*?$#', $line, $m)) {
|
||||
$indices[] = [((int)$m[1])-1, ((int)$m[2])-1, ((int)$m[3])-1];
|
||||
}
|
||||
}
|
||||
|
||||
// Pack header
|
||||
$packed =
|
||||
pack('C', count($infiles)).
|
||||
pack('C', count($verts)/count($infiles)).
|
||||
pack('C', count($indices));
|
||||
|
||||
// Pack normalized (-15, 15) vertices
|
||||
foreach ($verts as $i => $v) {
|
||||
$x = round(($v[0]/$max)*15)+15;
|
||||
$y = round(($v[1]/$max)*15)+15;
|
||||
$z = round(($v[2]/$max)*15)+15;
|
||||
|
||||
// echo "Vertex $i => ($x, $y, $z)\n";
|
||||
$packed .=
|
||||
pack('C', $x).
|
||||
pack('C', $y).
|
||||
pack('C', $z);
|
||||
|
||||
}
|
||||
|
||||
// Pack indices w. vertex index
|
||||
$a_last_index = 0;
|
||||
foreach ($indices as $i => $f) {
|
||||
$a_address_inc = $f[0] - $a_last_index;
|
||||
if ($a_address_inc > 3) {
|
||||
die("Face $i index a increment exceeds 2 bits ($a_address_inc)\n");
|
||||
}
|
||||
$a_last_index = $f[0];
|
||||
|
||||
if ($f[1] > 127 || $f[2] > 127) {
|
||||
die("Face $i index exceeds 7 bits ({$f[1]}, {$f[1]}, {$f[2]})\n");
|
||||
}
|
||||
|
||||
// echo "Face $i => ({$f[1]}, {$f[1]}, {$f[2]})\n";
|
||||
// $packed .= pack('v', ($a_address_inc << 14) | ($f[1] << 7) | $f[2]);
|
||||
$packed .=
|
||||
pack('C', $a_address_inc).
|
||||
pack('C', $f[1]).
|
||||
pack('C', $f[2]);
|
||||
}
|
||||
|
||||
// Write
|
||||
$packedfile = $argv[count($argv)-1];
|
||||
file_put_contents($packedfile, $packed);
|
||||
|
||||
echo "Wrote $packedfile: ".
|
||||
count($infiles)." frame(s), ".
|
||||
count($verts)." verts, ".
|
||||
count($indices)." indices, ".
|
||||
strlen($packed)." bytes\n";
|
||||
@@ -0,0 +1,240 @@
|
||||
|
||||
// Gutted for js13k and modified to use Float32 buffers directly
|
||||
// ~ Dominic Szablewski, phoboslab.org, Sep 2018
|
||||
|
||||
// Almost re-written for for jsk13 2019. Oscilators now use a lookup table
|
||||
// instead of calling functions. This and various other changes result in a
|
||||
// ~10x performance increase and smaller file size.
|
||||
// ~ Dominic Szablewski, phoboslab.org, Sep 2019
|
||||
|
||||
// Again updated for js13k 2021. Song and sound definitions are now just arrays
|
||||
// instead of objects.
|
||||
|
||||
|
||||
//
|
||||
// Sonant-X
|
||||
//
|
||||
// Copyr (c) 2014 Nicolas Vanhoren
|
||||
//
|
||||
// Sonant-X is a fork of js-sonant by Marcus Geelnard and Jake Taylor. It is
|
||||
// still published using the same license (zlib license, see below).
|
||||
//
|
||||
// Copyr (c) 2011 Marcus Geelnard
|
||||
// Copyr (c) 2008-2009 Jake Taylor
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
|
||||
let
|
||||
audio_ctx,
|
||||
AUDIO_SAMPLERATE = 44100, // Samples per second
|
||||
AUDIO_TAB_SIZE = 4096,
|
||||
AUDIO_TAB_MASK = AUDIO_TAB_SIZE-1,
|
||||
AUDIO_TAB = new Float32Array(AUDIO_TAB_SIZE*4), // 4 oscilators
|
||||
|
||||
audio_init = () => {
|
||||
// This function needs to be called in response to a user action, as it
|
||||
// tries to activate the audio context.
|
||||
audio_ctx = new AudioContext();
|
||||
audio_ctx.resume();
|
||||
|
||||
// Generate the lookup tables
|
||||
for (let i = 0; i < AUDIO_TAB_SIZE; i++) {
|
||||
AUDIO_TAB[i ] = Math.sin(i*6.283184/AUDIO_TAB_SIZE); // sin
|
||||
AUDIO_TAB[i + AUDIO_TAB_SIZE ] = AUDIO_TAB[i] < 0 ? -1 : 1; // square
|
||||
AUDIO_TAB[i + AUDIO_TAB_SIZE * 2] = i / AUDIO_TAB_SIZE - 0.5; // saw
|
||||
AUDIO_TAB[i + AUDIO_TAB_SIZE * 3] = i < AUDIO_TAB_SIZE/2 ? (i/(AUDIO_TAB_SIZE/4)) - 1 : 3 - (i/(AUDIO_TAB_SIZE/4)); // tri
|
||||
}
|
||||
},
|
||||
|
||||
audio_play = (buffer, volume = 1, loop = 0, pan = 0) => {
|
||||
let gain = audio_ctx.createGain(),
|
||||
source = audio_ctx.createBufferSource(),
|
||||
panner = audio_ctx.createStereoPanner();
|
||||
gain.gain.value = volume;
|
||||
gain.connect(audio_ctx.destination);
|
||||
panner.connect(gain);
|
||||
panner.pan.value = pan;
|
||||
source.buffer = buffer;
|
||||
source.loop = loop;
|
||||
source.connect(panner);
|
||||
source.start();
|
||||
},
|
||||
|
||||
audio_get_ctx_buffer = (buf_l, buf_r) => {
|
||||
let buffer = audio_ctx.createBuffer(2, buf_l.length, AUDIO_SAMPLERATE);
|
||||
buffer.getChannelData(0).set(buf_l);
|
||||
buffer.getChannelData(1).set(buf_r);
|
||||
return buffer;
|
||||
},
|
||||
|
||||
audio_generate_sound = (
|
||||
row_len, note, buf_l, buf_r, write_pos,
|
||||
|
||||
// Instrument properties
|
||||
osc1_oct, osc1_det, osc1_detune, osc1_xenv, osc1_vol, osc1_waveform,
|
||||
osc2_oct, osc2_det, osc2_detune, osc2_xenv, osc2_vol, osc2_waveform,
|
||||
noise_fader, attack, sustain, release, master,
|
||||
fx_filter, fx_freq, fx_resonance, fx_delay_time, fx_delay_amt, fx_pan_freq_p, fx_pan_amt,
|
||||
lfo_osc1_freq, lfo_fx_freq, lfo_freq_p, lfo_amt, lfo_waveform
|
||||
) => {
|
||||
let osc_lfo_offset = lfo_waveform * AUDIO_TAB_SIZE,
|
||||
osc1_offset = osc1_waveform * AUDIO_TAB_SIZE,
|
||||
osc2_offset = osc2_waveform * AUDIO_TAB_SIZE,
|
||||
fx_pan_freq = Math.pow(2, fx_pan_freq_p - 8) / row_len,
|
||||
lfo_freq = Math.pow(2, lfo_freq_p - 8) / row_len,
|
||||
|
||||
c1 = 0,
|
||||
c2 = 0,
|
||||
|
||||
q = fx_resonance / 255,
|
||||
low = 0,
|
||||
band = 0,
|
||||
high = 0,
|
||||
|
||||
buf_length = buf_l.length,
|
||||
num_samples = attack + sustain + release - 1,
|
||||
|
||||
osc1_freq =
|
||||
Math.pow(1.059463094, (note + (osc1_oct - 8) * 12 + osc1_det) - 128)
|
||||
* 0.00390625 * (1 + 0.0008 * osc1_detune),
|
||||
osc2_freq =
|
||||
Math.pow(1.059463094, (note + (osc2_oct - 8) * 12 + osc2_det) - 128)
|
||||
* 0.00390625 * (1 + 0.0008 * osc2_detune);
|
||||
|
||||
for (let j = num_samples; j >= 0; --j) {
|
||||
let
|
||||
// Buffer positions
|
||||
k = j + write_pos,
|
||||
|
||||
// LFO
|
||||
lfor = AUDIO_TAB[osc_lfo_offset + ((k * lfo_freq * AUDIO_TAB_SIZE) & AUDIO_TAB_MASK)] * lfo_amt / 512 + 0.5,
|
||||
|
||||
sample = 0,
|
||||
filter_f = fx_freq,
|
||||
temp_f,
|
||||
envelope = 1;
|
||||
|
||||
// Envelope
|
||||
if (j < attack) {
|
||||
envelope = j / attack;
|
||||
}
|
||||
else if (j >= attack + sustain) {
|
||||
envelope -= (j - attack - sustain) / release;
|
||||
}
|
||||
|
||||
// Oscillator 1
|
||||
temp_f = osc1_freq;
|
||||
if (lfo_osc1_freq) {
|
||||
temp_f *= lfor;
|
||||
}
|
||||
if (osc1_xenv) {
|
||||
temp_f *= envelope * envelope;
|
||||
}
|
||||
c1 += temp_f;
|
||||
sample += AUDIO_TAB[osc1_offset + ((c1 * AUDIO_TAB_SIZE) & AUDIO_TAB_MASK)] * osc1_vol;
|
||||
|
||||
// Oscillator 2
|
||||
temp_f = osc2_freq;
|
||||
if (osc2_xenv) {
|
||||
temp_f *= envelope * envelope;
|
||||
}
|
||||
c2 += temp_f;
|
||||
sample += AUDIO_TAB[osc2_offset + ((c2 * AUDIO_TAB_SIZE) & AUDIO_TAB_MASK)] * osc2_vol;
|
||||
|
||||
// Noise oscillator
|
||||
if (noise_fader) {
|
||||
sample += (2*Math.random()-1) * noise_fader * envelope;
|
||||
}
|
||||
|
||||
sample *= envelope / 255;
|
||||
|
||||
// State variable filter
|
||||
if (lfo_fx_freq) {
|
||||
filter_f *= lfor;
|
||||
}
|
||||
|
||||
filter_f = 1.5 * AUDIO_TAB[(filter_f * 0.5 / AUDIO_SAMPLERATE * AUDIO_TAB_SIZE) & AUDIO_TAB_MASK];
|
||||
low += filter_f * band;
|
||||
high = q * (sample - band) - low;
|
||||
band += filter_f * high;
|
||||
sample = [sample, high, low, band, low + high][fx_filter];
|
||||
|
||||
// Panning & master volume
|
||||
temp_f = AUDIO_TAB[(k * fx_pan_freq * AUDIO_TAB_SIZE) & AUDIO_TAB_MASK] * fx_pan_amt / 512 + 0.5;
|
||||
sample *= 0.00476 * master; // 39 / 8192 = 0.00476
|
||||
|
||||
buf_l[k] += sample * (1-temp_f);
|
||||
buf_r[k] += sample * temp_f;
|
||||
}
|
||||
},
|
||||
|
||||
audio_create_song = (row_len, pattern_len, song_len, tracks) => {
|
||||
let num_samples = AUDIO_SAMPLERATE * song_len,
|
||||
mix_buf_l = new Float32Array(num_samples),
|
||||
mix_buf_r = new Float32Array(num_samples);
|
||||
|
||||
for (let track of tracks) {
|
||||
let buf_l = new Float32Array(num_samples),
|
||||
buf_r = new Float32Array(num_samples),
|
||||
write_pos = 0,
|
||||
delay_shift = (track[0/*instrument*/][20/*fx_delay_time*/] * row_len) >> 1,
|
||||
delay_amount = track[0/*instrument*/][21/*fx_delay_amt*/] / 255;
|
||||
|
||||
for (let p = 0; p < pattern_len; p++) {
|
||||
for (let row = 0; row < 32; row++) {
|
||||
let note = track[2/*notes*/][track[1/*pattern*/][p] - 1]?.[row];
|
||||
if (note) {
|
||||
audio_generate_sound(row_len, note, buf_l, buf_r, write_pos, ...track[0/*instrument*/]);
|
||||
}
|
||||
write_pos += row_len;
|
||||
}
|
||||
}
|
||||
|
||||
audio_apply_delay(delay_shift, delay_amount, buf_l, buf_r);
|
||||
for (let b = 0; b < num_samples; b++) {
|
||||
mix_buf_l[b] += buf_l[b];
|
||||
mix_buf_r[b] += buf_r[b];
|
||||
}
|
||||
}
|
||||
return audio_get_ctx_buffer(mix_buf_l, mix_buf_r);
|
||||
},
|
||||
|
||||
audio_create_sound = (note, instrument, row_len = 5605) => {
|
||||
let delay_shift = (instrument[20/*fx_delay_time*/] * row_len) >> 1,
|
||||
delay_amount = instrument[21/*fx_delay_amt*/] / 255,
|
||||
num_samples =
|
||||
instrument[13/*env_attack*/] +
|
||||
instrument[14/*env_sustain*/] +
|
||||
instrument[15/*env_release*/] +
|
||||
delay_shift * 32 * delay_amount,
|
||||
buf_l = new Float32Array(num_samples),
|
||||
buf_r = new Float32Array(num_samples);
|
||||
audio_generate_sound(row_len, note, buf_l, buf_r, 0, ...instrument);
|
||||
audio_apply_delay(delay_shift, delay_amount, buf_l, buf_r);
|
||||
return audio_get_ctx_buffer(buf_l, buf_r);
|
||||
},
|
||||
|
||||
audio_apply_delay = (shift, amount, buf_l, buf_r) => {
|
||||
for (let i = 0; i < buf_l.length - shift; i++) {
|
||||
buf_l[i + shift] += buf_r[i] * amount;
|
||||
buf_r[i + shift] += buf_l[i] * amount;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
document.body.innerHTML +=
|
||||
'<style>'+
|
||||
'*{font-family:sans-serif;}'+
|
||||
'a,body{color:#fff;background:#111;text-align:center;margin:0;}'+
|
||||
'#c{display:block;width:100%;image-rendering:optimizeSpeed;image-rendering:pixelated;max-height:100vh;object-fit:contain;}'+
|
||||
'#g{position:relative;margin:0 0 32px 0;font-weight:bold;}'+
|
||||
'#ts{position:absolute;bottom:2em;left:0;right:0;font-size:1.2vw;}'+
|
||||
'#msg{position:absolute;top:8vw;left:0;right:0;font-size:1.2vw;display:none;}'+
|
||||
'#a,#h{position:absolute;bottom:3%;left:20%;right:0;font-size:3.2vw;}'+
|
||||
'#h{left:-20%;}'+
|
||||
'h1{font-size:16vw;margin:0;}'+
|
||||
'</style>'+
|
||||
'<div id="g">'+
|
||||
'<canvas id=c width=320 height=180></canvas>'+
|
||||
'<div id="ts"><h1>Q1K3</h1>CLICK TO START</div>'+
|
||||
'<div id="h"></div><div id="a"></div>'+
|
||||
'<div id="msg"></div>'+
|
||||
'</div>'+
|
||||
'<p>MOUSE SPEED: <input id="m" type="range" value=10 min=1 max=50></p>'+
|
||||
'<p><input id="f" type="button" value="FULLSCREEN"></p>'+
|
||||
'<p>'+
|
||||
'code: <a href="https://phoboslab.org">phoboslab.org</a> / music: <a href="http://no-fate.net">no-fate.net</a>'+
|
||||
'</p>';
|
||||
@@ -0,0 +1,226 @@
|
||||
|
||||
let ENTITY_GROUP_NONE = 0,
|
||||
ENTITY_GROUP_PLAYER = 1,
|
||||
ENTITY_GROUP_ENEMY = 2;
|
||||
|
||||
class entity_t {
|
||||
constructor(pos, p1, p2) {
|
||||
this.a = vec3();
|
||||
this.v = vec3();
|
||||
this.p = pos;
|
||||
this.s = vec3(2,2,2);
|
||||
this.f = 0;
|
||||
|
||||
this._health = 50;
|
||||
this._dead = 0;
|
||||
this._die_at = 0;
|
||||
this._step_height = 0;
|
||||
this._bounciness = 0;
|
||||
this._gravity = 1;
|
||||
this._yaw = 0;
|
||||
this._pitch = 0;
|
||||
this._anim = [1, [0]];
|
||||
this._anim_time = Math.random();
|
||||
this._on_ground = 0;
|
||||
this._keep_off_ledges = 0;
|
||||
|
||||
this._check_against = ENTITY_GROUP_NONE;
|
||||
this._stepped_up_at = 0;
|
||||
|
||||
this._init(p1, p2);
|
||||
}
|
||||
|
||||
_init(p1, p2) {}
|
||||
|
||||
_update() {
|
||||
if (this._model) {
|
||||
this._draw_model();
|
||||
}
|
||||
}
|
||||
|
||||
_update_physics() {
|
||||
if (this._die_at && this._die_at < game_time) {
|
||||
this._kill();
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply Gravity
|
||||
this.a.y = -1200 * this._gravity;
|
||||
|
||||
// Integrate acceleration & friction into velocity
|
||||
let ff = Math.min(this.f * game_tick, 1);
|
||||
this.v = vec3_add(
|
||||
this.v, vec3_sub(
|
||||
vec3_mulf(this.a, game_tick),
|
||||
vec3_mul(this.v, vec3(ff, 0, ff))
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// Set up the _check_entities array for entity collisions
|
||||
this._check_entities = [
|
||||
[],
|
||||
game_entities_friendly,
|
||||
game_entities_enemies
|
||||
][this._check_against];
|
||||
|
||||
// Divide the physics integration into 16 unit steps; otherwise fast
|
||||
// projectiles may just move through walls.
|
||||
let
|
||||
original_step_height = this._step_height,
|
||||
move_dist = vec3_mulf(this.v, game_tick),
|
||||
steps = Math.ceil(vec3_length(move_dist) / 16),
|
||||
move_step_height = vec3_mulf(move_dist, 1/steps);
|
||||
|
||||
for (let s = 0; s < steps; s++) {
|
||||
// Remember last position so we can roll back
|
||||
let lp = vec3_clone(this.p);
|
||||
|
||||
// Integrate velocity into position
|
||||
this.p = vec3_add(this.p, move_step_height);
|
||||
|
||||
// Collision with walls, horizonal
|
||||
if (this._collides(vec3(this.p.x, lp.y, lp.z))) {
|
||||
|
||||
// Can we step up?
|
||||
if (
|
||||
!this._step_height || !this._on_ground || this.v.y > 0 ||
|
||||
this._collides(vec3(this.p.x, lp.y+this._step_height, lp.z))
|
||||
) {
|
||||
this._did_collide(0);
|
||||
this.p.x = lp.x;
|
||||
this.v.x = -this.v.x * this._bounciness;
|
||||
}
|
||||
else {
|
||||
lp.y += this._step_height;
|
||||
this._stepped_up_at = game_time;
|
||||
}
|
||||
|
||||
s = steps; // stop after this iteration
|
||||
}
|
||||
|
||||
// Collision with walls, vertical
|
||||
if (this._collides(vec3(this.p.x, lp.y, this.p.z))) {
|
||||
|
||||
// Can we step up?
|
||||
if (
|
||||
!this._step_height || !this._on_ground || this.v.y > 0 ||
|
||||
this._collides(vec3(this.p.x, lp.y+this._step_height, this.p.z))
|
||||
) {
|
||||
this._did_collide(2);
|
||||
this.p.z = lp.z;
|
||||
this.v.z = -this.v.z * this._bounciness;
|
||||
}
|
||||
else {
|
||||
lp.y += this._step_height;
|
||||
this._stepped_up_at = game_time;
|
||||
}
|
||||
|
||||
s = steps; // stop after this iteration
|
||||
}
|
||||
|
||||
// Collision with ground/Ceiling
|
||||
if (this._collides(this.p)) {
|
||||
this._did_collide(1);
|
||||
this.p.y = lp.y;
|
||||
|
||||
// Only bounce from ground/ceiling if we have enough velocity
|
||||
let bounce = Math.abs(this.v.y) > 200 ? this._bounciness : 0;
|
||||
this._on_ground = this.v.y < 0 && !bounce;
|
||||
this.v.y = -this.v.y * bounce;
|
||||
|
||||
s = steps; // stop after this iteration
|
||||
}
|
||||
|
||||
this._step_height = original_step_height;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_collides(p) {
|
||||
if (this._dead) {
|
||||
return;
|
||||
}
|
||||
for (let entity of this._check_entities) {
|
||||
if (vec3_dist(p, entity.p) < this.s.y + entity.s.y) {
|
||||
// If we collide with an entity set the step height to 0,
|
||||
// so we don't climb up on its shoulders :/
|
||||
this._step_height = 0;
|
||||
this._did_collide_with_entity(entity);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there's no block beneath this point. We want the AI to keep
|
||||
// off of ledges.
|
||||
if (
|
||||
this._on_ground && this._keep_off_ledges &&
|
||||
!map_block_at(p.x >> 5, (p.y-this.s.y-8) >> 4, p.z >>5) &&
|
||||
!map_block_at(p.x >> 5, (p.y-this.s.y-24) >> 4, p.z >>5)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do the normal collision check with the whole box
|
||||
return map_block_at_box(vec3_sub(p, this.s), vec3_add(p, this.s));
|
||||
}
|
||||
|
||||
_did_collide(axis) {}
|
||||
|
||||
_did_collide_with_entity(other) {}
|
||||
|
||||
_draw_model() {
|
||||
this._anim_time += game_tick;
|
||||
|
||||
// Calculate which frames to use and how to mix them
|
||||
let f = (this._anim_time / this._anim[0]),
|
||||
mix = f - (f|0),
|
||||
frame_cur = this._anim[1][(f|0) % this._anim[1].length],
|
||||
frame_next = this._anim[1][((f+1)|0) % this._anim[1].length];
|
||||
|
||||
// Swap frames if we're looping to the first frame again
|
||||
if (frame_next < frame_cur) {
|
||||
[frame_next, frame_cur] = [frame_cur, frame_next];
|
||||
mix = 1-mix;
|
||||
}
|
||||
r_draw(
|
||||
this.p, this._yaw, this._pitch, this._texture,
|
||||
this._model.f[frame_cur], this._model.f[frame_next], mix,
|
||||
this._model.nv
|
||||
);
|
||||
}
|
||||
|
||||
_spawn_particles(amount, speed = 1, model, texture, lifetime) {
|
||||
for (let i = 0; i < amount; i++) {
|
||||
let particle = game_spawn(entity_particle_t, this.p);
|
||||
particle._model = model;
|
||||
particle._texture = texture;
|
||||
particle._die_at = game_time + lifetime + Math.random() * lifetime * 0.2;
|
||||
particle.v = vec3(
|
||||
(Math.random() - 0.5) * speed,
|
||||
Math.random() * speed,
|
||||
(Math.random() - 0.5) * speed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_receive_damage(from, amount) {
|
||||
if (this._dead) {
|
||||
return;
|
||||
}
|
||||
this._health -= amount;
|
||||
if (this._health <= 0) {
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
|
||||
_play_sound(sound) {
|
||||
let volume = clamp(scale(vec3_dist(this.p, r_camera), 64, 1200, 1, 0),0,1),
|
||||
pan = Math.sin(vec3_2d_angle(this.p, r_camera)-r_camera_yaw)*-1;
|
||||
audio_play(sound, volume, 0, pan);
|
||||
}
|
||||
|
||||
_kill() {
|
||||
this._dead = 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
class entity_barrel_t extends entity_t {
|
||||
_init() {
|
||||
this._model = model_barrel;
|
||||
this._texture = 21;
|
||||
this._pitch = Math.PI/2;
|
||||
this._health = 10;
|
||||
this.s = vec3(8, 32, 8);
|
||||
|
||||
game_entities_enemies.push(this);
|
||||
}
|
||||
|
||||
_kill() {
|
||||
// Deal some damage to nearby entities
|
||||
for (let entity of game_entities_enemies) {
|
||||
let dist = vec3_dist(this.p, entity.p);
|
||||
if (entity !== this && dist < 256) {
|
||||
entity._receive_damage(this, scale(dist, 0, 256, 60, 0));
|
||||
}
|
||||
}
|
||||
|
||||
super._kill();
|
||||
this._play_sound(sfx_grenade_explode);
|
||||
for (let m of model_gib_pieces) {
|
||||
this._spawn_particles(2, 600, m, 21, 1);
|
||||
}
|
||||
game_spawn(entity_light_t, vec3_add(this.p, vec3(0,16,0)), 250, 0x08f)._die_at = game_time + 0.2;
|
||||
game_entities_enemies = game_entities_enemies.filter(e => e != this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
class entity_door_t extends entity_t {
|
||||
_init(texture, dir) {
|
||||
this._model = model_door;
|
||||
this._texture = texture;
|
||||
this._health = 10;
|
||||
this.s = vec3(64, 64, 64);
|
||||
this._start_pos = vec3_clone(this.p);
|
||||
|
||||
this._reset_state_at = 0;
|
||||
this._yaw = dir * Math.PI/2;
|
||||
this._open = 0;
|
||||
|
||||
// Map 1 only has one door and it needs a key. Should be a flag
|
||||
// in the entity data instead :/
|
||||
this._needs_key = game_map_index == 1;
|
||||
|
||||
// Doors block enemies and players
|
||||
game_entities_enemies.push(this);
|
||||
game_entities_friendly.push(this);
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._draw_model();
|
||||
if (vec3_dist(this.p, game_entity_player.p) < 128) {
|
||||
if (this._needs_key) {
|
||||
game_show_message('YOU NEED THE KEY...');
|
||||
return;
|
||||
}
|
||||
this._reset_state_at = game_time + 3;
|
||||
}
|
||||
|
||||
if (this._reset_state_at < game_time) {
|
||||
this._open = Math.max(0, this._open-game_tick);
|
||||
}
|
||||
else {
|
||||
this._open = Math.min(1, this._open+game_tick);
|
||||
}
|
||||
|
||||
this.p = vec3_add(this._start_pos, vec3_rotate_y(vec3(96 * this._open,0,0), this._yaw));
|
||||
}
|
||||
|
||||
_receive_damage() {}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
|
||||
class entity_enemy_t extends entity_t {
|
||||
_init(patrol_dir) {
|
||||
|
||||
// Animations
|
||||
this._ANIMS =[
|
||||
[1, [0]], // 0: Idle
|
||||
[0.40, [1,2,3,4]], // 1: Walk
|
||||
[0.20, [1,2,3,4]], // 2: Run
|
||||
[0.25, [0,5,5,5]], // 3: Attack prepare
|
||||
[0.25, [5,0,0,0]], // 4: Attack
|
||||
];
|
||||
|
||||
// State definitions
|
||||
// [0: anim_index, 1: speed, 2: next_state_update, 3: next_state]
|
||||
this._STATE_IDLE = [0, 0, 0.1];
|
||||
this._STATE_PATROL = [1, 0.5, 0.5];
|
||||
this._STATE_FOLLOW = [2, 1, 0.3];
|
||||
this._STATE_ATTACK_RECOVER = [0, 0, 0.1, this._STATE_FOLLOW];
|
||||
this._STATE_ATTACK_EXEC = [4, 0, 0.4, this._STATE_ATTACK_RECOVER];
|
||||
this._STATE_ATTACK_PREPARE = [3, 0, 0.4, this._STATE_ATTACK_EXEC];
|
||||
this._STATE_ATTACK_AIM = [0, 0, 0.1, this._STATE_ATTACK_PREPARE];
|
||||
this._STATE_EVADE = [2, 1, 0.8, this._STATE_ATTACK_AIM];
|
||||
|
||||
this.s = vec3(12,28,12);
|
||||
|
||||
this._step_height = 17;
|
||||
this._speed = 196;
|
||||
|
||||
this._target_yaw = this._yaw;
|
||||
this._state_update_at = 0;
|
||||
this._attack_distance = 800;
|
||||
this._evade_distance = 96;
|
||||
this._attack_chance = 0.65;
|
||||
this._keep_off_ledges = 1;
|
||||
this._turn_bias = 1;
|
||||
|
||||
this._check_against = ENTITY_GROUP_PLAYER;
|
||||
|
||||
game_entities_enemies.push(this);
|
||||
|
||||
// If patrol_dir is non-zero it determines the partrol direction in
|
||||
// increments of 90°. Otherwise we just idle.
|
||||
if (patrol_dir) {
|
||||
this._set_state(this._STATE_PATROL);
|
||||
this._target_yaw = (Math.PI/2) * patrol_dir;
|
||||
this._anim_time = Math.random();
|
||||
}
|
||||
else {
|
||||
this._set_state(this._STATE_IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
_set_state(state) {
|
||||
this._state = state;
|
||||
this._anim = this._ANIMS[state[0]];
|
||||
this._anim_time = 0;
|
||||
this._state_update_at = game_time + state[2] + state[2]/4 * Math.random();
|
||||
}
|
||||
|
||||
_update() {
|
||||
// Is it time for a state update?
|
||||
if (this._state_update_at < game_time) {
|
||||
|
||||
// Choose a new turning bias for FOLLOW/EVADE when we hit a wall
|
||||
this._turn_bias = Math.random() > 0.5 ? 0.5 : -0.5;
|
||||
|
||||
let distance_to_player = vec3_dist(this.p, game_entity_player.p),
|
||||
angle_to_player = vec3_2d_angle(this.p, game_entity_player.p);
|
||||
|
||||
if (this._state[3]) {
|
||||
this._set_state(this._state[3]);
|
||||
}
|
||||
|
||||
// Try to minimize distance to the player
|
||||
if (this._state == this._STATE_FOLLOW) {
|
||||
|
||||
// Do we have a line of sight?
|
||||
if (!map_trace(this.p, game_entity_player.p)) {
|
||||
this._target_yaw = angle_to_player;
|
||||
}
|
||||
|
||||
// Are we close enough to attack?
|
||||
if (distance_to_player < this._attack_distance) {
|
||||
|
||||
// Are we too close? Evade!
|
||||
if (
|
||||
distance_to_player < this._evade_distance ||
|
||||
Math.random() > this._attack_chance
|
||||
) {
|
||||
this._set_state(this._STATE_EVADE);
|
||||
this._target_yaw += Math.PI/2 + Math.random() * Math.PI;
|
||||
}
|
||||
|
||||
// Just the right distance to attack!
|
||||
else {
|
||||
this._set_state(this._STATE_ATTACK_AIM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We just attacked; just keep looking at the player 0_o
|
||||
if (this._state == this._STATE_ATTACK_RECOVER) {
|
||||
this._target_yaw = angle_to_player;
|
||||
}
|
||||
|
||||
// Wake up from patroling or idlyng if we have a line of sight
|
||||
// and are near enough
|
||||
if (this._state == this._STATE_PATROL || this._state == this._STATE_IDLE) {
|
||||
if (
|
||||
distance_to_player < 700 &&
|
||||
!map_trace(this.p, game_entity_player.p)
|
||||
) {
|
||||
this._set_state(this._STATE_ATTACK_AIM);
|
||||
}
|
||||
}
|
||||
|
||||
// Aiming - reorient the entity towards the player, check
|
||||
// if we have a line of sight
|
||||
if (this._state == this._STATE_ATTACK_AIM) {
|
||||
this._target_yaw = angle_to_player;
|
||||
|
||||
// No line of sight? Randomly shuffle around :/
|
||||
if (map_trace(this.p, game_entity_player.p)) {
|
||||
this._set_state(this._STATE_EVADE);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the attack!
|
||||
if (this._state == this._STATE_ATTACK_EXEC) {
|
||||
this._attack();
|
||||
}
|
||||
}
|
||||
|
||||
// Rotate to desired angle
|
||||
this._yaw += anglemod(this._target_yaw - this._yaw) * 0.1;
|
||||
|
||||
|
||||
// Move along the yaw direction with the current speed (which might be 0)
|
||||
if (this._on_ground) {
|
||||
this.v = vec3_rotate_y(vec3(0, this.v.y, this._state[1] * this._speed), this._target_yaw);
|
||||
}
|
||||
|
||||
this._update_physics();
|
||||
this._draw_model();
|
||||
}
|
||||
|
||||
_spawn_projectile(type, speed, yaw_offset, pitch_offset) {
|
||||
let projectile = game_spawn(type, this.p);
|
||||
projectile._check_against = ENTITY_GROUP_PLAYER;
|
||||
projectile._yaw = this._yaw + Math.PI/2;
|
||||
|
||||
projectile.v = vec3_rotate_yaw_pitch(
|
||||
vec3(0, 0, speed),
|
||||
this._yaw + yaw_offset,
|
||||
Math.atan2(
|
||||
this.p.y-game_entity_player.p.y,
|
||||
vec3_dist(this.p, game_entity_player.p)
|
||||
) + pitch_offset
|
||||
);
|
||||
return projectile;
|
||||
}
|
||||
|
||||
_receive_damage(from, amount) {
|
||||
super._receive_damage(from, amount);
|
||||
this._play_sound(sfx_enemy_hit);
|
||||
|
||||
// Wake up if we're idle or patrolling
|
||||
if (this._state == this._STATE_IDLE || this._state == this._STATE_PATROL) {
|
||||
this._target_yaw = vec3_2d_angle(this.p, game_entity_player.p);
|
||||
this._set_state(this._STATE_FOLLOW);
|
||||
}
|
||||
|
||||
this._spawn_particles(2, 200, model_blood, 18, 0.5);
|
||||
}
|
||||
|
||||
_kill() {
|
||||
super._kill();
|
||||
for (let m of model_gib_pieces) {
|
||||
this._spawn_particles(2, 300, m, 18, 1);
|
||||
}
|
||||
this._play_sound(sfx_enemy_gib);
|
||||
game_entities_enemies = game_entities_enemies.filter(e => e != this);
|
||||
}
|
||||
|
||||
_did_collide(axis) {
|
||||
if (axis == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we hit a wall/ledge while patrolling just turn around 180
|
||||
if (this._state == this._STATE_PATROL) {
|
||||
this._target_yaw += Math.PI;
|
||||
}
|
||||
else {
|
||||
this._target_yaw += this._turn_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
class entity_enemy_enforcer_t extends entity_enemy_t {
|
||||
_init(patrol_dir) {
|
||||
super._init(patrol_dir);
|
||||
this._model = model_enforcer;
|
||||
this._texture = 19;
|
||||
this._health = 80;
|
||||
this.s = vec3(14,44,14);
|
||||
}
|
||||
|
||||
_attack() {
|
||||
this._play_sound(sfx_plasma_shoot);
|
||||
this._spawn_projectile(entity_projectile_plasma_t, 800, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
class entity_enemy_grunt_t extends entity_enemy_t {
|
||||
_init(patrol_dir) {
|
||||
super._init(patrol_dir);
|
||||
this._model = model_grunt;
|
||||
this._texture = 17;
|
||||
this._health = 40;
|
||||
}
|
||||
|
||||
_attack() {
|
||||
this._play_sound(sfx_shotgun_shoot);
|
||||
game_spawn(entity_light_t, vec3_add(this.p, vec3(0,30,0)), 10, 0xff)._die_at = game_time + 0.1;
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
this._spawn_projectile(
|
||||
entity_projectile_shell_t, 10000,
|
||||
Math.random()*0.08-0.04, Math.random()*0.08-0.04
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
class entity_enemy_hound_t extends entity_enemy_t {
|
||||
_init(patrol_dir) {
|
||||
super._init(patrol_dir);
|
||||
this._model = model_hound;
|
||||
this._texture = 22;
|
||||
this._health = 25;
|
||||
this._check_against = ENTITY_GROUP_PLAYER;
|
||||
|
||||
this.s = vec3(12,16,12);
|
||||
|
||||
this._attack_distance = 200;
|
||||
this._evade_distance = 64;
|
||||
this._attack_chance = 0.7;
|
||||
this._speed = 256;
|
||||
|
||||
this._ANIMS = [
|
||||
[1, [0]], // 0: Idle
|
||||
[0.15, [0,1]], // 2: Run
|
||||
[0.15, [0,1]], // 2: Run
|
||||
[1, [0]], // 3: Attack prepare
|
||||
[0.1, [0,1,1,1,0,0,0]], // 4: Attack
|
||||
];
|
||||
|
||||
this._STATE_PATROL = [1, 0.2, 0.5];
|
||||
this._STATE_ATTACK_RECOVER = [0, 0, 0.5, this._STATE_FOLLOW];
|
||||
this._STATE_ATTACK_EXEC = [4, 0, 1, this._STATE_ATTACK_RECOVER];
|
||||
this._STATE_ATTACK_PREPARE = [3, 0, 0.0, this._STATE_ATTACK_EXEC];
|
||||
this._STATE_ATTACK_AIM = [0, 0, 0.0, this._STATE_ATTACK_PREPARE];
|
||||
this._STATE_EVADE = [2, 1, 0.3, this._STATE_ATTACK_AIM];
|
||||
|
||||
this._set_state(this._STATE_IDLE);
|
||||
}
|
||||
|
||||
_did_collide_with_entity(other) {
|
||||
if (!this._did_hit && this._state == this._STATE_ATTACK_EXEC) {
|
||||
this._did_hit = 1;
|
||||
other._receive_damage(this, 14);
|
||||
}
|
||||
}
|
||||
|
||||
_attack() {
|
||||
this._play_sound(sfx_enemy_hound_attack);
|
||||
this.v = vec3_rotate_y(vec3(0, 250, 600), this._target_yaw);
|
||||
this._on_ground = 0;
|
||||
this._did_hit = 0;
|
||||
|
||||
// Ignore ledges while attacking
|
||||
this._keep_off_ledges = 0;
|
||||
clearTimeout(this._reset_ledges);
|
||||
this._reset_ledges = setTimeout(()=>this._keep_off_ledges = 1, 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
class entity_enemy_ogre_t extends entity_enemy_t {
|
||||
_init(patrol_dir) {
|
||||
super._init(patrol_dir);
|
||||
this._model = model_ogre;
|
||||
this._texture = 20;
|
||||
this._speed = 96;
|
||||
this._health = 200;
|
||||
this.s = vec3(14,36,14);
|
||||
|
||||
this._attack_distance = 350;
|
||||
this._ANIMS =[
|
||||
[1, [0]], // 0: Idle
|
||||
[0.80, [1,2,3,4]], // 1: Walk
|
||||
[0.40, [1,2,3,4]], // 2: Run
|
||||
[0.35, [0,5,5,5]], // 3: Attack prepare
|
||||
[0.35, [5,0,0,0]], // 4: Attack
|
||||
];
|
||||
}
|
||||
|
||||
_attack() {
|
||||
this._play_sound(sfx_grenade_shoot);
|
||||
this._spawn_projectile(entity_projectile_grenade_t, 600, 0, -0.4)._damage = 40;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
class entity_enemy_zombie_t extends entity_enemy_t {
|
||||
_init(patrol_dir) {
|
||||
super._init(patrol_dir);
|
||||
this._model = model_zombie;
|
||||
this._texture = 18;
|
||||
this._speed = 0;
|
||||
this._attack_distance = 350;
|
||||
this._health = 60;
|
||||
|
||||
this._ANIMS[3] = [0.25, [0,0,5,5]]; // 3: Attack prepare
|
||||
|
||||
this._STATE_FOLLOW = [0, 0, 0.1];
|
||||
this._STATE_ATTACK_RECOVER = [0, 0, 1.1, this._STATE_IDLE];
|
||||
this._STATE_ATTACK_EXEC = [4, 0, 0.4, this._STATE_ATTACK_RECOVER];
|
||||
this._STATE_ATTACK_PREPARE = [3, 0, 0.4, this._STATE_ATTACK_EXEC];
|
||||
this._STATE_ATTACK_AIM = [0, 0, 0.1, this._STATE_ATTACK_PREPARE];
|
||||
this._STATE_EVADE = [0, 0, 0.1, this._STATE_ATTACK_AIM];
|
||||
|
||||
this._set_state(this._STATE_IDLE);
|
||||
}
|
||||
|
||||
_receive_damage(from, amount) {
|
||||
// Ignore damage that's not large enough to gib us
|
||||
if (amount > 60) {
|
||||
super._receive_damage(from, amount)
|
||||
}
|
||||
}
|
||||
|
||||
_attack() {
|
||||
this._play_sound(sfx_enemy_hit);
|
||||
this._spawn_projectile(entity_projectile_gib_t, 600, 0, -0.5);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
class entity_light_t extends entity_t {
|
||||
_init(light, color) {
|
||||
this._light = light;
|
||||
this._spawn_time = game_time;
|
||||
if (light == 1) {
|
||||
this._flicker = true;
|
||||
}
|
||||
if (!color) {
|
||||
console.log('no color!')
|
||||
}
|
||||
this._color = [
|
||||
((color & 0x7) << 5),
|
||||
((color & 0x1c) << 3),
|
||||
(color & 0xc0)
|
||||
];
|
||||
}
|
||||
|
||||
_update() {
|
||||
if (this._flicker && Math.random() > 0.9) {
|
||||
this._light = Math.random() > 0.5 ? 10 : 0;
|
||||
}
|
||||
let intensity = this._light;
|
||||
|
||||
// If this light is a temporary one, fade it out over its lifetime
|
||||
if (this._die_at) {
|
||||
if (this._die_at < game_time) {
|
||||
this._kill();
|
||||
}
|
||||
intensity = scale(game_time, this._spawn_time, this._die_at, 1, 0) * this._light;
|
||||
}
|
||||
|
||||
r_push_light(this.p, intensity, this._color[0], this._color[1], this._color[2]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
class entity_particle_t extends entity_t {
|
||||
_init() {
|
||||
this._bounciness = 0.5;
|
||||
this.f = 0.1;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._yaw += this.v.y * 0.001;
|
||||
this._pitch += this.v.x * 0.001;
|
||||
this._update_physics();
|
||||
this._draw_model();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
class entity_pickup_t extends entity_t {
|
||||
_init() {
|
||||
this._model = model_pickup_box;
|
||||
this.s = vec3(12,12,12);
|
||||
this._yaw += Math.PI/2;
|
||||
}
|
||||
|
||||
_update() {
|
||||
if (!this._on_ground) {
|
||||
this._update_physics();
|
||||
}
|
||||
this._draw_model();
|
||||
if (vec3_dist(this.p, game_entity_player.p) < 40) {
|
||||
this._pickup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
class entity_pickup_grenadelauncher_t extends entity_pickup_t {
|
||||
_init() {
|
||||
super._init();
|
||||
this._texture = 21;
|
||||
this._model = model_pickup_grenadelauncher;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._yaw += 0.02;
|
||||
super._update();
|
||||
}
|
||||
|
||||
_pickup() {
|
||||
audio_play(sfx_pickup);
|
||||
game_entity_player._weapon_index = game_entity_player._weapons.push(new weapon_grenadelauncher_t) - 1;
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
class entity_pickup_grenades_t extends entity_pickup_t {
|
||||
_init() {
|
||||
super._init();
|
||||
this._texture = 25;
|
||||
this._model = model_pickup_grenades;
|
||||
}
|
||||
|
||||
_pickup() {
|
||||
for (let w of game_entity_player._weapons) {
|
||||
if (w instanceof(weapon_grenadelauncher_t)) {
|
||||
w._ammo += 10;
|
||||
audio_play(sfx_pickup);
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
class entity_pickup_health_t extends entity_pickup_t {
|
||||
_init() {
|
||||
super._init();
|
||||
this._texture = 23;
|
||||
}
|
||||
|
||||
_pickup() {
|
||||
audio_play(sfx_pickup);
|
||||
game_entity_player._health += 25;
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
|
||||
class entity_pickup_key_t extends entity_pickup_t {
|
||||
_init() {
|
||||
super._init();
|
||||
this._texture = 21;
|
||||
this._model = model_pickup_key;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._yaw += 0.02;
|
||||
super._update();
|
||||
}
|
||||
|
||||
_pickup() {
|
||||
audio_play(sfx_pickup);
|
||||
game_show_message('YOU GOT THE KEY!');
|
||||
for (let e of game_entities) {
|
||||
if (e._needs_key) {
|
||||
e._needs_key = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
class entity_pickup_nailgun_t extends entity_pickup_t {
|
||||
_init() {
|
||||
super._init();
|
||||
this._texture = 12;
|
||||
this._model = model_pickup_nailgun;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._yaw += 0.02;
|
||||
super._update();
|
||||
}
|
||||
|
||||
_pickup() {
|
||||
audio_play(sfx_pickup);
|
||||
game_entity_player._weapon_index = game_entity_player._weapons.push(new weapon_nailgun_t) - 1;
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
class entity_pickup_nails_t extends entity_pickup_t {
|
||||
_init() {
|
||||
super._init();
|
||||
this._texture = 24;
|
||||
}
|
||||
|
||||
_pickup() {
|
||||
for (let w of game_entity_player._weapons) {
|
||||
if (w instanceof(weapon_nailgun_t)) {
|
||||
w._ammo += 50;
|
||||
audio_play(sfx_pickup);
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
|
||||
class entity_player_t extends entity_t {
|
||||
_init() {
|
||||
this.s = vec3(12,24,12);
|
||||
this.f = 10;
|
||||
this._speed = 3000;
|
||||
this._step_height = 17;
|
||||
this._can_jump = 0;
|
||||
this._can_shoot_at = 0;
|
||||
this._health = 100;
|
||||
|
||||
this._check_against = ENTITY_GROUP_ENEMY;
|
||||
|
||||
this._weapons = [new weapon_shotgun_t];
|
||||
this._weapon_index = 0;
|
||||
|
||||
// Map 1 needs some rotation of the starting look-at direction
|
||||
this._yaw += game_map_index * Math.PI;
|
||||
this._bob = 0;
|
||||
|
||||
game_entity_player = this;
|
||||
game_entities_friendly.push(this);
|
||||
}
|
||||
|
||||
_update() {
|
||||
// Mouse look
|
||||
this._pitch = clamp(this._pitch + mouse_y * m.value * 0.00015, -1.5, 1.5);
|
||||
this._yaw = (this._yaw + mouse_x * m.value * 0.00015) % (Math.PI*2);
|
||||
|
||||
// Acceleration in movement direction
|
||||
this.a = vec3_mulf(
|
||||
vec3_rotate_y(
|
||||
vec3(
|
||||
keys[key_right] - keys[key_left],
|
||||
0,
|
||||
keys[key_up] - keys[key_down]
|
||||
),
|
||||
this._yaw
|
||||
),
|
||||
this._speed * (this._on_ground ? 1 : 0.3)
|
||||
);
|
||||
|
||||
if (keys[key_jump] && this._on_ground && this._can_jump) {
|
||||
this.v.y = 400;
|
||||
this._on_ground = 0;
|
||||
this._can_jump = 0;
|
||||
}
|
||||
if (!keys[key_jump]) {
|
||||
this._can_jump = 1;
|
||||
}
|
||||
|
||||
this._weapon_index = (
|
||||
this._weapon_index + keys[key_next] + this._weapons.length - keys[key_prev]
|
||||
) % this._weapons.length;
|
||||
|
||||
let shoot_wait = this._can_shoot_at - game_time,
|
||||
weapon = this._weapons[this._weapon_index];
|
||||
|
||||
// Shoot Weapon
|
||||
if (keys[key_action] && shoot_wait < 0) {
|
||||
this._can_shoot_at = game_time + weapon._reload;
|
||||
|
||||
if (weapon._needs_ammo && weapon._ammo == 0) {
|
||||
audio_play(sfx_no_ammo);
|
||||
}
|
||||
else {
|
||||
weapon._shoot(this.p, this._yaw, this._pitch);
|
||||
game_spawn(entity_light_t, this.p, 10, 0xff)._die_at = game_time + 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
this._bob += vec3_length(this.a) * 0.0001;
|
||||
this.f = this._on_ground ? 10 : 2.5;
|
||||
this._update_physics();
|
||||
|
||||
r_camera.x = this.p.x;
|
||||
r_camera.z = this.p.z;
|
||||
|
||||
// Smooth step up on stairs
|
||||
r_camera.y = this.p.y + 8 - clamp(game_time - this._stepped_up_at, 0, 0.1) * -160;
|
||||
|
||||
r_camera_yaw = this._yaw;
|
||||
r_camera_pitch = this._pitch;
|
||||
|
||||
|
||||
// Draw weapon at camera position at an offset and add the current
|
||||
// recoil (calculated from shoot_wait and weapon._reload) accounting
|
||||
// for the current view yaw/pitch
|
||||
|
||||
r_draw(
|
||||
vec3_add(
|
||||
r_camera,
|
||||
vec3_rotate_yaw_pitch(
|
||||
vec3(
|
||||
0,
|
||||
-10 + Math.sin(this._bob)*0.3,
|
||||
12 + clamp(scale(shoot_wait, 0, weapon._reload, 5, 0), 0, 5)
|
||||
),
|
||||
this._yaw, this._pitch
|
||||
)
|
||||
),
|
||||
this._yaw + Math.PI/2, this._pitch,
|
||||
weapon._texture, weapon._model.f[0], weapon._model.f[0], 0,
|
||||
weapon._model.nv
|
||||
);
|
||||
|
||||
h.textContent = this._health|0;
|
||||
a.textContent = weapon._needs_ammo ? weapon._ammo : '∞';
|
||||
|
||||
// Debug: a light around the player
|
||||
// r_push_light(vec3_add(this.p, vec3(0,64,0)), 10, 255, 192, 32);
|
||||
}
|
||||
|
||||
_receive_damage(from, amount) {
|
||||
audio_play(sfx_hurt);
|
||||
super._receive_damage(from, amount);
|
||||
}
|
||||
|
||||
_kill() {
|
||||
super._kill();
|
||||
h.textContent = this._health|0;
|
||||
title_show_message('YOU DIED');
|
||||
setTimeout(() => game_init(game_map_index), 2000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
class entity_projectile_gib_t extends entity_t {
|
||||
_init() {
|
||||
this._texture = 18;
|
||||
this._bounciness = 0;
|
||||
this._die_at = game_time + 2;
|
||||
this._model = model_gib;
|
||||
|
||||
this._yaw = Math.random();
|
||||
this._pitch = Math.random();
|
||||
}
|
||||
|
||||
_update() {
|
||||
super._update_physics();
|
||||
this._draw_model();
|
||||
this.f = this._on_ground ? 15 : 0;
|
||||
}
|
||||
|
||||
_did_collide(axis) {
|
||||
if (axis == 1 && this.v.y < -128) {
|
||||
this._play_sound(sfx_enemy_hit);
|
||||
}
|
||||
}
|
||||
|
||||
_did_collide_with_entity(other) {
|
||||
other._receive_damage(this, 10);
|
||||
this._kill();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
class entity_projectile_grenade_t extends entity_t {
|
||||
_init() {
|
||||
this._texture = 8;
|
||||
this._model = model_grenade;
|
||||
this._die_at = game_time + 2;
|
||||
this._bounciness = 0.5;
|
||||
this._damage = 120;
|
||||
}
|
||||
|
||||
_update() {
|
||||
super._update_physics();
|
||||
this._draw_model();
|
||||
r_push_light(vec3_add(this.p, vec3(0,16,0)), (Math.sin(game_time*10)+2)*0.5, 255, 32, 0);
|
||||
this.f = this._on_ground ? 5 : 0.5;
|
||||
}
|
||||
|
||||
_did_collide(axis) {
|
||||
if (axis != 1 || this.v.y < -128) {
|
||||
this._yaw += Math.random();
|
||||
this._play_sound(sfx_grenade_bounce);
|
||||
}
|
||||
}
|
||||
|
||||
_did_collide_with_entity(other) {
|
||||
this._kill();
|
||||
}
|
||||
|
||||
_kill() {
|
||||
// Deal some damage to nearby entities
|
||||
for (let entity of this._check_entities) {
|
||||
let dist = vec3_dist(this.p, entity.p);
|
||||
if (dist < 196) {
|
||||
entity._receive_damage(this, scale(dist, 0, 196, this._damage, 0));
|
||||
}
|
||||
}
|
||||
|
||||
super._kill();
|
||||
this._play_sound(sfx_grenade_explode);
|
||||
this._spawn_particles(20, 800, model_explosion, 8, 1);
|
||||
game_spawn(entity_light_t, vec3_add(this.p, vec3(0,16,0)), 250, 0x08f)._die_at = game_time + 0.2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
class entity_projectile_nail_t extends entity_t {
|
||||
_init() {
|
||||
this._texture = 2;
|
||||
this._model = model_nail;
|
||||
this._gravity = 0;
|
||||
this._die_at = game_time + 3;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._update_physics();
|
||||
this._draw_model();
|
||||
}
|
||||
|
||||
_did_collide(axis) {
|
||||
this._kill();
|
||||
this._play_sound(sfx_nailgun_hit);
|
||||
this._spawn_particles(2, 80, model_explosion, 8, 0.4);
|
||||
game_spawn(entity_light_t, this.p, 1, 0xff)._die_at = game_time + 0.1;
|
||||
}
|
||||
|
||||
_did_collide_with_entity(other) {
|
||||
this._kill();
|
||||
other._receive_damage(this, 9);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
class entity_projectile_plasma_t extends entity_t {
|
||||
_init() {
|
||||
this._texture = 21;
|
||||
this._model = model_nail;
|
||||
this._gravity = 0;
|
||||
this._die_at = game_time + 3;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._update_physics();
|
||||
this._draw_model();
|
||||
r_push_light(this.p, 5, 255, 128, 0);
|
||||
}
|
||||
|
||||
_did_collide(axis) {
|
||||
this._kill();
|
||||
this._play_sound(sfx_nailgun_hit);
|
||||
this._spawn_particles(2, 80, model_explosion, 8, 0.4);
|
||||
game_spawn(entity_light_t, vec3_add(this.p, vec3(0,10,0)), 5, 0xf5)._die_at = game_time + 0.1;
|
||||
}
|
||||
|
||||
_did_collide_with_entity(other) {
|
||||
this._kill();
|
||||
other._receive_damage(this, 15);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
class entity_projectile_shell_t extends entity_t {
|
||||
_init() {
|
||||
this._gravity = 0;
|
||||
this._die_at = game_time + 0.1;
|
||||
}
|
||||
|
||||
_update() {
|
||||
this._update_physics();
|
||||
}
|
||||
|
||||
_did_collide(axis) {
|
||||
this._kill();
|
||||
this._spawn_particles(2, 80, model_explosion, 4, 0.4);
|
||||
game_spawn(entity_light_t, this.p, 0.5, 0xff)._die_at = game_time + 0.1;
|
||||
}
|
||||
|
||||
_did_collide_with_entity(other) {
|
||||
this._kill();
|
||||
other._receive_damage(this, 4);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
class entity_torch_t extends entity_t {
|
||||
_init() {
|
||||
this._texture = 30;
|
||||
this._model = model_torch;
|
||||
|
||||
this._anim = [0.05, [0,1,2,1,2,0,0,1,2]];
|
||||
|
||||
this.p.x -= 16;
|
||||
this.p.z -= 16;
|
||||
this._light_pos = this.p;
|
||||
|
||||
// Find which wall we're on; move to the torch model towards the wall
|
||||
// and the light position outwards
|
||||
for (let trace_dir of [vec3(-32,0,0), vec3(32,0,0), vec3(0,0,-32), vec3(0,0,32)]) {
|
||||
let trace_end = vec3_add(this.p, trace_dir);
|
||||
if (map_trace(this.p, vec3_add(this.p, trace_dir))) {
|
||||
this.p = vec3_add(this.p, vec3_mulf(trace_dir, 0.4));
|
||||
this._light_pos = vec3_sub(this.p, vec3_mulf(trace_dir, 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._light = 0;
|
||||
}
|
||||
|
||||
_update() {
|
||||
super._update();
|
||||
|
||||
if (Math.random() > 0.8) {
|
||||
this._light = Math.random();
|
||||
}
|
||||
r_push_light(this._light_pos, Math.sin(game_time)+this._light+6, 255,192,16);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
class entity_trigger_level_t extends entity_t {
|
||||
_update() {
|
||||
if (!this._dead && vec3_dist(this.p, game_entity_player.p) < 64) {
|
||||
game_next_level();
|
||||
this._dead = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
|
||||
let
|
||||
game_tick = 0,
|
||||
game_time = 0.016,
|
||||
game_real_time_last,
|
||||
game_message_timeout = 0,
|
||||
|
||||
game_entities,
|
||||
game_entities_enemies,
|
||||
game_entities_friendly,
|
||||
game_entity_player,
|
||||
game_map_index,
|
||||
game_jump_to_next_level,
|
||||
|
||||
game_init = (map_index) => {
|
||||
ts.style.display = 'none',
|
||||
|
||||
game_entities = [];
|
||||
game_entities_enemies = [];
|
||||
game_entities_friendly = [];
|
||||
|
||||
game_map_index = map_index;
|
||||
map_init(map_data[game_map_index]);
|
||||
},
|
||||
|
||||
game_next_level = () => {
|
||||
game_jump_to_next_level = 1;
|
||||
},
|
||||
|
||||
game_spawn = (type, pos, p1, p2) => {
|
||||
let entity = new (type)(pos, p1, p2)
|
||||
game_entities.push(entity);
|
||||
return entity;
|
||||
},
|
||||
|
||||
game_show_message = (text) => {
|
||||
msg.textContent = text;
|
||||
msg.style.display = 'block';
|
||||
clearTimeout(game_message_timeout);
|
||||
game_message_timeout = setTimeout(()=>msg.style.display = 'none', 2000);
|
||||
},
|
||||
|
||||
title_show_message = (msg, sub = '') => {
|
||||
ts.innerHTML = '<h1>'+msg+'</h1>' + sub;
|
||||
ts.style.display = 'block';
|
||||
},
|
||||
|
||||
game_run = (time_now) => {
|
||||
requestAnimationFrame(game_run);
|
||||
|
||||
time_now *= 0.001;
|
||||
game_tick = Math.min((time_now - (game_real_time_last||time_now)),0.05);
|
||||
game_real_time_last = time_now;
|
||||
game_time += game_tick;
|
||||
|
||||
r_prepare_frame(0.1, 0.2, 0.5);
|
||||
|
||||
// Update and render entities
|
||||
let alive_entities = [];
|
||||
for (let entity of game_entities) {
|
||||
if (!entity._dead) {
|
||||
entity._update();
|
||||
alive_entities.push(entity);
|
||||
}
|
||||
}
|
||||
game_entities = alive_entities;
|
||||
|
||||
map_draw();
|
||||
r_end_frame();
|
||||
|
||||
// Reset mouse movement and buttons that should be pressed, not held.
|
||||
mouse_x = mouse_y = 0;
|
||||
keys[key_next] = keys[key_prev] = 0;
|
||||
|
||||
if (game_jump_to_next_level) {
|
||||
game_jump_to_next_level = 0;
|
||||
game_map_index++;
|
||||
if (game_map_index == 2) {
|
||||
title_show_message('THE END', 'THANKS FOR PLAYING ❤');
|
||||
h.textContent = a.textContent = '';
|
||||
game_entity_player._dead = 1;
|
||||
|
||||
// Set camera position for end screen
|
||||
r_camera = vec3(1856,784,2272);
|
||||
r_camera_yaw = 0;
|
||||
r_camera_pitch = 0.5;
|
||||
}
|
||||
else {
|
||||
game_init(game_map_index);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
<!doctype html><html><head><title>Q1K3</title></head><body><script>
|
||||
GAME_SOURCE
|
||||
</script>
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
// We use the ev.code for keyboard input. This contains a string like "KeyW"
|
||||
// or "ArrowLeft", which is awkward to use, but it's keyboard layout neutral,
|
||||
// so that WASD should work with any layout.
|
||||
|
||||
// We detect the 6th or 3rd char for each of those strings and map them to an
|
||||
// in-game button.
|
||||
|
||||
// Movement, Action, Prev/Next, Jump
|
||||
let keymap = {
|
||||
W: 1, p: 1, // Key[W] or ArrowU[p]
|
||||
A: 2, e: 2, // Key[A] or ArrowL[e]ft
|
||||
S: 3, o: 3, // Key[S] or ArrowR[i]ght
|
||||
D: 4, i: 4, // Key[D] or ArrowD[o]wn
|
||||
Q: 5, // Key[Q]
|
||||
E: 6, // Key[E]
|
||||
c: 9, // KeySpa[c]e
|
||||
},
|
||||
keys = [
|
||||
// Unused zeroth key, so we can test the keymap result for truthiness
|
||||
0,
|
||||
|
||||
// WASD/Arrow Keys and prev next have to be set to zero, because we use
|
||||
// the value (0 or 1) to calculate the move direction or weapon switch
|
||||
0,0,0,0,
|
||||
0,0
|
||||
|
||||
// Following Keys (action, jump) to not have to be set here
|
||||
// as they are just tested for truthiness
|
||||
],
|
||||
key_up = 1,
|
||||
key_down = 3,
|
||||
key_left = 2,
|
||||
key_right = 4,
|
||||
key_prev = 5,
|
||||
key_next = 6,
|
||||
key_action = 7, // ev.button = 0
|
||||
key_jump = 9, // ev.button = 2
|
||||
mouse_x = 0,
|
||||
mouse_y = 0,
|
||||
last_wheel_event = 0;
|
||||
|
||||
document.onkeydown = (ev) => {
|
||||
let k = keymap[ev.code[6] || ev.code[3]];
|
||||
if (k) {
|
||||
ev.preventDefault();
|
||||
keys[k] = 1;
|
||||
}
|
||||
};
|
||||
|
||||
document.onkeyup = (ev) => {
|
||||
let k = keymap[ev.code[6] || ev.code[3]];
|
||||
if (k) {
|
||||
ev.preventDefault();
|
||||
keys[k] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
document.onwheel = (ev) => {
|
||||
// Allow for one wheel event every 0.1s. This sucks, but prevents free
|
||||
// spinning or touch scrolling mouses (eg. Apple Magic Mouse) from doing
|
||||
// wild things.
|
||||
if (game_time - last_wheel_event > 0.1) {
|
||||
keys[key_prev + (ev.deltaY > 1 ? 1 : 0)] = 1;
|
||||
last_wheel_event = game_time;
|
||||
}
|
||||
};
|
||||
|
||||
c.onmousemove = (ev) => {
|
||||
mouse_x += ev.movementX;
|
||||
mouse_y += ev.movementY;
|
||||
};
|
||||
|
||||
c.onmousedown = (ev) => {
|
||||
ev.preventDefault();
|
||||
keys[key_action + ev.button] = 1;
|
||||
};
|
||||
|
||||
c.onmouseup = (ev) => {
|
||||
ev.preventDefault();
|
||||
keys[key_action + ev.button] = 0;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
|
||||
let
|
||||
map_data,
|
||||
model_data,
|
||||
|
||||
// Particles
|
||||
model_explosion,
|
||||
model_blood,
|
||||
model_gib,
|
||||
model_gib_pieces = [],
|
||||
|
||||
// Enemies
|
||||
model_grunt,
|
||||
model_enforcer,
|
||||
model_ogre,
|
||||
model_zombie,
|
||||
model_hound,
|
||||
|
||||
// Map Objects
|
||||
model_barrel,
|
||||
model_torch,
|
||||
|
||||
// Weapon view models
|
||||
model_shotgun,
|
||||
model_nailgun,
|
||||
model_grenadelauncher,
|
||||
|
||||
// Pickups
|
||||
model_pickup_nailgun,
|
||||
model_pickup_grenadelauncher,
|
||||
model_pickup_box,
|
||||
model_pickup_grenades,
|
||||
model_pickup_key,
|
||||
model_door,
|
||||
|
||||
// Projectiles
|
||||
model_grenade,
|
||||
model_plasma, // aka. nail
|
||||
|
||||
// Sounds
|
||||
sfx_enemy_hit,
|
||||
sfx_enemy_gib,
|
||||
sfx_enemy_hound_attack,
|
||||
|
||||
sfx_no_ammo,
|
||||
sfx_hurt,
|
||||
|
||||
sfx_plasma_shoot,
|
||||
|
||||
sfx_shotgun_shoot,
|
||||
sfx_shotgun_reload,
|
||||
|
||||
sfx_nailgun_shoot,
|
||||
sfx_nailgun_hit,
|
||||
|
||||
sfx_grenade_shoot,
|
||||
sfx_grenade_bounce,
|
||||
sfx_grenade_explode,
|
||||
|
||||
game_load = async () => {
|
||||
r_init();
|
||||
|
||||
// Create textures
|
||||
ttt(texture_data).map(r_create_texture);
|
||||
|
||||
// Load map & model containers
|
||||
map_data = await map_load_container(/*DEBUG[*/ 'build/' + /*]*/ 'l');
|
||||
model_data = await model_load_container(/*DEBUG[*/ 'build/' + /*]*/ 'm');
|
||||
|
||||
// Create models. Many models share the same geometry just with different
|
||||
// sizes and textures.
|
||||
// 0: generic blob
|
||||
// 1: humanoid
|
||||
// 2: barrel
|
||||
// 3: q logo
|
||||
// 4: hound
|
||||
// 5: box
|
||||
// 6: nailgun
|
||||
// 7: torch
|
||||
|
||||
model_q = model_init(model_data[3]);
|
||||
|
||||
model_explosion = model_init(model_data[0], 0.1,0.1,0.1);
|
||||
model_blood = model_init(model_data[0], 0.1,0.2,0.1);
|
||||
model_gib = model_init(model_data[0], 0.3,0.6,0.3);
|
||||
|
||||
model_grunt = model_init(model_data[1], 2.5,2.2,2.5);
|
||||
model_enforcer = model_init(model_data[1], 3,2.7,3);
|
||||
model_zombie = model_init(model_data[1], 1.5,2,1.5);
|
||||
model_ogre = model_init(model_data[1], 4,3,4);
|
||||
model_hound = model_init(model_data[4],2.5,2.5,2.5);
|
||||
|
||||
model_barrel = model_init(model_data[2], 2, 2, 2);
|
||||
model_torch = model_init(model_data[7], 0.6,1,0.6);
|
||||
|
||||
model_pickup_nailgun = model_init(model_data[6], 1, 1, 1);
|
||||
model_pickup_grenadelauncher = model_init(model_data[2], 1, 0.5, 0.5);
|
||||
model_pickup_box = model_init(model_data[5], 0.7, 0.7, 0.7);
|
||||
model_pickup_grenades = model_init(model_data[5], 0.5, 1, 0.5);
|
||||
model_pickup_key = model_init(model_data[5], 0.1, 0.7, 0.1);
|
||||
|
||||
model_door = model_init(model_data[5], 5, 5, 0.5);
|
||||
|
||||
model_shotgun = model_init(model_data[2], 1,0.2,0.2);
|
||||
model_grenadelauncher = model_init(model_data[2], 0.7,0.4,0.4);
|
||||
model_nailgun = model_init(model_data[6], 0.7,0.7,0.7);
|
||||
|
||||
model_grenade = model_init(model_data[2], 0.3,0.3,0.3);
|
||||
model_nail = model_init(model_data[2], 0.5,0.1,0.1);
|
||||
|
||||
// Take some parts from the grunt model and build individual giblet models
|
||||
// from it. Arms and legs and stuff...
|
||||
for (let i = 0; i < 204; i+=34) {
|
||||
let m = model_init(model_data[1], 2,1,2);
|
||||
m.f[0] += i;
|
||||
m.nv = 34;
|
||||
model_gib_pieces.push(m);
|
||||
}
|
||||
|
||||
|
||||
r_submit_buffer();
|
||||
requestAnimationFrame(run_frame);
|
||||
|
||||
f.onclick = () => g.requestFullscreen();
|
||||
g.onclick = () => {
|
||||
g.onclick = () => c.requestPointerLock();
|
||||
g.onclick();
|
||||
// title_show_message('...');
|
||||
|
||||
audio_init();
|
||||
|
||||
setTimeout(()=> {
|
||||
// Generate sounds
|
||||
sfx_enemy_hit = audio_create_sound(135, [8,0,0,1,148,1,3,5,0,0,139,1,0,2653,0,2193,255,2,639,119,2,23,0,0,0,0,0,0,0]);
|
||||
sfx_enemy_gib = audio_create_sound(140, [7,0,0,1,148,1,7,5,0,1,139,1,0,4611,789,15986,195,2,849,119,3,60,0,0,0,1,10,176,1]);
|
||||
sfx_enemy_hound_attack = audio_create_sound(132, [8,0,0,1,192,1,8,0,0,1,120,1,0,5614,0,20400,192,1,329,252,1,55,0,0,1,1,8,192,3]);
|
||||
|
||||
sfx_no_ammo = audio_create_sound(120, [8,0,0,0,96,1,8,0,0,0,0,0,255,0,0,1075,232,1,2132,255,0,0,0,0,0,0,0,0,0]);
|
||||
sfx_hurt = audio_create_sound(135, [7,3,140,1,232,3,8,0,9,1,139,3,0,4611,1403,34215,256,4,1316,255,0,0,0,1,0,1,7,255,0]);
|
||||
sfx_pickup = audio_create_sound(140, [7,0,0,1,187,3,8,0,0,1,204,3,0,4298,927,1403,255,0,0,0,3,35,0,0,0,0,0,0,0]);
|
||||
|
||||
sfx_plasma_shoot = audio_create_sound(135, [8,0,0,1,147,1,6,0,0,1,159,1,0,197,1234,21759,232,2,2902,255,2,53,0,0,0,0,0,0,0]);
|
||||
|
||||
sfx_shotgun_shoot = audio_create_sound(135, [7,3,0,1,255,1,6,0,0,1,255,1,112,548,1979,11601,255,2,2902,176,2,77,0,0,1,0,10,255,1]);
|
||||
sfx_shotgun_reload = audio_create_sound(125, [9,0,0,1,131,1,0,0,0,0,0,3,255,137,22,1776,255,2,4498,176,2,36,2,84,0,0,3,96,0]);
|
||||
|
||||
sfx_nailgun_shoot = audio_create_sound(130, [7,0,0,1,132,1,8,4,0,1,132,2,162,0,0,8339,232,2,2844,195,2,40,0,0,0,0,0,0,0]);
|
||||
sfx_nailgun_hit = audio_create_sound(135, [8,0,0,1,148,1,0,0,0,0,0,1,255,0,0,2193,128,2,6982,119,2,23,0,0,0,0,0,0,0]);
|
||||
|
||||
sfx_grenade_shoot = audio_create_sound(127, [8,0,0,1,171,1,9,3,0,1,84,3,96,2653,0,13163,159,2,3206,255,2,64,0,0,0,1,9,226,0]);
|
||||
sfx_grenade_bounce = audio_create_sound(168, [7,0,124,0,128,0,8,5,127,0,128,0,125,88,0,2193,125,1,1238,240,1,91,3,47,0,0,0,0,0]);
|
||||
sfx_grenade_explode = audio_create_sound(135, [8,0,0,1,195,1,6,0,0,1,127,1,255,197,1234,21759,232,2,1052,255,4,73,3,25,1,0,10,227,1]);
|
||||
|
||||
|
||||
audio_play(audio_create_song(...music_data), 1, 1);
|
||||
game_init(0);
|
||||
run_frame = game_run;
|
||||
},100); // Not sure why such a long delay is needed. Ideally we would
|
||||
// want to use requestAnimationFrame, but the previous DOM
|
||||
// update (...) never makes it to the screen then ;/
|
||||
};
|
||||
},
|
||||
|
||||
run_frame = (time_now) => {
|
||||
r_prepare_frame();
|
||||
|
||||
r_draw(
|
||||
vec3(0,0,0), 0, 0, 1,
|
||||
model_q.f[0], model_q.f[0], 0,
|
||||
model_q.nv
|
||||
);
|
||||
r_push_light(
|
||||
vec3(Math.sin(time_now*0.00033)*200, 100, -100),
|
||||
10, 255,192,32
|
||||
);
|
||||
r_push_light(
|
||||
vec3_rotate_y(vec3(0, 0, 100),time_now*0.00063),
|
||||
10, 32,64,255
|
||||
);
|
||||
r_push_light(
|
||||
vec3_rotate_y(vec3(100, 0, 0),time_now*0.00053),
|
||||
10, 196,128,255
|
||||
);
|
||||
|
||||
r_end_frame();
|
||||
requestAnimationFrame(run_frame);
|
||||
};
|
||||
|
||||
game_load();
|
||||
@@ -0,0 +1,170 @@
|
||||
|
||||
let
|
||||
map,
|
||||
map_size = 128,
|
||||
|
||||
map_load_container = async (path) => {
|
||||
/* Parse map container format
|
||||
typedef struct {
|
||||
u8 x, y, z;
|
||||
u8 sx, sy, sz;
|
||||
} block_t;
|
||||
|
||||
typedef struct {
|
||||
u8 sentinel;
|
||||
u8 tex;
|
||||
} block_texture_t;
|
||||
|
||||
typedef struct {
|
||||
char type;
|
||||
u8 x, y, z;
|
||||
u8 data1, data2;
|
||||
} entity_t;
|
||||
|
||||
struct {
|
||||
u16 blocks_size;
|
||||
block_t blocks[];
|
||||
u16 num_entities;
|
||||
entity_t entities[num_entities];
|
||||
} map_data;
|
||||
|
||||
Block data is interleaved with the block_texture_t struct to denote
|
||||
the texture index to use for the following blocks.
|
||||
*/
|
||||
|
||||
let data = new Uint8Array(await (await fetch(path)).arrayBuffer()),
|
||||
maps = [];
|
||||
for (let i = 0; i < data.length;) {
|
||||
let blocks_size = data[i++] | (data[i++] << 8),
|
||||
cm = new Uint8Array(map_size * map_size * map_size >> 3), // collision map
|
||||
nm = new Uint8Array(map_size * map_size * map_size >> 3), // nav map
|
||||
b = data.subarray(i, i += blocks_size),
|
||||
r = [],
|
||||
t;
|
||||
|
||||
// Parse block data and construct geometry and the collision map
|
||||
for (let j = 0; j < b.length;) {
|
||||
|
||||
// First value is either the x coordinate or a texture change
|
||||
// sentinel value (255) followed by the texture coordinate
|
||||
if (b[j] == 255) {
|
||||
j++;
|
||||
t = b[j++];
|
||||
}
|
||||
let
|
||||
x = b[j++], y = b[j++], z = b[j++],
|
||||
sx = b[j++], sy = b[j++], sz = b[j++];
|
||||
|
||||
// Submit the block to the render buffer; we get the vertex offset
|
||||
// of this block within the buffer back, so we can draw it later
|
||||
r.push({
|
||||
t,
|
||||
b: r_push_block(
|
||||
x << 5, y << 4, z << 5,
|
||||
sx << 5, sy << 4, sz << 5,
|
||||
t
|
||||
)
|
||||
});
|
||||
|
||||
// The collision map is a bitmap; 8 x blocks per byte
|
||||
for (let cz = z; cz < z + sz; cz++) {
|
||||
for (let cy = y; cy < y + sy; cy++) {
|
||||
for (let cx = x; cx < x + sx; cx++) {
|
||||
cm[
|
||||
(
|
||||
cz * map_size * map_size +
|
||||
cy * map_size +
|
||||
cx
|
||||
) >> 3
|
||||
] |= 1 << (cx & 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Slice of entity data; we parse it when we actually spawn
|
||||
// the entities in map_init()
|
||||
let num_entities = data[i++] | (data[i++] << 8),
|
||||
e = data.subarray(i, i += num_entities * 6 /*sizeof(entity_t)*/);
|
||||
maps.push({cm, e, r});
|
||||
}
|
||||
return maps;
|
||||
},
|
||||
|
||||
map_init = (m) => {
|
||||
map = m;
|
||||
|
||||
// Entity Id to class - must be consistent with map_packer.c line ~900
|
||||
let spawn_class = [
|
||||
/* 00 */ entity_player_t,
|
||||
/* 01 */ entity_enemy_grunt_t,
|
||||
/* 02 */ entity_enemy_enforcer_t,
|
||||
/* 03 */ entity_enemy_ogre_t,
|
||||
/* 04 */ entity_enemy_zombie_t,
|
||||
/* 05 */ entity_enemy_hound_t,
|
||||
/* 06 */ entity_pickup_nailgun_t,
|
||||
/* 07 */ entity_pickup_grenadelauncher_t,
|
||||
/* 08 */ entity_pickup_health_t,
|
||||
/* 09 */ entity_pickup_nails_t,
|
||||
/* 10 */ entity_pickup_grenades_t,
|
||||
/* 11 */ entity_barrel_t,
|
||||
/* 12 */ entity_light_t,
|
||||
/* 13 */ entity_trigger_level_t,
|
||||
/* 14 */ entity_door_t,
|
||||
/* 15 */ entity_pickup_key_t,
|
||||
/* 16 */ entity_torch_t,
|
||||
];
|
||||
|
||||
// Parse entity data and spawn all entities for this map
|
||||
for (let i = 0; i < map.e.length;) {
|
||||
let type = spawn_class[m.e[i++]];
|
||||
game_spawn(
|
||||
type,
|
||||
vec3(m.e[i++] * 32, m.e[i++] * 16, m.e[i++] * 32),
|
||||
m.e[i++], m.e[i++]
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
map_block_at = (x, y, z) =>
|
||||
map.cm[
|
||||
(
|
||||
z * map_size * map_size +
|
||||
y * map_size +
|
||||
x
|
||||
) >> 3
|
||||
] & (1 << (x & 7)),
|
||||
|
||||
map_trace = (a, b) => {
|
||||
let diff = vec3_sub(b, a),
|
||||
step_dir = vec3_mulf(vec3_normalize(diff), 16),
|
||||
steps = vec3_length(diff)/16;
|
||||
|
||||
for (let i = 0; i < steps; i++) {
|
||||
a = vec3_add(a, step_dir);
|
||||
if (map_block_at(a.x >> 5, a.y >> 4, a.z >> 5)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
map_block_at_box = (box_start, box_end) => {
|
||||
for (let z = box_start.z >> 5; z <= box_end.z >> 5; z++) {
|
||||
for (let y = box_start.y >> 4; y <= box_end.y >> 4; y++) {
|
||||
for (let x = box_start.x >> 5; x <= box_end.x >> 5; x++) {
|
||||
if (map_block_at(x, y, z)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
map_draw = () => {
|
||||
let p = vec3();
|
||||
for (let r of map.r) {
|
||||
r_draw(p, 0, 0, r.t, r.b,r.b,0,36);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
let
|
||||
clamp = (v, min, max) => v < min ? min : (v > max ? max : v),
|
||||
scale = (v, in_min, in_max, out_min, out_max) => out_min + ((out_max) - out_min) * (((v) - in_min) / ((in_max) - in_min)),
|
||||
anglemod = (r) => Math.atan2(Math.sin(r), Math.cos(r)),
|
||||
vec3 = (x = 0, y = 0, z = 0) => ({x, y, z}),
|
||||
vec3_rotate_yaw_pitch = (p, yaw, pitch) => vec3_rotate_y(vec3_rotate_x(p, pitch), yaw),
|
||||
vec3_rotate_y = (p, rad) => vec3(p.z * Math.sin(rad) + p.x * Math.cos(rad), p.y, p.z * Math.cos(rad) - p.x * Math.sin(rad)),
|
||||
vec3_rotate_x = (p, rad) => vec3(p.x, p.y * Math.cos(rad) - p.z * Math.sin(rad), p.y * Math.sin(rad) + p.z * Math.cos(rad)),
|
||||
vec3_2d_angle = (a, b) => Math.atan2(b.x - a.x, b.z - a.z),
|
||||
vec3_clone = (a) => vec3(a.x,a.y,a.z),
|
||||
vec3_length = (a) => Math.hypot(a.x,a.y,a.z),
|
||||
vec3_dist = (a, b) => vec3_length(vec3_sub(a, b)),
|
||||
vec3_dot = (a, b) => (a.x * b.x + a.y * b.y + a.z * b.z),
|
||||
vec3_add = (a, b) => vec3(a.x + b.x, a.y + b.y, a.z + b.z),
|
||||
vec3_sub = (a, b) => vec3(a.x - b.x, a.y - b.y, a.z - b.z),
|
||||
vec3_mul = (a, b) => vec3(a.x * b.x, a.y * b.y, a.z * b.z),
|
||||
vec3_mulf = (a, b) => vec3(a.x * b, a.y * b, a.z * b),
|
||||
vec3_cross = (a, b) => vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x),
|
||||
vec3_normalize = (v) => vec3_mulf(v, 1/vec3_length(v)),
|
||||
vec3_face_normal = (v0, v1, v2) => vec3_normalize(vec3_cross(vec3_sub(v0, v1), vec3_sub(v2, v1)));
|
||||
@@ -0,0 +1,107 @@
|
||||
|
||||
let
|
||||
model_load_container = async (path) => {
|
||||
/* Parse Retarded Model Format (.rmf):
|
||||
struct {
|
||||
u8 num_frames;
|
||||
u8 num_verts; // per frame
|
||||
u8 num_indices;
|
||||
struct {
|
||||
u8 x, y, z;
|
||||
} verts[num_frames * num_verts];
|
||||
struct {
|
||||
u8 a_address_inc, b_index, c_index;
|
||||
} indices[num_indices];
|
||||
} rmf_data;
|
||||
*/
|
||||
let data = new Uint8Array(await (await fetch(path)).arrayBuffer()),
|
||||
models = [];
|
||||
|
||||
for (let i = 0; i < data.length;) {
|
||||
// let model_size = num_frames * num_verts * 3 + num_indices * 3
|
||||
let model_size = (data[i++] * data[i++] + data[i++]) * 3;
|
||||
models.push(data.subarray(i-3, i += model_size));
|
||||
}
|
||||
return models;
|
||||
},
|
||||
|
||||
model_init = (data, sx = 1, sy = 1, sz = 1) => {
|
||||
// Load header, prepare buffers
|
||||
let j = 0,
|
||||
num_frames = data[j++],
|
||||
num_vertices = data[j++],
|
||||
num_indices = data[j++],
|
||||
vertices = new Float32Array(num_vertices * num_frames * 3),
|
||||
indices = new Uint8Array(num_indices * 3),
|
||||
|
||||
index_increment = 0,
|
||||
offset = 2,
|
||||
|
||||
// Load vertices, center on origin (-15), scale, find the
|
||||
// min/max x and y to compute our UV coords accordingly.
|
||||
min_x = 16,
|
||||
max_x = -16,
|
||||
min_y = 16,
|
||||
max_y = -16;
|
||||
|
||||
for (let i = 0; i < num_vertices * num_frames * 3; i += 3) {
|
||||
vertices[i] = (data[j++] - 15) * sx;
|
||||
vertices[i+1] = (data[j++] - 15) * sy;
|
||||
vertices[i+2] = (data[j++] - 15) * sz;
|
||||
|
||||
// Find min/max only for the first frame
|
||||
if (i < num_vertices * 3) {
|
||||
min_x = Math.min(min_x, vertices[i]);
|
||||
max_x = Math.max(max_x, vertices[i]);
|
||||
min_y = Math.min(min_y, vertices[i+1]);
|
||||
max_y = Math.max(max_y, vertices[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Load indices, 1x 2bit increment, 2x 7bit absolute
|
||||
for (let i = 0; i < num_indices * 3; i += 3) {
|
||||
index_increment += data[j++];
|
||||
indices[i] = index_increment;
|
||||
indices[i+1] = data[j++];
|
||||
indices[i+2] = data[j++];
|
||||
}
|
||||
|
||||
// UV coords in texture space and width/height as fraction of model size
|
||||
let uf = 1 / (max_x - min_x),
|
||||
u = -min_x * uf,
|
||||
vf = -1 / (max_y - min_y),
|
||||
v = max_y * vf;
|
||||
|
||||
// Compute normals for each frame and face and submit to render buffer.
|
||||
// Capture the current vertex offset for the first vertex of each frame.
|
||||
let frames = [];
|
||||
|
||||
for (let frame_index = 0; frame_index < num_frames; frame_index++) {
|
||||
frames.push(r_num_verts);
|
||||
|
||||
let vertex_offset = frame_index * num_vertices * 3;
|
||||
for (let i = 0; i < num_indices * 3; i += 3) {
|
||||
|
||||
let mv = [], uv = [];
|
||||
for (let face_vertex = 0, o = 0; face_vertex < 3; face_vertex++) {
|
||||
let idx = indices[i + face_vertex] * 3;
|
||||
mv[face_vertex] = vec3(
|
||||
vertices[vertex_offset + idx + 0],
|
||||
vertices[vertex_offset + idx + 1],
|
||||
vertices[vertex_offset + idx + 2]
|
||||
);
|
||||
uv[face_vertex] = {
|
||||
u: vertices[idx + 0] * uf + u,
|
||||
v: vertices[idx + 1] * vf + v
|
||||
};
|
||||
}
|
||||
|
||||
let n = vec3_face_normal(mv[2], mv[1], mv[0]);
|
||||
r_push_vert(mv[2], n, uv[2].u, uv[2].v);
|
||||
r_push_vert(mv[1], n, uv[1].u, uv[1].v);
|
||||
r_push_vert(mv[0], n, uv[0].u, uv[0].v);
|
||||
}
|
||||
}
|
||||
|
||||
return {f: frames, nv: num_indices * 3};
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
let music_data = [6014,21,88,[[[7,0,0,1,255,0,7,0,0,1,255,0,0,100,0,3636,254,2,1199,254,4,71,0,0,0,0,0,0,0],[1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1],[[126,126,0,0,126,0,0,0,0,0,0,0,0,0,0,0,126,126,0,0,126,0,0,0,0,0,0,0,0,0,0,0]]],[[6,0,0,0,255,2,6,0,18,0,255,2,0,100000,56363,100000,199,2,200,254,8,24,0,0,0,0,0,0,0],[0,0,2,2,3,4,2,2,3,5,2,2,3,4,2,2,3,5],[[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],[132,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],[133,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[125,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],[120,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]]],[[7,0,0,0,87,2,8,0,0,0,16,3,8,0,22,2193,255,3,1162,51,10,182,2,190,0,1,10,96,0],[0,0,0,0,0,0,1,1,1,1,1,1,1,1],[[149,149,0,0,149,0,149,0,149,149,0,0,149,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]],[[8,0,0,0,65,2,6,0,0,0,243,3,0,200,7505,20000,204,4,6180,81,4,198,0,0,0,0,6,131,0],[0,0,0,0,0,0,0,0,0,0,1,1,2,3,1,1,2,3],[[132,0,0,0,0,0,0,0,133,0,0,0,137,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[132,0,0,0,0,0,0,0,133,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[132,0,0,0,0,0,0,0,133,0,0,0,125,0,0,0,0,0,0,0,125,0,0,0,0,0,0,0,0,0,0,0]]]]];
|
||||
@@ -0,0 +1,354 @@
|
||||
|
||||
let
|
||||
options = {antialias: false},
|
||||
gl = (c.getContext('webgl', options) || c.getContext('experimental-webgl', options)),
|
||||
|
||||
R_MAX_VERTS = 1024 * 64, // allow 512k verts max
|
||||
R_MAX_LIGHT_V3 = 64,
|
||||
|
||||
// Vertex shader source. This translates the model position & rotation and also
|
||||
// mixes positions of two buffers for animations.
|
||||
R_SOURCE_VS =
|
||||
'precision highp float;' +
|
||||
|
||||
// Vertex positions, normals and uv coords for the fragment shader
|
||||
'varying vec3 vp,vn;' +
|
||||
'varying vec2 vt;' +
|
||||
|
||||
// Input vertex positions & normals and blend vertex positions & normals
|
||||
'attribute vec3 p,n,p2,n2;' +
|
||||
|
||||
// Input UV coords
|
||||
'attribute vec2 t;' +
|
||||
|
||||
// Camera position (x, y, z) and aspect ratio (w)
|
||||
'uniform vec4 c;' +
|
||||
|
||||
// Model position (x, y, z)
|
||||
'uniform vec3 mp;' +
|
||||
|
||||
// Model rotation (yaw, pitch)
|
||||
'uniform vec2 mr;' +
|
||||
|
||||
// Mouse rotation yaw (x), pitch (y)
|
||||
'uniform vec2 m;' +
|
||||
|
||||
// Blend factor between the two vertex positions
|
||||
'uniform float f;' +
|
||||
|
||||
// Generate a rotation Matrix around the x,y,z axis;
|
||||
// Used for model rotation and camera yaw
|
||||
'mat4 rx(float r){' +
|
||||
'return mat4(' +
|
||||
'1,0,0,0,' +
|
||||
'0,cos(r),sin(r),0,' +
|
||||
'0,-sin(r),cos(r),0,' +
|
||||
'0,0,0,1' +
|
||||
');' +
|
||||
'}' +
|
||||
|
||||
'mat4 ry(float r){' +
|
||||
'return mat4(' +
|
||||
'cos(r),0,-sin(r),0,' +
|
||||
'0,1,0,0,' +
|
||||
'sin(r),0,cos(r),0,' +
|
||||
'0,0,0,1' +
|
||||
');' +
|
||||
'}' +
|
||||
|
||||
'mat4 rz(float r){' +
|
||||
'return mat4(' +
|
||||
'cos(r),sin(r),0,0,' +
|
||||
'-sin(r),cos(r),0,0,' +
|
||||
'0,0,1,0,' +
|
||||
'0,0,0,1' +
|
||||
');' +
|
||||
'}' +
|
||||
|
||||
'void main(void){' +
|
||||
// Rotation Matrixes for model rotation
|
||||
'mat4 '+
|
||||
'mry=ry(mr.x),' +
|
||||
'mrz=rz(mr.y);' +
|
||||
|
||||
// Mix vertex positions, rotate and add the model position
|
||||
'vp=(mry*mrz*vec4(mix(p,p2,f),1.)).xyz+mp;' +
|
||||
|
||||
// Mix normals
|
||||
'vn=(mry*mrz*vec4(mix(n,n2,f),1.)).xyz;' +
|
||||
|
||||
// UV coords are handed over to the fragment shader as is
|
||||
'vt=t;' +
|
||||
|
||||
// Final vertex position is transformed by the projection matrix,
|
||||
// rotated around mouse yaw/pitch and offset by the camera position
|
||||
// We use a FOV of 90, so the matrix[0] and [5] are conveniently 1.
|
||||
// (1 / Math.tan((90/180) * Math.PI / 2) === 1)
|
||||
'gl_Position=' +
|
||||
'mat4(' +
|
||||
'1,0,0,0,' +
|
||||
'0,c.w,0,0,' +
|
||||
'0,0,1,1,' +
|
||||
'0,0,-2,0' +
|
||||
')*' + // projection
|
||||
'rx(-m.y)*ry(-m.x)*' +
|
||||
'vec4(vp-c.xyz,1.);' +
|
||||
'}',
|
||||
|
||||
// Fragment shader source. Calculates the lighting, does some cheesy gamma
|
||||
// correction and reduces the colors of the final output.
|
||||
R_SOURCE_FS =
|
||||
'precision highp float;' +
|
||||
|
||||
// Vertex positions, normals and uv coords
|
||||
'varying vec3 vp,vn;' +
|
||||
'varying vec2 vt;' +
|
||||
|
||||
'uniform sampler2D s;' +
|
||||
|
||||
// Lights [(x,y,z), [r,g,b], ...]
|
||||
'uniform vec3 l['+R_MAX_LIGHT_V3+'];' +
|
||||
|
||||
'void main(void){' +
|
||||
'gl_FragColor=texture2D(s,vt);' +
|
||||
|
||||
// Debug: no textures
|
||||
// 'gl_FragColor=vec4(1.0,1.0,1.0,1.0);' +
|
||||
|
||||
// Calculate all lights
|
||||
'vec3 vl;' +
|
||||
'for(int i=0;i<'+R_MAX_LIGHT_V3+';i+=2) {' +
|
||||
'vl+=' +
|
||||
// Angle to normal
|
||||
'max('+
|
||||
'dot('+
|
||||
'vn, normalize(l[i]-vp)' +
|
||||
')' +
|
||||
',0.)*' +
|
||||
'(1./pow(length(l[i]-vp),2.))' + // Inverse distance squared
|
||||
'*l[i+1];' + // Light color/intensity
|
||||
'}' +
|
||||
|
||||
// Debug: full bright lights
|
||||
// 'vl = vec3(2,2,2);' +
|
||||
|
||||
'gl_FragColor.rgb=floor('+
|
||||
'gl_FragColor.rgb*pow(vl,vec3(0.75))'+ // Light, Gamma
|
||||
'*16.0+0.5'+
|
||||
')/16.0;' + // Reduce final output color for some extra dirty looks
|
||||
'}',
|
||||
|
||||
// 8 properties per vert [x,y,z, u,v, nx,ny,nz]
|
||||
r_buffer = new Float32Array(R_MAX_VERTS*8),
|
||||
r_num_verts = 0,
|
||||
|
||||
// 2 vec3 per light [(x,y,z), [r,g,b], ...]
|
||||
r_light_buffer = new Float32Array(R_MAX_LIGHT_V3*3),
|
||||
r_num_lights = 0,
|
||||
|
||||
// Uniform locations
|
||||
r_u_camera,
|
||||
r_u_lights,
|
||||
r_u_mouse,
|
||||
r_u_pos,
|
||||
r_u_rotation,
|
||||
r_u_frame_mix,
|
||||
|
||||
// Vertex attribute location for mixing
|
||||
r_va_p2, r_va_n2,
|
||||
|
||||
// Texture handles
|
||||
r_textures = [],
|
||||
|
||||
// Camera position
|
||||
r_camera = vec3(0, 0,-50),
|
||||
r_camera_pitch = 0.2,
|
||||
r_camera_yaw = 0,
|
||||
|
||||
// We collect all draw calls in an array and draw them all at once at the end
|
||||
// the frame. This way the lights buffer will be completely filled and we
|
||||
// only need to set it once for all geometry
|
||||
r_draw_calls = [],
|
||||
|
||||
r_init = () => {
|
||||
// Create shorthand WebGL function names
|
||||
// let webglShortFunctionNames = {};
|
||||
for (let name in gl) {
|
||||
if (gl[name].length != undefined) {
|
||||
gl[name.match(/(^..|[A-Z]|\d.|v$)/g).join('')] = gl[name];
|
||||
// webglShortFunctionNames[name] = 'gl.' +name.match(/(^..|[A-Z]|\d.|v$)/g).join('');
|
||||
}
|
||||
}
|
||||
// console.log(JSON.stringify(webglShortFunctionNames, null, '\t'));
|
||||
|
||||
let shader_program = gl.createProgram();
|
||||
gl.attachShader(shader_program, r_compile_shader(gl.VERTEX_SHADER, R_SOURCE_VS));
|
||||
gl.attachShader(shader_program, r_compile_shader(gl.FRAGMENT_SHADER, R_SOURCE_FS));
|
||||
gl.linkProgram(shader_program);
|
||||
gl.useProgram(shader_program);
|
||||
|
||||
r_u_camera = gl.getUniformLocation(shader_program, 'c');
|
||||
r_u_lights = gl.getUniformLocation(shader_program, 'l');
|
||||
r_u_mouse = gl.getUniformLocation(shader_program, 'm');
|
||||
r_u_pos = gl.getUniformLocation(shader_program, 'mp');
|
||||
r_u_rotation = gl.getUniformLocation(shader_program, 'mr');
|
||||
r_u_frame_mix = gl.getUniformLocation(shader_program, 'f');
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
|
||||
|
||||
r_vertex_attrib(shader_program, 'p', 3, 8, 0); // position
|
||||
r_vertex_attrib(shader_program, 't', 2, 8, 3); // texture coord
|
||||
r_vertex_attrib(shader_program, 'n', 3, 8, 5); // normals
|
||||
|
||||
r_va_p2 = r_vertex_attrib(shader_program, 'p2', 3, 8, 0); // mix position
|
||||
r_va_n2 = r_vertex_attrib(shader_program, 'n2', 3, 8, 5); // mix normals
|
||||
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.enable(gl.BLEND);
|
||||
gl.enable(gl.CULL_FACE);
|
||||
gl.viewport(0,0,c.width,c.height);
|
||||
},
|
||||
|
||||
r_compile_shader = (shader_type, shader_source) => {
|
||||
let shader = gl.createShader(shader_type);
|
||||
gl.shaderSource(shader, shader_source);
|
||||
gl.compileShader(shader);
|
||||
// console.log(gl.getShaderInfoLog(shader));
|
||||
return shader;
|
||||
},
|
||||
|
||||
r_vertex_attrib = (shader_program, attrib_name, count, vertex_size, offset) => {
|
||||
let location = gl.getAttribLocation(shader_program, attrib_name);
|
||||
gl.enableVertexAttribArray(location);
|
||||
gl.vertexAttribPointer(location, count, gl.FLOAT, false, vertex_size * 4, offset * 4);
|
||||
return location;
|
||||
},
|
||||
|
||||
r_create_texture = (c) => {
|
||||
let t = {t:gl.createTexture(), c};
|
||||
gl.bindTexture(gl.TEXTURE_2D, t.t);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, c);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
|
||||
gl.generateMipmap(gl.TEXTURE_2D);
|
||||
r_textures.push(t);
|
||||
},
|
||||
|
||||
r_prepare_frame = (r,g,b) => {
|
||||
gl.clearColor(r,g,b,1);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);
|
||||
|
||||
r_num_lights = 0;
|
||||
r_light_buffer.fill(0);
|
||||
},
|
||||
|
||||
r_end_frame = () => {
|
||||
gl.uniform4f(r_u_camera, r_camera.x, r_camera.y, r_camera.z, 16/9);
|
||||
gl.uniform2f(r_u_mouse, r_camera_yaw, r_camera_pitch);
|
||||
gl.uniform3fv(r_u_lights, r_light_buffer);
|
||||
|
||||
let vo = 0,
|
||||
last_texture = -1;
|
||||
for (let c of r_draw_calls) {
|
||||
|
||||
// c = [x, y, z, yaw, pitch, texture, offset1, offset2, mix, length]
|
||||
|
||||
// Bind new texture only if it changed from the previous one. The map
|
||||
// is sorted by texture indices, so this helps.
|
||||
if (last_texture != c[5]) {
|
||||
last_texture = c[5];
|
||||
gl.bindTexture(gl.TEXTURE_2D, r_textures[last_texture].t);
|
||||
}
|
||||
|
||||
gl.uniform3f(r_u_pos, c[0], c[1], c[2]);
|
||||
gl.uniform2f(r_u_rotation, c[3], c[4]);
|
||||
gl.uniform1f(r_u_frame_mix, c[8]);
|
||||
|
||||
// If we have two different frames, calculate the offset from the
|
||||
// drawArrays call to the mix frame.
|
||||
// Setting the vertexAttribPointer is quite expensive, so we only
|
||||
// do this if we have to; i.e. for animated models.
|
||||
if (vo != (c[7]-c[6])) {
|
||||
vo = (c[7]-c[6]);
|
||||
gl.vertexAttribPointer(r_va_p2, 3, gl.FLOAT, false, 8 * 4, vo*8*4);
|
||||
gl.vertexAttribPointer(r_va_n2, 3, gl.FLOAT, false, 8 * 4, (vo*8+5)*4);
|
||||
}
|
||||
gl.drawArrays(gl.TRIANGLES, c[6], c[9]);
|
||||
}
|
||||
|
||||
// Reset draw calls
|
||||
r_draw_calls = [];
|
||||
},
|
||||
|
||||
r_draw = (pos, yaw, pitch, texture, f1, f2, mix, num_verts) => {
|
||||
r_draw_calls.push([
|
||||
pos.x, pos.y, pos.z, yaw, pitch,
|
||||
texture, f1, f2, mix, num_verts
|
||||
]);
|
||||
},
|
||||
|
||||
r_submit_buffer = () => {
|
||||
gl.bufferData(gl.ARRAY_BUFFER, r_buffer.subarray(0, r_num_verts*8), gl.STATIC_DRAW);
|
||||
},
|
||||
|
||||
r_push_vert = (pos, normal, u, v) => {
|
||||
r_buffer.set([pos.x, pos.y, pos.z, u, v, normal.x, normal.y, normal.z], r_num_verts * 8);
|
||||
r_num_verts++;
|
||||
},
|
||||
|
||||
r_push_quad = (v0, v1, v2, v3, u, v) => {
|
||||
let n = vec3_face_normal(v0, v1, v2);
|
||||
r_push_vert(v0, n, u, 0);
|
||||
r_push_vert(v1, n, 0, 0);
|
||||
r_push_vert(v2, n, u, v);
|
||||
r_push_vert(v3, n, 0, v);
|
||||
r_push_vert(v2, n, u, v);
|
||||
r_push_vert(v1, n, 0, 0);
|
||||
},
|
||||
|
||||
r_push_block = (x, y, z, sx, sy, sz, texture) => {
|
||||
let canvas = r_textures[texture].c,
|
||||
index = r_num_verts,
|
||||
tx = sx/canvas.width,
|
||||
ty = sy/canvas.height,
|
||||
tz = sz/canvas.width,
|
||||
|
||||
// top
|
||||
v0 = vec3(x, y + sy, z),
|
||||
v1 = vec3(x + sx, y + sy, z),
|
||||
v2 = vec3(x, y + sy, z + sz),
|
||||
v3 = vec3(x + sx, y + sy, z + sz),
|
||||
|
||||
// bottom
|
||||
v4 = vec3(x, y, z + sz),
|
||||
v5 = vec3(x + sx, y, z + sz),
|
||||
v6 = vec3(x, y, z),
|
||||
v7 = vec3(x + sx, y, z);
|
||||
|
||||
r_push_quad(v0, v1, v2, v3, tx, tz); // top
|
||||
r_push_quad(v4, v5, v6, v7, tx, tz); // bottom
|
||||
r_push_quad(v2, v3, v4, v5, tx, ty); // front
|
||||
r_push_quad(v1, v0, v7, v6, tx, ty); // back
|
||||
r_push_quad(v3, v1, v5, v7, tz, ty); // right
|
||||
r_push_quad(v0, v2, v6, v4, tz, ty); // left
|
||||
return index;
|
||||
},
|
||||
|
||||
r_push_light = (pos, intensity, r, g, b) => {
|
||||
// Calculate the distance to the light, fade it out between 768--1024
|
||||
let fade = clamp(
|
||||
scale(
|
||||
vec3_dist(pos, r_camera),
|
||||
768, 1024, 1, 0
|
||||
),
|
||||
0, 1
|
||||
) * intensity * 10;
|
||||
|
||||
if (fade && r_num_lights < R_MAX_LIGHT_V3/2) {
|
||||
r_light_buffer.set([pos.x, pos.y, pos.z, r*fade, g*fade, b*fade], r_num_lights*6);
|
||||
r_num_lights++;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
let texture_data = [[64,64,0,2,3,1.4,2,17176,1.3],[64,64,38751,1,18,4,2,2,27,9,65530,0,7,1,-1,9,13,5,52,8,8,65528,39039,4,0,0,0,64,512,15,4,0,0,0,64,64,14],[64,64,38751,1,18,4,2,2,27,9,65530,0,7,1,-1,0,13,64,52,64,8,65531,39039,4,0,0,0,64,512,15,4,0,0,0,64,64,14],[64,64,13119,4,1,0,0,64,64,15,0,24,11,17,50,65523,2,8],[32,32,21839,1,0,2,10,2,11,4,65528,10,25931,4,0,0,0,32,32,14],[32,32,17487,0,1,1,30,30,65528,11,21580,4,0,0,0,32,32,15],[32,32,30015,4,5,0,0,32,32,15,1,5,4,2,2,22,6,65522,0,8],[32,32,8751,1,1,1,8,4,11,5,65524,15,17487,4,0,0,0,64,64,15],[32,32,13119,4,4,0,0,32,32,15,1,10,3,11,6,25,10,64536,64568,65519],[32,32,8751,1,1,1,3,3,4,4,65524,14,21565,1,1,-1,15,1,16,16,65522,7,0,1,-1,0,1,15,16,6,65521,0,4,4,0,0,0,32,32,15],[32,32,8719,2,63506,1,4,0,0,0,32,32,12],[32,32,21295,4,10,0,-4,32,298,10,2,4372,1],[32,32,8463,1,-1,1,35,1,35,4,65522,10,34399,0,-1,6,34,6,65526,2,34399,2,29479,1,4,6,0,0,32,32,5],[32,32,5535,4,0,0,0,128,64,14],[32,32,8463,1,0,0,3,3,4,4,0,10,65521,0,4,4,23,23,10,64885,21551,3,4,16,13,0,11,"::][::",4,0,4,4,26,26,15],[32,32,8751,1,1,1,8,3,11,5,65524,15,17487,0,9,6,14,13,15,65525,4383,4,0,0,0,64,64,12,3,10,11,20267,0,8,"---"],[32,32,17487,4,5,0,0,32,32,15,1,4,4,3,3,22,22,65523,7,30587],[64,64,38767,2,36875,2.5,1,4,10,15,8,39,59,15,15,8463,1,3,30,14,5,15,6,12813,4367,38671,0,20,1,22,6,13119,10,38671,4,0,0,0,64,64,11],[32,32,40975,2,63308,1.5,2,63751,7.3],[64,64,13119,4,17,0,0,64,64,15,0,0,29,64,64,0,0,89,4,4,21,-6,22,24,15],[32,32,13119,4,9,0,0,32,32,15,4,8,6,-22,21,32,15,4,18,0,0,32,32,4],[64,64,13119,0,0,0,64,64,0,0,64271,3,-1,50,33795,0,32,"XXX",4,7,0,0,64,64,6],[64,64,34063,4,7,0,0,64,64,12,2,12554,1],[32,32,65535,4,12,0,0,32,32,9,3,6,30,61455,0,25,"+"],[32,32,5903,4,12,0,0,32,32,9,3,5,14,65529,0,12,"NIИ"],[32,32,64271,0,12,1,7,30,65528,8,63247,4,7,0,0,32,32,8],[32,32,13119,1,1,1,14,14,16,32,56328,15,26399,1,-7,17,14,14,16,32,56328,8,26159,2,29706,1,4,0,0,0,32,320,14],[32,32,33567,1,1,1,6,30,16,31,65526,15,33823,1,9,-14,6,30,16,32,65526,15,29743,2,55625,1.5,4,0,0,0,32,320,15],[32,32,12559,1,1,1,14,14,16,16,65525,7,21295,0,1,1,14,14,65525,0,34399,0,17,17,14,14,65524,0,34399,2,8,1.5],[32,32,9503,4,11,0,0,32,32,12,1,1,1,6,7,6,8,65521,0,4],[32,32,15,4,18,0,16,32,32,15,4,27,0,-16,32,32,10]];
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
TTT Tiny Texture Tumbler
|
||||
Dominic Szablewski - https://phoboslab.org
|
||||
|
||||
-- LICENSE: The MIT License(MIT)
|
||||
Copyright(c) 2019 Dominic Szablewski
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files(the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions :
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// Compress with:
|
||||
// uglifyjs ttt.js --compress --screw-ie8 --mangle toplevel -o ttt.min.js
|
||||
let
|
||||
ttt=(td, only_this_index = -1,stack_depth = 0) => {
|
||||
return td.filter((d,i) => only_this_index < 0 || i == only_this_index).map(d => {
|
||||
let i = 0,
|
||||
e = document.createElement('canvas'),
|
||||
c = e.getContext('2d'),
|
||||
rgba_from_2byte = (c) =>
|
||||
'rgba(' + [
|
||||
((c>>12)&15) * 17,
|
||||
((c>>8)&15) * 17,
|
||||
((c>>4)&15) * 17,
|
||||
(c&15)/15
|
||||
].join() + ')',
|
||||
fill_rect = (x, y, w, h, ...colors) =>
|
||||
colors.map((color, j) => {
|
||||
c.fillStyle = rgba_from_2byte(color);
|
||||
c.fillRect(x+[-1,1,0][j], y+[-1,1,0][j], w, h);
|
||||
})
|
||||
;
|
||||
// Set up canvas width and height
|
||||
e.width = d[i++];
|
||||
e.height = d[i++];
|
||||
|
||||
// Fill with background color
|
||||
fill_rect(0, 0, e.width, e.height, 0,0, d[i++]);
|
||||
|
||||
// Perform all the steps for this texture
|
||||
while (i < d.length) {
|
||||
let f = [
|
||||
// 0 - rectangle: x, y, width, height, top, bottom, fill
|
||||
(x, y, width, height, top, bottom, fill) => {
|
||||
fill_rect(x, y, width, height, top, bottom, fill)
|
||||
},
|
||||
|
||||
// 1 - rectangle_multiple: start_x, start_y, width, height,
|
||||
// inc_x, inc_y, top, bottom, fill
|
||||
(sx, sy, w, h, inc_x, inc_y, top, bottom, fill) => {
|
||||
for (let x = sx; x < e.width; x += inc_x) {
|
||||
for (let y = sy; y < e.height; y += inc_y) {
|
||||
fill_rect(x, y, w, h, top, bottom, fill);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 2 - random noise: color, size
|
||||
(color, size) => {
|
||||
for (let x = 0; x < e.width; x += size) {
|
||||
for (let y = 0; y < e.height; y += size) {
|
||||
// Take the color value (first 3 nibbles) and
|
||||
// randomize the alpha value (last nibble)
|
||||
// between 0 and the input alpha.
|
||||
fill_rect(
|
||||
x, y, size, size, 0, 0,
|
||||
(color&0xfff0) + Math.random()*(color&15)
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 3 - text: x, y, color, font,size, text
|
||||
(x, y, color, font, size, text) => {
|
||||
c.fillStyle = rgba_from_2byte(color);
|
||||
c.font = size + 'px ' + ['sans-',''][font]+'serif';
|
||||
c.fillText(text, x, y);
|
||||
},
|
||||
|
||||
// 4 - draw a previous texture
|
||||
// We limit the stack depth here to not end up in an infinite
|
||||
// loop by accident
|
||||
(texture_index, x, y, w, h, alpha) => {
|
||||
c.globalAlpha = alpha/15;
|
||||
(
|
||||
texture_index < td.length && stack_depth < 16 &&
|
||||
c.drawImage(
|
||||
ttt(td, texture_index, stack_depth+1)[0],
|
||||
x, y, w, h
|
||||
)
|
||||
);
|
||||
c.globalAlpha = 1;
|
||||
}
|
||||
][d[i++]];
|
||||
f(...d.slice(i, i+=f.length));
|
||||
}
|
||||
return e;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
|
||||
class weapon_t {
|
||||
constructor() {
|
||||
this._needs_ammo = 1;
|
||||
this._projectile_offset = vec3(0,0,8);
|
||||
this._init();
|
||||
}
|
||||
|
||||
_shoot(pos, yaw, pitch) {
|
||||
if (this._needs_ammo) {
|
||||
this._ammo--;
|
||||
}
|
||||
audio_play(this._sound);
|
||||
this._spawn_projectile(pos, yaw, pitch);
|
||||
}
|
||||
|
||||
_spawn_projectile(pos, yaw, pitch) {
|
||||
let projectile = game_spawn(this._projectile_type, vec3_add(
|
||||
pos,
|
||||
vec3_add(
|
||||
vec3(0, 12, 0),
|
||||
vec3_rotate_yaw_pitch(
|
||||
this._projectile_offset,
|
||||
yaw, pitch
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
// Set the projectile velocity, yaw and pitch
|
||||
projectile.v = vec3_rotate_yaw_pitch(
|
||||
vec3(0, 0, this._projectile_speed),
|
||||
yaw, pitch
|
||||
);
|
||||
projectile._yaw = yaw -Math.PI/2;
|
||||
projectile._pitch = -pitch;
|
||||
projectile._check_against = ENTITY_GROUP_ENEMY;
|
||||
|
||||
// Alternate left/right fire for next projectile (nailgun)
|
||||
this._projectile_offset.x *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
class weapon_shotgun_t extends weapon_t {
|
||||
_init() {
|
||||
this._texture = 7;
|
||||
this._model = model_shotgun;
|
||||
this._sound = sfx_shotgun_shoot;
|
||||
this._needs_ammo = 0;
|
||||
this._reload = 0.9;
|
||||
this._projectile_type = entity_projectile_shell_t;
|
||||
this._projectile_speed = 10000;
|
||||
}
|
||||
|
||||
_spawn_projectile(pos, yaw, pitch) {
|
||||
setTimeout(()=>audio_play(sfx_shotgun_reload), 200);
|
||||
setTimeout(()=>audio_play(sfx_shotgun_reload), 350);
|
||||
for (let i = 0; i < 8; i++) {
|
||||
super._spawn_projectile(pos, yaw+Math.random()*0.08-0.04, pitch+Math.random()*0.08-0.04);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class weapon_nailgun_t extends weapon_t {
|
||||
_init() {
|
||||
this._texture = 4;
|
||||
this._model = model_nailgun;
|
||||
this._sound = sfx_nailgun_shoot;
|
||||
this._ammo = 100;
|
||||
this._reload = 0.09;
|
||||
this._projectile_type = entity_projectile_nail_t;
|
||||
this._projectile_speed = 1300;
|
||||
this._projectile_offset = vec3(6,0,8);
|
||||
}
|
||||
}
|
||||
|
||||
class weapon_grenadelauncher_t extends weapon_t {
|
||||
_init() {
|
||||
this._texture = 21;
|
||||
this._model = model_grenadelauncher;
|
||||
this._sound = sfx_grenade_shoot;
|
||||
this._ammo = 10;
|
||||
this._reload = 0.650;
|
||||
this._projectile_type = entity_projectile_grenade_t;
|
||||
this._projectile_speed = 900;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
};
|
||||
gs();
|
||||
@@ -0,0 +1,9 @@
|
||||
// Holy hell, wtf, bbq! If we don't wrap the whole game in a global function,
|
||||
// installed on the window scope, everything will be garbage collected in chrome
|
||||
// in the roadrolled version, even though the requestAnimationFrame should hold
|
||||
// on to the closure.
|
||||
|
||||
// I assumme it's a weird interaction between eval() (used by roadroller) and
|
||||
// async functions. In any case, it seems to be a bug in v8.
|
||||
|
||||
gs = () => {
|
||||