mirror of
https://github.com/bearstonem/openmohaa-vr.git
synced 2026-10-18 01:00:20 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96bf729c54 | ||
|
|
edcf521506 | ||
|
|
9e7991f4b1 | ||
|
|
86e7a24b38 | ||
|
|
ff587a8444 | ||
|
|
c3e98ed681 | ||
|
|
cc2d698fe2 | ||
|
|
420161095f | ||
|
|
58b0d335e7 | ||
|
|
ce336e8962 | ||
|
|
5b72eb189a | ||
|
|
7600d3ca02 | ||
|
|
8c3be9d549 | ||
|
|
2ddb534321 | ||
|
|
21a1f61b04 | ||
|
|
7219848655 | ||
|
|
4695449fc7 | ||
|
|
af3dd2602b | ||
|
|
5bba5abece | ||
|
|
bdcb6c42b6 | ||
|
|
0fe01d23d6 | ||
|
|
fc675e4064 | ||
|
|
a29af7c3f6 | ||
|
|
732872f433 | ||
|
|
04b5fdb934 | ||
|
|
e23ce01d19 | ||
|
|
648dc395e7 | ||
|
|
ab2a26a14e | ||
|
|
238e94b4d5 | ||
|
|
0c18e0e26c | ||
|
|
7085d60d02 | ||
|
|
3933e63044 | ||
|
|
342552c349 | ||
|
|
9addff08ce | ||
|
|
2ff1071115 | ||
|
|
49f4ac66ab | ||
|
|
7761cbd74c | ||
|
|
103debcf6b | ||
|
|
526ab8071c | ||
|
|
ac45f20fa6 | ||
|
|
a45b36f2f3 | ||
|
|
bea35d28fc | ||
|
|
bb71f84985 | ||
|
|
2f62e61dc8 | ||
|
|
dceceb976d | ||
|
|
59bf9fbd54 | ||
|
|
a1cd6f2746 | ||
|
|
76178064a0 | ||
|
|
31ac3f7096 | ||
|
|
545dc19811 | ||
|
|
5f598cf1f9 | ||
|
|
4e66f2482f | ||
|
|
f873fd447f | ||
|
|
a4123f65b3 | ||
|
|
93e56d968e | ||
|
|
b4e22d3040 | ||
|
|
351f601986 | ||
|
|
41fdd28d8b | ||
|
|
d7c6cc0157 | ||
|
|
f1b83f1dab | ||
|
|
bb401d8d3c | ||
|
|
8bb9cd46f8 | ||
|
|
c27695247e | ||
|
|
7b9835a118 | ||
|
|
2dc75b7527 | ||
|
|
6c577a7251 | ||
|
|
5031402c2c | ||
|
|
a4bd37af8c | ||
|
|
4dc60b9aa4 | ||
|
|
ce89399824 | ||
|
|
b92d2972f6 | ||
|
|
f53680983b | ||
|
|
d6fd337a07 | ||
|
|
95230a8d0a | ||
|
|
04524e9de9 | ||
|
|
df4f6f9515 | ||
|
|
e9c7a1f959 | ||
|
|
c4502469f4 | ||
|
|
c2cb15a1d1 | ||
|
|
4d108a272f | ||
|
|
f523c32044 | ||
|
|
5ac5632e59 | ||
|
|
80f3296854 | ||
|
|
1b1433dd1b | ||
|
|
7647bbaf36 | ||
|
|
f00fd281b3 | ||
|
|
b5ea1ddb53 | ||
|
|
b16ce90be3 | ||
|
|
4c0f7a34de | ||
|
|
2e11cd4ea2 | ||
|
|
c2ad608508 | ||
|
|
5ec8c901e2 | ||
|
|
e6bbbdb79e | ||
|
|
f5fa8d15d1 | ||
|
|
7aee02ba8d | ||
|
|
cf51e14cf5 | ||
|
|
7fb383c810 | ||
|
|
34f66963e3 | ||
|
|
6059063b67 | ||
|
|
8bf57017ac | ||
|
|
9f1d35a11b | ||
|
|
aa51987077 | ||
|
|
64055d2580 | ||
|
|
45e82c590e | ||
|
|
0c92890ef2 | ||
|
|
03e8a64283 | ||
|
|
4e14535f08 | ||
|
|
356e7c51fc | ||
|
|
52a146d664 | ||
|
|
76f107230c | ||
|
|
4a49b15649 | ||
|
|
6c448694b6 | ||
|
|
34a1cee89b | ||
|
|
29239dadfa | ||
|
|
e5a4574f92 | ||
|
|
2d70547f9d | ||
|
|
f6279e8c17 | ||
|
|
18ade839c6 | ||
|
|
b72eb8c6cc | ||
|
|
e0446db81d | ||
|
|
a8bb9aaa77 | ||
|
|
6595c3c673 | ||
|
|
4ecf3195a5 | ||
|
|
02f0e309e3 | ||
|
|
0fdfcf48f9 | ||
|
|
e9b5c7efd5 | ||
|
|
2a32b75815 | ||
|
|
d966afe4ef | ||
|
|
92e2d42e19 | ||
|
|
58e5e3fd63 | ||
|
|
b61c7b3988 | ||
|
|
ee030f27e2 | ||
|
|
02df95fc21 | ||
|
|
03100b47c1 | ||
|
|
67444b0f15 | ||
|
|
f6ae9a2b43 | ||
|
|
98cd85bc9a | ||
|
|
83a83b08f6 | ||
|
|
448e9010dc | ||
|
|
ce69ed75f7 | ||
|
|
6ac70d6b7c | ||
|
|
4f588d939d | ||
|
|
f6ebdd1998 | ||
|
|
7438dd709c | ||
|
|
1207b46937 | ||
|
|
497f853171 | ||
|
|
4984f8b925 | ||
|
|
a1d581df39 | ||
|
|
6db89a5440 | ||
|
|
4671aa9893 | ||
|
|
4d66b35ba1 | ||
|
|
4b6bb674c5 | ||
|
|
c9a4fc65a2 | ||
|
|
d84b22aa5c | ||
|
|
1f484e3e15 | ||
|
|
8beec0a84d | ||
|
|
f66475d957 | ||
|
|
5bef94f671 | ||
|
|
08ba82bcb6 | ||
|
|
2c5225bce2 | ||
|
|
1e18b027a0 | ||
|
|
44b69efde5 | ||
|
|
78f810e943 | ||
|
|
8e14620067 | ||
|
|
e3b5279f2e | ||
|
|
c7bc06746c | ||
|
|
d074eea927 | ||
|
|
cb0aab4aa2 | ||
|
|
7268d9a733 | ||
|
|
4a2278ffc7 | ||
|
|
e0c2329e44 | ||
|
|
64934be8bc | ||
|
|
d232388e2d | ||
|
|
63c5057a45 | ||
|
|
407a30408d | ||
|
|
0dc31e22b4 | ||
|
|
da89c99586 | ||
|
|
55b91adb45 | ||
|
|
699f8b1b01 | ||
|
|
0b14732f9e | ||
|
|
2bbba486a4 | ||
|
|
7eeec056c8 | ||
|
|
a7a224054a | ||
|
|
fad9529c61 | ||
|
|
c1ae133cf1 | ||
|
|
cf14b84876 | ||
|
|
3f2d62db4a | ||
|
|
717a56c116 | ||
|
|
21958db630 | ||
|
|
bba11beb39 | ||
|
|
0e33f8258a | ||
|
|
8ff70d1ceb | ||
|
|
fe0e345a8d | ||
|
|
6e3b83bd3a | ||
|
|
08dfaa8e1e | ||
|
|
a4e0e7b697 | ||
|
|
7064abc862 | ||
|
|
4b449772b3 | ||
|
|
2db3eb868a | ||
|
|
32028ccf1d | ||
|
|
5200e886d7 | ||
|
|
73cf84506b | ||
|
|
bad116e615 | ||
|
|
6dfc8b8f32 | ||
|
|
2ccd63e31a | ||
|
|
7b0132f2fb | ||
|
|
d1d87edaa1 | ||
|
|
c36757be06 | ||
|
|
6807471464 | ||
|
|
9787c5c235 | ||
|
|
707de8d342 | ||
|
|
57d24335cc | ||
|
|
27ce5af057 | ||
|
|
5a474b84c8 | ||
|
|
4dcd1111fb | ||
|
|
f47474bd27 | ||
|
|
fb254bf4f4 | ||
|
|
4ef4c86808 | ||
|
|
93d6d00b4a | ||
|
|
77b5648094 | ||
|
|
28b434e56d | ||
|
|
b6ab949337 | ||
|
|
d113d292eb | ||
|
|
8a855f37a2 | ||
|
|
38e46221bd | ||
|
|
2c816c0846 | ||
|
|
9abc35bc18 | ||
|
|
5b141089c3 | ||
|
|
7fb4de0c6c | ||
|
|
52cb234142 | ||
|
|
c88a3f5a24 | ||
|
|
f93ea7ab8d | ||
|
|
83a6f2a03f | ||
|
|
f4ed87b30a | ||
|
|
a14db185bd | ||
|
|
dc96125c61 | ||
|
|
2af3dee1d8 | ||
|
|
0e1b92a5eb | ||
|
|
4b04bfaea2 | ||
|
|
1e843cfb78 | ||
|
|
71548aff04 | ||
|
|
3f412058f7 | ||
|
|
a7c0a086c4 | ||
|
|
2af56d8a2e | ||
|
|
e7768ce390 | ||
|
|
2b6bd8c8d2 | ||
|
|
8ec2359d26 | ||
|
|
26a7e3c25a | ||
|
|
e605159f7f | ||
|
|
6198c4ceee | ||
|
|
f020b2e8ed | ||
|
|
21916a5ab7 | ||
|
|
7228a07e50 | ||
|
|
04388fe6d2 | ||
|
|
e9e43e3525 | ||
|
|
54c5f49918 | ||
|
|
8b73d676cb | ||
|
|
e99f9599f3 | ||
|
|
ecf59afd51 | ||
|
|
d0b9890213 | ||
|
|
0f4e22947b | ||
|
|
454b5c6988 | ||
|
|
cb7144bf82 | ||
|
|
3c16267738 | ||
|
|
c62185ef04 | ||
|
|
3865e1a784 | ||
|
|
849e213d95 | ||
|
|
1c9055b705 | ||
|
|
d447ec1c14 | ||
|
|
195ed5872a | ||
|
|
f985785629 | ||
|
|
e31b284243 | ||
|
|
6a3f7d89bb | ||
|
|
537c381644 | ||
|
|
776d3fa897 | ||
|
|
b4ad70dc20 | ||
|
|
95c0f4fe2d | ||
|
|
08cf0462dc | ||
|
|
102e395133 | ||
|
|
6c552b0cb3 | ||
|
|
929cb3eb79 | ||
|
|
e1f391fa4b | ||
|
|
eddd56f770 | ||
|
|
0fad7c1ad6 | ||
|
|
797ae47b46 | ||
|
|
5b89e25e9b | ||
|
|
048c555973 | ||
|
|
4824f8a3b3 | ||
|
|
082465ac98 | ||
|
|
15a00c0792 | ||
|
|
a01cf19c47 | ||
|
|
86cfa42f2c | ||
|
|
8a821b51bd | ||
|
|
79baec1625 | ||
|
|
f43930db63 | ||
|
|
c93faed19a | ||
|
|
0d7b822216 | ||
|
|
e268c47e16 | ||
|
|
521af45611 | ||
|
|
b96afa380c | ||
|
|
10d73cd784 | ||
|
|
50a2578a49 | ||
|
|
c7f877c8b4 | ||
|
|
8451cff91e | ||
|
|
e2910930da | ||
|
|
410fa7ac15 | ||
|
|
8908890d72 | ||
|
|
53c1c94dac | ||
|
|
5a87b21efc | ||
|
|
26944dcf4a | ||
|
|
f68b402d24 | ||
|
|
72f090b289 | ||
|
|
7030c23994 | ||
|
|
4ce1bb71e4 | ||
|
|
f30b1cb409 | ||
|
|
6c3a4e7a18 | ||
|
|
50fe18d41f | ||
|
|
9f879d978d | ||
|
|
d805881721 | ||
|
|
2f2a4d0ad6 | ||
|
|
b5bcd68038 | ||
|
|
1a44bd8fec | ||
|
|
f2714340e7 | ||
|
|
16a007e214 | ||
|
|
c463974c15 | ||
|
|
422d16e8eb | ||
|
|
288b208921 | ||
|
|
830ed4957b | ||
|
|
7cea7392a4 | ||
|
|
77ebd44d19 | ||
|
|
3f84bdf285 | ||
|
|
8d4d9fec39 | ||
|
|
18981a9f29 | ||
|
|
68edccef05 | ||
|
|
ecd2c0a742 | ||
|
|
7975ae0353 | ||
|
|
9fadfb3577 | ||
|
|
88a9d4a076 | ||
|
|
2e06403b17 | ||
|
|
a7db332547 | ||
|
|
845c725b9a | ||
|
|
99f886f350 | ||
|
|
59fad24126 | ||
|
|
0a94d50c4f | ||
|
|
ec5cba6188 | ||
|
|
03d72d4240 | ||
|
|
3e6afaf509 | ||
|
|
0885ee5227 | ||
|
|
b327ff5159 | ||
|
|
6fd62d4ad9 | ||
|
|
d10034b9ce | ||
|
|
1c21143f07 | ||
|
|
b6dfd7db06 | ||
|
|
a5c596f928 | ||
|
|
d2d658c42f | ||
|
|
4925c20b71 | ||
|
|
6f352b10c2 | ||
|
|
ee5f9281ea | ||
|
|
8bc6499944 | ||
|
|
237d2962d0 | ||
|
|
c649d27f75 | ||
|
|
20237c0aa3 | ||
|
|
61eacd739b | ||
|
|
d459191f01 | ||
|
|
e28ea74549 | ||
|
|
026c1264fe | ||
|
|
5b85ab4dc6 | ||
|
|
c2a266c845 | ||
|
|
031b575955 | ||
|
|
278e84580e | ||
|
|
d697a93a73 | ||
|
|
be89c1fa1f | ||
|
|
c6b832294c | ||
|
|
791881338b | ||
|
|
e2fb54781e | ||
|
|
98236d5662 | ||
|
|
d8cfe96b0f | ||
|
|
f84b61a94d | ||
|
|
ead4cfc94e | ||
|
|
f0a2a28650 | ||
|
|
c3fcb5f8c5 | ||
|
|
f1b745ea9c | ||
|
|
f505142244 | ||
|
|
1b0bc7c104 | ||
|
|
6fbf496a02 | ||
|
|
79f5d11415 | ||
|
|
f8395b6264 | ||
|
|
031952374a | ||
|
|
221de56d95 | ||
|
|
a469c448de | ||
|
|
110e60e3dd | ||
|
|
59cd7d5116 | ||
|
|
bb59e3c3f2 | ||
|
|
ac7ec18a37 | ||
|
|
ca34d8de85 | ||
|
|
8ab663d5d8 | ||
|
|
670de51637 | ||
|
|
5eba2f5662 | ||
|
|
863a730271 | ||
|
|
0fc3ecf67e | ||
|
|
864986ae9a | ||
|
|
0e597e8bf7 | ||
|
|
860b660f61 | ||
|
|
0058f255e6 | ||
|
|
fc1392dfd6 | ||
|
|
6e53b67310 | ||
|
|
a6aea380fe | ||
|
|
0a46fa69b9 | ||
|
|
c2c4cd07e0 | ||
|
|
bfb6416cfa | ||
|
|
377a979fa8 | ||
|
|
8cf2dffb79 | ||
|
|
66f153d087 | ||
|
|
d7a594c124 | ||
|
|
830caf2c2c | ||
|
|
28190c6649 | ||
|
|
125095d52e | ||
|
|
f00d992755 | ||
|
|
e86ece9da1 | ||
|
|
7dd3d9a0bf | ||
|
|
213696bdfc | ||
|
|
b64e597d53 | ||
|
|
186344d8de | ||
|
|
42e0be0f78 | ||
|
|
388d3bef62 | ||
|
|
7757f3a3c4 | ||
|
|
cab948d988 | ||
|
|
4852182aa0 | ||
|
|
434aba95eb | ||
|
|
0a5ca66a64 | ||
|
|
533356be0f | ||
|
|
4cc0149073 | ||
|
|
d28f117979 | ||
|
|
c14d13007c | ||
|
|
df8a12664c | ||
|
|
ca79cf659b | ||
|
|
86034d5a98 | ||
|
|
8f4258716f | ||
|
|
3be28b528a | ||
|
|
e3dd8c46de | ||
|
|
72f9f20b53 | ||
|
|
bb33f7fbcd | ||
|
|
1ed03b0716 | ||
|
|
ec4c8458f0 | ||
|
|
4480b5815e | ||
|
|
5709800f1a | ||
|
|
a11b2ec07b | ||
|
|
5220a7c2f7 | ||
|
|
99d6d3dc7a | ||
|
|
914e036fe2 | ||
|
|
c87cce4091 | ||
|
|
161c5f9b84 | ||
|
|
cc28cbb012 | ||
|
|
5aa9b21d2f | ||
|
|
d56097ed06 | ||
|
|
e1da479646 | ||
|
|
95138d4c5b | ||
|
|
6a03d7978d | ||
|
|
c5235a340b | ||
|
|
d1348de690 | ||
|
|
1d28e9f4f3 | ||
|
|
5580ecacf9 | ||
|
|
c69270e50a | ||
|
|
d98703234b | ||
|
|
493d11d404 | ||
|
|
f78c2b826c | ||
|
|
dbe8428789 | ||
|
|
ecf0157dba | ||
|
|
eebeaafd9d | ||
|
|
1dbfe29970 | ||
|
|
769fb56285 | ||
|
|
39623d910b | ||
|
|
0e0c9a9b37 | ||
|
|
d8cffd6adf | ||
|
|
990f820333 | ||
|
|
9f70dc9ef8 | ||
|
|
8851a005b0 | ||
|
|
ed24b4b95a | ||
|
|
fb0cea2056 | ||
|
|
385c7bd904 | ||
|
|
7e0147d842 | ||
|
|
e49bb9af31 | ||
|
|
7daa98c9fa | ||
|
|
144c3b3c75 | ||
|
|
5a9852c292 | ||
|
|
d3e3446781 | ||
|
|
ed770e53e1 | ||
|
|
9ec34ad19d | ||
|
|
1cd8a3e0fc | ||
|
|
97f400564a | ||
|
|
e73bda2161 | ||
|
|
19ea1ac76f | ||
|
|
ce53e2c57d | ||
|
|
9df167cea1 | ||
|
|
6b8ffca431 | ||
|
|
835f60f00b | ||
|
|
42171cc799 | ||
|
|
dda56346bc | ||
|
|
0745c42af9 | ||
|
|
1e876faffc | ||
|
|
8bd7acd1da | ||
|
|
12a53f36cc | ||
|
|
4b9894b2bc | ||
|
|
4b020c54ee | ||
|
|
672d9fc4a2 | ||
|
|
9a9b20276e | ||
|
|
f73419ca8d | ||
|
|
b113a4c38c | ||
|
|
d811a58297 | ||
|
|
79d8b91977 | ||
|
|
abfb82f340 | ||
|
|
c3e027c54f | ||
|
|
67322b2665 | ||
|
|
423112b2fd | ||
|
|
d48f252bb0 | ||
|
|
054d833dd6 | ||
|
|
45b8178295 | ||
|
|
1cf4076be1 | ||
|
|
6e59e30f17 | ||
|
|
353ed34a71 | ||
|
|
6e0ce3f0e4 | ||
|
|
dc6d3ca5c6 | ||
|
|
5b5fb1c4d6 | ||
|
|
29f328abf0 | ||
|
|
fbd03b6a26 | ||
|
|
f5a58decf5 | ||
|
|
595958d578 | ||
|
|
034ceb2a99 | ||
|
|
59b113b2dc | ||
|
|
4239d215b8 | ||
|
|
d5d5274b6f | ||
|
|
6f325cb294 | ||
|
|
a07a7359b6 | ||
|
|
89983b1508 | ||
|
|
31bd29b92b | ||
|
|
db7e785734 | ||
|
|
d40d4e8d79 | ||
|
|
bf02aee57d | ||
|
|
f91d5f9fe9 | ||
|
|
1296918abe | ||
|
|
f9e7f344be | ||
|
|
de40d640d5 | ||
|
|
6eb1ec3cf5 | ||
|
|
d4e366ee14 | ||
|
|
ca25bb983f | ||
|
|
9c62ece9bd | ||
|
|
84c7acfeed | ||
|
|
319e3baa78 | ||
|
|
d496c0b14d | ||
|
|
b9bab148ee | ||
|
|
cba4af3d65 | ||
|
|
22bcbaeebe | ||
|
|
d8c59163fa | ||
|
|
7e60d9c422 | ||
|
|
0d2eb7f693 | ||
|
|
35b767402b | ||
|
|
85e481d3cd |
No files matched your search
+46
@@ -0,0 +1,46 @@
|
||||
build
|
||||
Makefile.local
|
||||
*.swp
|
||||
*tags
|
||||
*~
|
||||
|
||||
# OS X
|
||||
####################
|
||||
.Spotlight-V100/
|
||||
.Trashes/
|
||||
._*
|
||||
.AppleDouble
|
||||
.DS_Store
|
||||
.LSOverride
|
||||
Icon?
|
||||
make-macosx-values.local
|
||||
|
||||
# Xcode
|
||||
####################
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
*.user
|
||||
*.xcuserstate
|
||||
*.moved-aside
|
||||
*~.nib
|
||||
.idea/
|
||||
DerivedData/
|
||||
project.xcworkspace/
|
||||
xcuserdata/
|
||||
profile
|
||||
!default.pbxuser
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.perspectivev3
|
||||
|
||||
# Microsoft Visual Studio
|
||||
####################
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.suo
|
||||
|
||||
.vs
|
||||
out
|
||||
code_unfinished/*
|
||||
+164
-51
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(omohaaded)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(openmohaa)
|
||||
|
||||
include(TargetArch.cmake)
|
||||
|
||||
@@ -24,7 +24,7 @@ endif()
|
||||
set(TARGET_BASE_GAME "main${TARGET_BASE_SUFFIX}")
|
||||
|
||||
if(MSVC)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-Wno-comment)
|
||||
# Ignore warnings for code like 'assert("Assert string")'
|
||||
@@ -55,6 +55,17 @@ ELSE()
|
||||
set(TARGET_PLATFORM_PREFIX "")
|
||||
ENDIF()
|
||||
|
||||
IF(CMAKE_BUILD_TYPE MATCHES Debug)
|
||||
set(TARGET_CONFIG_SUFFIX "-dbg")
|
||||
add_definitions(-D_DEBUG)
|
||||
ELSE()
|
||||
set(TARGET_CONFIG_SUFFIX "")
|
||||
ENDIF()
|
||||
|
||||
# Common stuff
|
||||
|
||||
## For modules
|
||||
|
||||
set(SOURCES_SHARED
|
||||
"code/qcommon/class.cpp"
|
||||
"code/qcommon/con_set.cpp"
|
||||
@@ -71,45 +82,48 @@ set(SOURCES_SHARED
|
||||
"code/script/scriptvariable.cpp"
|
||||
)
|
||||
|
||||
# Shared libraries
|
||||
file(GLOB_RECURSE SOURCES_BG "code/game/bg_*.cpp")
|
||||
|
||||
## Server game library
|
||||
file(GLOB_RECURSE SOURCES_GAME "code/game/*.c" "code/game/*.cpp" "code/parser/*.cpp" "code/script/*.cpp")
|
||||
set(SOURCES_GAME_LIB ${SOURCES_SHARED} ${SOURCES_GAME})
|
||||
|
||||
add_library(fgame SHARED ${SOURCES_GAME_LIB})
|
||||
target_compile_definitions(fgame PRIVATE GAME_DLL ARCHIVE_SUPPORTED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
|
||||
target_include_directories(fgame PUBLIC "code/qcommon" "code/script" "code/game")
|
||||
target_include_directories(fgame PRIVATE "code/parser")
|
||||
target_compile_features(fgame PUBLIC cxx_std_17)
|
||||
|
||||
set_target_properties(fgame PROPERTIES PREFIX "${TARGET_PLATFORM_PREFIX}")
|
||||
set_target_properties(fgame PROPERTIES OUTPUT_NAME "game${TARGET_ARCH_SUFFIX}")
|
||||
set_target_properties(fgame PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TARGET_BASE_GAME}")
|
||||
INSTALL(TARGETS fgame DESTINATION "${TARGET_BASE_GAME}")
|
||||
|
||||
## Client game library
|
||||
## TODO! Build the cgame shared library
|
||||
|
||||
# Applications
|
||||
|
||||
## Code for all executables
|
||||
## For executable
|
||||
|
||||
### Platform-specific code
|
||||
if(WIN32)
|
||||
set(SOURCES_PLATFORM_SPECIFIC
|
||||
"code/sys/con_win32.c"
|
||||
"code/sys/sys_win32.c"
|
||||
"code/sys/win_bounds.cpp"
|
||||
"code/sys/win_localization.cpp"
|
||||
WIN32
|
||||
"code/win32/win_bounds.cpp"
|
||||
"code/win32/win_localization.cpp"
|
||||
"code/win32/win_main.c"
|
||||
"code/win32/win_net.c"
|
||||
"code/win32/win_shared.c"
|
||||
"code/win32/win_syscon.c"
|
||||
"code/win32/win_wndproc.c"
|
||||
"code/win32/win_resource.rc"
|
||||
)
|
||||
|
||||
set(SOURCES_CLIENT_PLATFORM_SPECIFIC
|
||||
"code/win32/win_gamma.c"
|
||||
"code/win32/win_glimp.c"
|
||||
"code/win32/win_input.c"
|
||||
"code/win32/win_qgl.c"
|
||||
"code/win32/win_snd.c"
|
||||
)
|
||||
else()
|
||||
set(SOURCES_PLATFORM_SPECIFIC
|
||||
"code/sys/con_tty.c"
|
||||
"code/sys/sys_unix.c"
|
||||
"code/unix/linux_signals.c"
|
||||
"code/unix/unix_main.c"
|
||||
"code/unix/unix_net.c"
|
||||
"code/unix/unix_shared.c"
|
||||
# These are still used even they're prefixed 'win'
|
||||
"code/sys/win_bounds.cpp"
|
||||
"code/sys/win_localization.cpp"
|
||||
"code/win32/win_bounds.cpp"
|
||||
"code/win32/win_localization.cpp"
|
||||
)
|
||||
|
||||
set(SOURCES_CLIENT_PLATFORM_SPECIFIC
|
||||
"code/unix/linux_common.c"
|
||||
"code/unix/linux_glimp.c"
|
||||
"code/unix/linux_joystick.c"
|
||||
"code/unix/linux_qgl.c"
|
||||
"code/unix/linux_snd.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -135,16 +149,11 @@ set(SOURCES_COMMON
|
||||
"code/qcommon/memory.c"
|
||||
"code/qcommon/msg.cpp"
|
||||
"code/qcommon/net_chan.c"
|
||||
"code/qcommon/net_ip.c"
|
||||
"code/qcommon/q_math.c"
|
||||
"code/qcommon/q_shared.c"
|
||||
"code/qcommon/tiki_main.cpp"
|
||||
"code/qcommon/tiki_script.cpp"
|
||||
"code/qcommon/unzip.c"
|
||||
# Main stuff
|
||||
"code/sys/sys_main.c"
|
||||
"code/sys/sys_autoupdater.c"
|
||||
"code/sys/con_log.c"
|
||||
# Gamespy
|
||||
"code/gamespy/sv_gamespy.c"
|
||||
"code/gamespy/sv_gqueryreporting.c"
|
||||
@@ -154,35 +163,139 @@ file(GLOB_RECURSE SOURCES_SKEL "code/tiki/*.cpp" "code/skeletor/*.cpp")
|
||||
|
||||
set(SOURCES_APP ${SOURCES_SHARED} ${SOURCES_COMMON} ${SOURCES_SKEL})
|
||||
|
||||
## Executables
|
||||
# Targets
|
||||
|
||||
## Server
|
||||
|
||||
### Server game library
|
||||
file(GLOB_RECURSE SOURCES_GAME "code/game/*.c" "code/game/*.cpp" "code/parser/*.cpp" "code/script/*.cpp")
|
||||
set(SOURCES_GAME_LIB ${SOURCES_SHARED} ${SOURCES_GAME})
|
||||
|
||||
add_library(fgame SHARED ${SOURCES_GAME_LIB})
|
||||
target_compile_definitions(fgame PRIVATE GAME_DLL ARCHIVE_SUPPORTED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
|
||||
target_include_directories(fgame PUBLIC "code/qcommon" "code/script" "code/game")
|
||||
target_include_directories(fgame PRIVATE "code/parser")
|
||||
target_compile_features(fgame PUBLIC cxx_nullptr)
|
||||
target_compile_features(fgame PUBLIC c_variadic_macros)
|
||||
|
||||
set_target_properties(fgame PROPERTIES PREFIX "${TARGET_PLATFORM_PREFIX}")
|
||||
set_target_properties(fgame PROPERTIES OUTPUT_NAME "game${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
|
||||
set_target_properties(fgame PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TARGET_BASE_GAME}")
|
||||
INSTALL(TARGETS fgame DESTINATION "${TARGET_BASE_GAME}")
|
||||
|
||||
include("code/gamespy/gcd.cmake")
|
||||
|
||||
### Client version
|
||||
### TODO! Build the executable client (without the server part)
|
||||
|
||||
### Listen version
|
||||
### TODO! Build the executable, full version (both client and server)
|
||||
|
||||
### Dedicated version
|
||||
### Server executable
|
||||
file(GLOB_RECURSE SOURCES_SERVER "code/server/*.c" "code/server/*.cpp")
|
||||
set(SOURCES_SERVER_APP ${SOURCES_APP} ${SOURCES_SERVER})
|
||||
|
||||
add_executable(omohaaded ${SOURCES_SERVER_APP} ${SOURCES_PLATFORM_SPECIFIC} "code/null/null_client.c" "code/null/null_input.c" "code/null/null_snddma.c")
|
||||
target_compile_definitions(omohaaded PRIVATE NO_SCRIPTENGINE DEDICATED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
|
||||
target_compile_features(omohaaded PUBLIC cxx_std_17)
|
||||
add_executable(omohaaded ${SOURCES_PLATFORM_SPECIFIC} ${SOURCES_SERVER_APP} "code/null/null_client.c" "code/null/null_input.c" "code/null/null_snddma.c")
|
||||
target_compile_definitions(omohaaded PRIVATE NO_SCRIPTENGINE APP_MODULE DEDICATED TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
|
||||
target_compile_features(omohaaded PUBLIC cxx_nullptr)
|
||||
target_compile_features(omohaaded PUBLIC c_variadic_macros)
|
||||
# Gamespy dependency
|
||||
add_dependencies(omohaaded gcd)
|
||||
target_link_libraries(omohaaded PRIVATE gcd)
|
||||
target_include_directories(omohaaded PUBLIC "code/qcommon" "code/script" "code/gamespy" "code/server" "code/SDL2/include")
|
||||
set_target_properties(omohaaded PROPERTIES OUTPUT_NAME "omohaaded${TARGET_BASE_SUFFIX}${TARGET_ARCH_SUFFIX}")
|
||||
set_target_properties(omohaaded PROPERTIES OUTPUT_NAME "omohaaded${TARGET_BASE_SUFFIX}${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
|
||||
|
||||
if(WIN32)
|
||||
if (MSVC)
|
||||
target_link_options(omohaaded PRIVATE "/MANIFEST:NO")
|
||||
endif()
|
||||
target_link_libraries(omohaaded PRIVATE wsock32 ws2_32)
|
||||
target_link_libraries(omohaaded PRIVATE winmm)
|
||||
|
||||
INSTALL(FILES $<TARGET_PDB_FILE:fgame> DESTINATION "${TARGET_BASE_GAME}" OPTIONAL)
|
||||
INSTALL(FILES $<TARGET_PDB_FILE:omohaaded> DESTINATION "./" OPTIONAL)
|
||||
elseif(UNIX)
|
||||
target_link_libraries(omohaaded PRIVATE ${CMAKE_DL_LIBS})
|
||||
find_package(Threads)
|
||||
target_link_libraries(omohaaded PRIVATE ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(omohaaded PRIVATE m)
|
||||
target_link_libraries(omohaaded PRIVATE stdc++)
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS omohaaded DESTINATION "./")
|
||||
|
||||
if (WITH_CLIENT)
|
||||
## Client
|
||||
|
||||
### Client game library
|
||||
file(GLOB_RECURSE SOURCES_CGAME "code/cgame/*.c" "code/cgame/*.cpp")
|
||||
set(SOURCES_CGAME_LIB ${SOURCES_SHARED} ${SOURCES_CGAME} ${SOURCES_BG})
|
||||
|
||||
add_library(cgame SHARED ${SOURCES_CGAME_LIB})
|
||||
target_compile_definitions(cgame PRIVATE CGAME_DLL NO_SCRIPTENGINE TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
|
||||
target_include_directories(cgame PUBLIC "code/qcommon" "code/cgame" "code/script")
|
||||
target_compile_features(cgame PUBLIC cxx_nullptr)
|
||||
target_compile_features(cgame PUBLIC c_variadic_macros)
|
||||
|
||||
set_target_properties(cgame PROPERTIES PREFIX "${TARGET_PLATFORM_PREFIX}")
|
||||
set_target_properties(cgame PROPERTIES OUTPUT_NAME "cgame${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
|
||||
set_target_properties(cgame PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TARGET_BASE_GAME}")
|
||||
INSTALL(TARGETS cgame DESTINATION "${TARGET_BASE_GAME}")
|
||||
|
||||
### Executable
|
||||
file(GLOB_RECURSE SOURCES_JPEG_8 "code/jpeg-8c/*.c")
|
||||
add_library(jpeg8 STATIC ${SOURCES_JPEG_8})
|
||||
target_include_directories(jpeg8 PRIVATE "code/jpeg-8c")
|
||||
|
||||
file(GLOB_RECURSE SOURCES_CLIENT "code/client/*.c" "code/client/*.cpp" "code/qcommon/puff.c")
|
||||
file(GLOB_RECURSE SOURCES_UILIB "code/uilib/*.c" "code/uilib/*.cpp")
|
||||
file(GLOB_RECURSE SOURCES_RENDERER "code/renderer/*.c" "code/renderer/*.cpp")
|
||||
#file(GLOB_RECURSE SOURCES_RENDERER "code/sdl/*.c" "code/renderercommon/*.c" "code/renderergl2/*.c" "code/renderergl2/*.cpp")
|
||||
set(SOURCES_CLIENT_APP ${SOURCES_APP} ${SOURCES_SERVER} ${SOURCES_CLIENT} ${SOURCES_UILIB} ${SOURCES_LIBS} ${SOURCES_RENDERER})
|
||||
|
||||
add_executable(openmohaa ${SOURCES_PLATFORM_SPECIFIC} ${SOURCES_CLIENT_APP} ${SOURCES_CLIENT_PLATFORM_SPECIFIC})
|
||||
target_compile_definitions(openmohaa PRIVATE NO_SCRIPTENGINE APP_MODULE TARGET_GAME_TYPE=${TARGET_GAME_TYPE})
|
||||
target_compile_features(openmohaa PUBLIC cxx_nullptr)
|
||||
target_compile_features(openmohaa PUBLIC c_variadic_macros)
|
||||
target_link_libraries(openmohaa PRIVATE jpeg8)
|
||||
# Gamespy dependency
|
||||
add_dependencies(openmohaa gcd)
|
||||
target_link_libraries(openmohaa PRIVATE gcd)
|
||||
target_include_directories(openmohaa PUBLIC "code/qcommon" "code/script" "code/gamespy" "code/server" "code/client" "code/uilib" "code/SDL2/include" "code/jpeg-8c")
|
||||
set_target_properties(openmohaa PROPERTIES OUTPUT_NAME "openmohaa${TARGET_BASE_SUFFIX}${TARGET_ARCH_SUFFIX}${TARGET_CONFIG_SUFFIX}")
|
||||
|
||||
if(WIN32)
|
||||
if (MSVC)
|
||||
target_link_options(openmohaa PRIVATE "/MANIFEST:NO")
|
||||
|
||||
#add_library(sdl2 SHARED IMPORTED)
|
||||
#set_target_properties(sdl2 PROPERTIES
|
||||
# IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/code/libs/win32/SDL2.lib"
|
||||
#)
|
||||
#
|
||||
#add_library(sdl2main SHARED IMPORTED)
|
||||
#set_target_properties(sdl2main PROPERTIES
|
||||
# IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/code/libs/win32/SDL2main.lib"
|
||||
#)
|
||||
#
|
||||
#add_library(glew32 SHARED IMPORTED)
|
||||
#set_target_properties(glew32 PROPERTIES
|
||||
# IMPORTED_IMPLIB "${CMAKE_SOURCE_DIR}/code/libs/win32/glew32.lib"
|
||||
#)
|
||||
|
||||
target_link_libraries(openmohaa PRIVATE opengl32)
|
||||
endif()
|
||||
|
||||
target_link_libraries(openmohaa PRIVATE wsock32 ws2_32)
|
||||
target_link_libraries(openmohaa PRIVATE winmm)
|
||||
|
||||
INSTALL(FILES $<TARGET_PDB_FILE:cgame> DESTINATION "${TARGET_BASE_GAME}" OPTIONAL)
|
||||
INSTALL(FILES $<TARGET_PDB_FILE:openmohaa> DESTINATION "./" OPTIONAL)
|
||||
elseif(UNIX)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLUT REQUIRED)
|
||||
find_package(X11 REQUIRED)
|
||||
find_package(Threads)
|
||||
|
||||
target_include_directories(openmohaa PRIVATE ${OPENGL_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS})
|
||||
target_link_libraries(openmohaa PRIVATE ${OPENGL_LIBRARIES} ${GLUT_LIBRARY} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(openmohaa PRIVATE m)
|
||||
target_link_libraries(openmohaa PRIVATE stdc++)
|
||||
target_link_libraries(openmohaa PRIVATE ${X11_LIBRARIES} ${X11_Xxf86vm_LIB} ${X11_Xext_LIB} Xxf86dga)
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS openmohaa DESTINATION "./")
|
||||
endif()
|
||||
@@ -2,22 +2,23 @@
|
||||
|
||||
| Path | Description |
|
||||
| ---------------------|-------------------------------------------------------------------
|
||||
| build/ | Output files |
|
||||
| code/ | OpenMoHAA source code |
|
||||
| code/cgame | Client game code |
|
||||
| code/client | Client (network stuff, snapshots, etc) |
|
||||
| code/game | Server game code (game logic stuff, etc) |
|
||||
| code/gamespy | Gamespy SDK |
|
||||
| code/mohui | MoHAA User Interface |
|
||||
| code/null | Null redirector (used by the OpenMoHAA Dedicated Server) |
|
||||
| code/parser | Flex/Bison parser |
|
||||
| code/qcommon | Global shared stuff such as maths |
|
||||
| code/renderer | OpenMoHAA renderer |
|
||||
| code/sdl(12) | SDL code |
|
||||
| code/script | Script engine |
|
||||
| code/server | Server code (networkn snapshots, handling clients etc) |
|
||||
| code/server | Server code (network, snapshots, handling clients etc) |
|
||||
| code/skeletor | Skeleton model engine |
|
||||
| code/sys | Main application system |
|
||||
| code/tiki | Complete TIKI engine |
|
||||
| code/uilib | UI library (Ubertools stuff) |
|
||||
| code/{win32,unix} | Platform-specific code |
|
||||
| docker | Docker files, for compiling on various linux versions |
|
||||
| docs | Documentation stuff |
|
||||
| misc/ | Project stuff, definition files and various resources stuff. |
|
||||
@@ -14,25 +14,38 @@
|
||||
|
||||
## Current State
|
||||
|
||||
OpenMoHAA is still in its early days.
|
||||
|
||||
### Server
|
||||
|
||||
The server version can successfully be built. There are few unimplemented stuff from the game library :
|
||||
The server version can successfully be built.
|
||||
Some stuff are not working as intended, such as Actor or Vehicle. These systems are both almost fully implemented, but not really in stable state.
|
||||
|
||||
- Actor
|
||||
- Vehicle
|
||||
Overall the server part and the game module are almost fully implemented, but the stability may vary, there may be some minor bugs and crashes.
|
||||
|
||||
### Client
|
||||
|
||||
There is currently no client build because the client code is currently unusable. Here is what's missing or unimplemented :
|
||||
The client version of OpenMoHAA is partially implemented and not stable currently. The cgame module is partially implemented as well, but is compatible with the original MOH:AA game. Credits to **Heavy Metal: F.A.K.K. 2**'s SDK for the cgame module.
|
||||
|
||||
- cgame (using F.A.K.K build)
|
||||
- rendering (mostly advanced)
|
||||
- sound (must be reworked)
|
||||
- UI
|
||||
Here is the current working state for each part of the engine:
|
||||
|
||||
| Part name | Full | Almost | Half | Early | Bad | Not working | Comment |
|
||||
|-------------------------|------|--------|------|-------|-----|-------------|-------------------------------------------------------------------|
|
||||
| Audio | | | | | x | | Very basic implementation from Quake III |
|
||||
| CG Module | | x | | | | | Missing FX, Marks and decals |
|
||||
| Client | | | x | | | | Missing GameSpy, server list, binds, map picker, ... |
|
||||
| Collision | x | | | | | | |
|
||||
| Model/TIKI/Skeletor | x | | | | | | |
|
||||
| Renderer | | | | x | | | Missing ghost, marks, sphere lights, sky portal, sun flare, swipe |
|
||||
| Server | | x | | | | | Probably a few bugs remaining |
|
||||
| Server module (fgame) | | x | | | | | Actor, vehicle, and few gameplay bugs |
|
||||
| UI | | | | x | | | Has core features only (menu, widgets, console, hud, urc loading) |
|
||||
|
||||
NOTE: Both client and server version can be compiled to target **Medal of Honor: Spearhead** and **Medal of Honor: Breakthrough**.
|
||||
|
||||
## Running
|
||||
|
||||
Backup the existing **gamex86.dll** (rename it to **gamex86.bak**).
|
||||
Backup existing mohaa files, **cgamex86.dll** and **gamex86.dll** (set their extension to **.bak**)
|
||||
|
||||
a) extract archive to your MOHAA installation directory.
|
||||
|
||||
@@ -50,23 +63,38 @@ You can now start a local OpenMOHAA server or play on a server.
|
||||
|
||||
## Compiling
|
||||
|
||||
These are the tools required for all platforms :
|
||||
- CMake
|
||||
- Flex and Bison
|
||||
- Clang (at least version 11)
|
||||
OpenMoHAA supports both x86 and x64 architectures, and although the target platform is Windows, it still can be compiled for other platforms, and even other architectures.
|
||||
|
||||
At least C++17 is required. Avoid GCC/G++ because it uses nonstandard extensions.
|
||||
These are the tools required for all platforms :
|
||||
- CMake >= 3.5
|
||||
- Flex and Bison (currently not used)
|
||||
- A C++11 compiler is required.
|
||||
|
||||
The installation directory can be set to MOHAA directory.
|
||||
|
||||
The client build can be built by adding `-DWITH_CLIENT=1` to the CMake command line. This will compile the cgame module and the full app with rendering, ui and sound suppport, alongside the dedicated server version.
|
||||
|
||||
To compile for either Spearhead or Breakthrough, append `-DTARGET_GAME_TYPE=x` where x can be 1 for Team Assault (Spearhead), and 2 for Team Tactics (Breakthrough). 2 is recommended because Team Tactics can connect to both Spearhead and Breakthrough servers.
|
||||
|
||||
### Linux
|
||||
|
||||
These are the tools required on Unix :
|
||||
- Clang >= 3.3 or GCC >= 4.8.1
|
||||
|
||||
**clang-3.5** and **gcc-4.8.5** should work (tested on Ubuntu 16.04).
|
||||
|
||||
1 line install command with latest clang version : `sudo apt-get install -y ninja-build cmake make clang-15 lld-15 flex bison`
|
||||
|
||||
### Windows
|
||||
|
||||
Visual Studio (2019 or 2022) is generally preferred.
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Third party
|
||||
|
||||
### SDL
|
||||
@@ -103,8 +131,8 @@ https://xiph.org/vorbis/
|
||||
|
||||
https://opus-codec.org/
|
||||
|
||||
## URL
|
||||
## URLs and communities
|
||||
|
||||
- https://openmohaa.sourceforge.net/
|
||||
- https://github.com/openmoh/openmohaa/
|
||||
- https://mohaaaa.co.uk/AAAAMOHAA/index.php
|
||||
- https://x-null.net/
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,964 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// client side entity commands
|
||||
|
||||
/*
|
||||
The cg_command system is used for a variety of different functions, but mostly it is
|
||||
used for spawning client side temp models. Either through the use of emitters or
|
||||
commands that are tied to various frames of animation.
|
||||
|
||||
The ctempmodel_t class is the data structure for all of the static tempmodels.
|
||||
These are updated every frame and refEntity and refSprite data is created and added
|
||||
to the renderer for drawing.
|
||||
|
||||
The spawnthing_t is the intermediate data holder. When the TIKI file is processed
|
||||
the spawnthing_t is cleared out and values are assigned based on the commands issued.
|
||||
|
||||
cg_common_data is a list of common data elements that are the same in the ctempmodel_t and
|
||||
the spawhthing_t
|
||||
|
||||
After the m_spawnthing is filled in, 1 or more ctempmodel_t structures are spawned.
|
||||
|
||||
The ClientCommandManager is the listener that process all of the commands in the
|
||||
TIKI file, similar to ScriptMaster in the server game dll.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "listener.h"
|
||||
#include "script.h"
|
||||
#include "vector.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
#define EMITTER_DEFAULT_LIFE 1000
|
||||
#define MAX_EMITTERS 32
|
||||
#define MAX_SWIPES 32
|
||||
|
||||
#define T_RANDSCALE (1 << 0)
|
||||
#define T_SCALEANIM (1 << 1)
|
||||
#define T_SPHERE (1 << 2)
|
||||
#define T_INWARDSPHERE (1 << 3)
|
||||
#define T_CIRCLE (1 << 4)
|
||||
#define T_FADE (1 << 5)
|
||||
#define T_DIETOUCH (1 << 6)
|
||||
#define T_ANGLES (1 << 7)
|
||||
#define T_WAVE (1 << 8)
|
||||
#define T_SWARM (1 << 9)
|
||||
#define T_ALIGN (1 << 10)
|
||||
#define T_COLLISION (1 << 11)
|
||||
#define T_FLICKERALPHA (1 << 12)
|
||||
#define T_DLIGHT (1 << 13)
|
||||
#define T_FADEIN (1 << 14)
|
||||
#define T_GLOBALFADEIN (1 << 15)
|
||||
#define T_GLOBALFADEOUT (1 << 16)
|
||||
#define T_PARENTLINK (1 << 17)
|
||||
#define T_RANDOMROLL (1 << 18)
|
||||
#define T_HARDLINK (1 << 19)
|
||||
#define T_ANIMATEONCE (1 << 20)
|
||||
#define T_BEAMTHING (1 << 21)
|
||||
#define T_RANDVELAXIS (1 << 22)
|
||||
#define T_BOUNCESOUND (1 << 23)
|
||||
#define T_BOUNCESOUNDONCE (1 << 24)
|
||||
#define T_TWINKLE (1 << 25)
|
||||
#define T_TWINKLE_OFF (1 << 26)
|
||||
#define T_ALIGNONCE (1 << 27)
|
||||
#define T_SCALEUPDOWN (1 << 28)
|
||||
#define T_AUTOCALCLIFE (1 << 29)
|
||||
#define T_ASSIGNED_NUMBER (1 << 30)
|
||||
#define T_DETAIL (1 << 31)
|
||||
|
||||
#define T2_MOVE (1 << 0)
|
||||
#define T2_AMOVE (1 << 1)
|
||||
#define T2_ACCEL (1 << 2)
|
||||
#define T2_TRAIL (1 << 3)
|
||||
#define T2_PHYSICS_EVERYFRAME (1 << 4)
|
||||
#define T2_TEMPORARY_DECAL (1 << 5)
|
||||
#define T2_BOUNCE_DECAL (1 << 6)
|
||||
#define T2_PARALLEL (1 << 7)
|
||||
#define T2_VOLUMETRIC (1 << 8)
|
||||
#define T2_WIND_AFFECT (1 << 10)
|
||||
#define T2_SPRITEGRIDLIGHTING (1 << 11)
|
||||
#define T2_WATERONLY (1 << 12)
|
||||
#define T2_ALIGNSTRETCH (1 << 13)
|
||||
#define T2_ALWAYSDRAW (1 << 14)
|
||||
#define T2_CLAMP_VEL (1 << 15)
|
||||
#define T2_CLAMP_VEL_AXIS (1 << 16)
|
||||
#define T2_CONE (1 << 17)
|
||||
#define T2_RADIALVELOCITY (1 << 18)
|
||||
#define T2_FRICTION (1 << 19)
|
||||
#define T2_VARYCOLOR (1 << 20)
|
||||
|
||||
class spawnthing_t;
|
||||
class specialeffect_t;
|
||||
|
||||
typedef enum { NOT_RANDOM, RANDOM, CRANDOM } randtype_t;
|
||||
|
||||
class cg_common_data : public Class
|
||||
{
|
||||
public:
|
||||
cg_common_data();
|
||||
|
||||
int life;
|
||||
int createTime;
|
||||
Vector origin;
|
||||
Vector oldorigin;
|
||||
Vector accel;
|
||||
Vector angles;
|
||||
Vector velocity;
|
||||
Vector avelocity;
|
||||
Vector parentOrigin;
|
||||
Vector parentMins;
|
||||
Vector parentMaxs;
|
||||
Vector minVel;
|
||||
Vector maxVel;
|
||||
float color[4];
|
||||
float alpha;
|
||||
float scaleRate;
|
||||
float scalemin;
|
||||
float scalemax;
|
||||
float bouncefactor;
|
||||
int bouncecount;
|
||||
int maxbouncecount;
|
||||
str bouncesound;
|
||||
int bouncesound_delay;
|
||||
int flags;
|
||||
int flags2;
|
||||
dtiki_t* tiki;
|
||||
int swarmfreq;
|
||||
float swarmmaxspeed;
|
||||
float swarmdelta;
|
||||
float lightIntensity;
|
||||
int lightType;
|
||||
int fadeintime;
|
||||
int fadedelay;
|
||||
int parent;
|
||||
int collisionmask;
|
||||
int min_twinkletimeoff;
|
||||
int max_twinkletimeoff;
|
||||
int min_twinkletimeon;
|
||||
int max_twinkletimeon;
|
||||
int lightstyle;
|
||||
int physicsRate;
|
||||
float scale;
|
||||
float scale2;
|
||||
str swipe_shader;
|
||||
str swipe_tag_start;
|
||||
str swipe_tag_end;
|
||||
str shadername;
|
||||
float swipe_life;
|
||||
float friction;
|
||||
|
||||
float decal_orientation;
|
||||
float decal_radius;
|
||||
};
|
||||
|
||||
inline cg_common_data::cg_common_data()
|
||||
{
|
||||
int i;
|
||||
|
||||
bouncesound_delay = 0;
|
||||
life = 0;
|
||||
createTime = 0;
|
||||
alpha = 0;
|
||||
fadedelay = 0;
|
||||
lightIntensity = 0;
|
||||
lightType = (dlighttype_t)0;
|
||||
bouncefactor = 0;
|
||||
bouncecount = 0;
|
||||
maxbouncecount = 0;
|
||||
scaleRate = 0;
|
||||
scale = 1;
|
||||
scalemin = 0;
|
||||
scalemax = 0;
|
||||
swarmfreq = 0;
|
||||
swarmmaxspeed = 0;
|
||||
swarmdelta = 0;
|
||||
flags = 0;
|
||||
flags2 = 0;
|
||||
fadeintime = 0;
|
||||
parent = 0;
|
||||
tiki = nullptr;
|
||||
collisionmask = 0;
|
||||
min_twinkletimeoff = 0;
|
||||
max_twinkletimeoff = 0;
|
||||
min_twinkletimeon = 0;
|
||||
max_twinkletimeoff = 0;
|
||||
lightstyle = -1;
|
||||
physicsRate = 10;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
color[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ctempmodel_t : public Class
|
||||
{
|
||||
public:
|
||||
ctempmodel_t();
|
||||
|
||||
class ctempmodel_t* next;
|
||||
class ctempmodel_t* prev;
|
||||
|
||||
cg_common_data cgd;
|
||||
str modelname;
|
||||
|
||||
refEntity_t lastEnt;
|
||||
refEntity_t ent;
|
||||
|
||||
int number;
|
||||
int lastAnimTime;
|
||||
int lastPhysicsTime;
|
||||
int killTime;
|
||||
int next_bouncesound_time;
|
||||
int seed;
|
||||
int twinkleTime;
|
||||
int aliveTime;
|
||||
qboolean addedOnce;
|
||||
qboolean lastEntValid;
|
||||
spawnthing_t* m_spawnthing;
|
||||
|
||||
void (*touchfcn)(ctempmodel_t* ct, trace_t* trace);
|
||||
};
|
||||
|
||||
inline ctempmodel_t::ctempmodel_t()
|
||||
{
|
||||
number = 0;
|
||||
lastPhysicsTime = 0;
|
||||
lastAnimTime = 0;
|
||||
killTime = 0;
|
||||
next_bouncesound_time = 0;
|
||||
seed = 0;
|
||||
twinkleTime = 0;
|
||||
aliveTime = 0;
|
||||
addedOnce = qfalse;
|
||||
lastEntValid = qfalse;
|
||||
}
|
||||
|
||||
enum class vsstypes_t : unsigned char {
|
||||
VST_DEFAULT,
|
||||
VST_GUN,
|
||||
VST_IMPACT,
|
||||
VST_DIRT,
|
||||
VST_HEAVY,
|
||||
VST_STEAM,
|
||||
VST_MIST,
|
||||
VST_SGREN,
|
||||
VST_GRENADE,
|
||||
VST_FIRE,
|
||||
VST_GREASEFIRE,
|
||||
VST_DEBRIS,
|
||||
NUM_VSS_TYPES
|
||||
};
|
||||
|
||||
class cvssource_t
|
||||
{
|
||||
public:
|
||||
cvssource_t* next;
|
||||
cvssource_t* prev;
|
||||
cvssource_t* stnext;
|
||||
int stindex;
|
||||
Vector lastOrigin;
|
||||
float lastRadius;
|
||||
float lastDensity;
|
||||
float lastColor[3];
|
||||
float lastLighting[3];
|
||||
Vector newOrigin;
|
||||
float newRadius;
|
||||
float newDensity;
|
||||
float newColor[3];
|
||||
float newLighting[3];
|
||||
float ooRadius;
|
||||
Vector velocity;
|
||||
float startAlpha;
|
||||
int roll;
|
||||
Vector repulsion;
|
||||
int lifeTime;
|
||||
int collisionmask;
|
||||
int parent;
|
||||
int flags;
|
||||
int flags2;
|
||||
int smokeType;
|
||||
float typeInfo;
|
||||
float fadeMult;
|
||||
float scaleMult;
|
||||
int lastPhysicsTime;
|
||||
int lastLightingTime;
|
||||
qboolean lastValid;
|
||||
};
|
||||
|
||||
class cvssourcestate_t
|
||||
{
|
||||
public:
|
||||
Vector origin;
|
||||
float color[3];
|
||||
float radius;
|
||||
float density;
|
||||
};
|
||||
|
||||
#define LIFE_SWIPE 1
|
||||
#define MAX_SWIPE_POINTS 64
|
||||
|
||||
struct swipepoint_t {
|
||||
vec3_t points[2];
|
||||
float time;
|
||||
};
|
||||
|
||||
class swipething_t : public Class
|
||||
{
|
||||
public:
|
||||
qboolean enabled;
|
||||
str tagname_start;
|
||||
str tagname_end;
|
||||
int entitynum;
|
||||
float startcolor[4];
|
||||
float endcolor[4];
|
||||
swipepoint_t swipepoints[MAX_SWIPE_POINTS];
|
||||
swipepoint_t cntPoint;
|
||||
int num_live_swipes;
|
||||
int first_swipe;
|
||||
float life;
|
||||
qhandle_t shader;
|
||||
void Init();
|
||||
};
|
||||
|
||||
inline void swipething_t::Init()
|
||||
{
|
||||
int i;
|
||||
|
||||
enabled = qfalse;
|
||||
tagname_start = "";
|
||||
tagname_end = "";
|
||||
entitynum = -1;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
startcolor[i] = 1.f;
|
||||
endcolor[i] = 0.f;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_SWIPE_POINTS; i++) {
|
||||
VectorSet(swipepoints[i].points[0], 0.f, 0.f, 0.f);
|
||||
VectorSet(swipepoints[i].points[1], 0.f, 0.f, 0.f);
|
||||
swipepoints[i].time = 0.f;
|
||||
}
|
||||
|
||||
num_live_swipes = 0;
|
||||
first_swipe = 0;
|
||||
}
|
||||
|
||||
// Enttracker is used to keep track of client side tempmodels. They are
|
||||
// assigned a number from a pool of 256.
|
||||
class enttracker_t : public Class
|
||||
{
|
||||
public:
|
||||
enttracker_t();
|
||||
int AssignNumber(void);
|
||||
|
||||
protected:
|
||||
qboolean usedNumbers[256];
|
||||
virtual void RemoveEntity(int entnum);
|
||||
};
|
||||
|
||||
inline enttracker_t::enttracker_t()
|
||||
|
||||
{
|
||||
memset(usedNumbers, 0, sizeof(usedNumbers));
|
||||
}
|
||||
|
||||
inline void enttracker_t::RemoveEntity(int entnum)
|
||||
|
||||
{
|
||||
// If the entnum is a magic number, then clear out the usedNumber field, so
|
||||
// that it may be reused for this emitter.
|
||||
|
||||
if (entnum >= MAGIC_UNUSED_NUMBER) {
|
||||
entnum -= MAGIC_UNUSED_NUMBER;
|
||||
|
||||
assert(entnum >= 0);
|
||||
assert(entnum < 256);
|
||||
|
||||
usedNumbers[entnum] = qfalse;
|
||||
}
|
||||
}
|
||||
|
||||
inline int enttracker_t::AssignNumber(void)
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
// These numbers are used for client side tempmodels that are emitters
|
||||
// themselves. Since they don't have real entity_numbers, they must be
|
||||
// assigned a MAGIC number so we can keep track of the last time that the
|
||||
// model emitted something.
|
||||
|
||||
// Search for a number that is not used
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (!usedNumbers[i]) {
|
||||
usedNumbers[i] = qtrue;
|
||||
return MAGIC_UNUSED_NUMBER + i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
class emittertime_t : public Class
|
||||
{
|
||||
public:
|
||||
int entity_number;
|
||||
int last_emit_time;
|
||||
Vector oldorigin;
|
||||
qboolean active;
|
||||
qboolean lerp_emitter;
|
||||
};
|
||||
|
||||
// emitterthing_t is used to keep track of the last time and emitter was updated
|
||||
// for a particular entity number. It inherits from the enttracker_t so it can
|
||||
// manage client side tempmodels
|
||||
class emitterthing_t : public enttracker_t
|
||||
{
|
||||
protected:
|
||||
Container<emittertime_t> m_emittertimes; // A list of entity numbers and the
|
||||
// last time they emitted
|
||||
|
||||
public:
|
||||
emittertime_t* GetEmitTime(int entnum);
|
||||
virtual void RemoveEntity(int entnum);
|
||||
qboolean startoff;
|
||||
};
|
||||
|
||||
inline void emitterthing_t::RemoveEntity(int entnum)
|
||||
{
|
||||
int num, count;
|
||||
emittertime_t* et;
|
||||
|
||||
if (entnum == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
count = m_emittertimes.NumObjects();
|
||||
|
||||
for (num = count; num >= 1; num--) {
|
||||
et = &m_emittertimes.ObjectAt(num);
|
||||
if (et->entity_number == entnum) {
|
||||
m_emittertimes.RemoveObjectAt(num);
|
||||
}
|
||||
}
|
||||
|
||||
enttracker_t::RemoveEntity(entnum);
|
||||
}
|
||||
|
||||
inline emittertime_t* emitterthing_t::GetEmitTime(int entnum)
|
||||
{
|
||||
int num, count;
|
||||
emittertime_t* et;
|
||||
|
||||
count = m_emittertimes.NumObjects();
|
||||
|
||||
for (num = 1; num <= count; num++) {
|
||||
et = &m_emittertimes.ObjectAt(num);
|
||||
if (et->entity_number == entnum) {
|
||||
return et;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new entry if we didn't find it already
|
||||
et = &m_emittertimes.ObjectAt(m_emittertimes.AddObject({}));
|
||||
et->entity_number = entnum;
|
||||
et->last_emit_time = cg.time;
|
||||
et->lerp_emitter = qfalse;
|
||||
|
||||
if (this->startoff) {
|
||||
et->active = qfalse;
|
||||
} else {
|
||||
et->active = qtrue;
|
||||
}
|
||||
|
||||
return et;
|
||||
}
|
||||
|
||||
class commandtime_t : public Class
|
||||
{
|
||||
public:
|
||||
int entity_number;
|
||||
int command_number;
|
||||
int last_command_time;
|
||||
};
|
||||
|
||||
// This class is used for keeping track of the last time an entity executed a
|
||||
// particular command. A command number must be assigned externally by the user
|
||||
class commandthing_t : public enttracker_t
|
||||
{
|
||||
|
||||
Container<commandtime_t*> m_commandtimes; // A list of entity numbers and the last time they
|
||||
// executed a command
|
||||
|
||||
public:
|
||||
commandtime_t* GetLastCommandTime(int entnum, int commandnum);
|
||||
virtual void RemoveEntity(int entnum);
|
||||
};
|
||||
|
||||
inline void commandthing_t::RemoveEntity(int entnum)
|
||||
|
||||
{
|
||||
int num, count;
|
||||
commandtime_t* ct;
|
||||
|
||||
count = m_commandtimes.NumObjects();
|
||||
|
||||
for (num = count; num >= 1; num--) {
|
||||
ct = m_commandtimes.ObjectAt(num);
|
||||
if (ct->entity_number == entnum) {
|
||||
m_commandtimes.RemoveObjectAt(num);
|
||||
}
|
||||
}
|
||||
|
||||
enttracker_t::RemoveEntity(entnum);
|
||||
}
|
||||
|
||||
inline commandtime_t* commandthing_t::GetLastCommandTime(int entnum,
|
||||
int commandnum)
|
||||
|
||||
{
|
||||
int num, count;
|
||||
commandtime_t* ct;
|
||||
|
||||
// Search for this entity number
|
||||
count = m_commandtimes.NumObjects();
|
||||
|
||||
for (num = 1; num <= count; num++) {
|
||||
ct = m_commandtimes.ObjectAt(num);
|
||||
if ((ct->entity_number == entnum) &&
|
||||
(ct->command_number == commandnum)) {
|
||||
return ct;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new entry if we didn't find it
|
||||
ct = new commandtime_t;
|
||||
ct->entity_number = entnum;
|
||||
ct->command_number = commandnum;
|
||||
ct->last_command_time = 0;
|
||||
|
||||
m_commandtimes.AddObject(ct);
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
class spawnthing_t : public emitterthing_t
|
||||
{
|
||||
public:
|
||||
Container<str>
|
||||
m_modellist; // A list of models that should be spawned from the emitter
|
||||
Container<str> m_taglist; // A list of tags to create beams
|
||||
|
||||
cg_common_data cgd;
|
||||
int entnum;
|
||||
|
||||
Vector origin_offset_base;
|
||||
Vector origin_offset_amplitude;
|
||||
Vector axis_offset_base;
|
||||
Vector axis_offset_amplitude;
|
||||
Vector randvel_base;
|
||||
Vector randvel_amplitude;
|
||||
Vector avelocity_base;
|
||||
Vector avelocity_amplitude;
|
||||
Vector angles_amplitude;
|
||||
vec3_t axis[3];
|
||||
vec3_t tag_axis[3];
|
||||
float life_random;
|
||||
float forwardVelocity;
|
||||
float sphereRadius;
|
||||
float coneHeight;
|
||||
float spawnRate;
|
||||
int lastTime;
|
||||
int count;
|
||||
int tagnum;
|
||||
str emittername;
|
||||
str animName;
|
||||
float dcolor[3];
|
||||
qboolean dlight;
|
||||
int numtempmodels;
|
||||
float linked_origin[3];
|
||||
float linked_axis[3][3];
|
||||
float fMinRangeSquared;
|
||||
float fMaxRangeSquared;
|
||||
|
||||
// beam stuff also impact trace stuff
|
||||
str startTag;
|
||||
str endTag;
|
||||
float length;
|
||||
float min_offset;
|
||||
float max_offset;
|
||||
float overlap;
|
||||
float numSubdivisions;
|
||||
float delay;
|
||||
float toggledelay;
|
||||
int beamflags;
|
||||
int numspherebeams;
|
||||
float endalpha;
|
||||
float spreadx;
|
||||
float spready;
|
||||
qboolean use_last_trace_end;
|
||||
|
||||
void (*touchfcn)(ctempmodel_t* ct, trace_t* trace);
|
||||
str GetModel(void);
|
||||
void SetModel(str model);
|
||||
};
|
||||
|
||||
inline void spawnthing_t::SetModel(str model)
|
||||
|
||||
{
|
||||
m_modellist.ClearObjectList();
|
||||
m_modellist.AddObject(model);
|
||||
}
|
||||
|
||||
inline str spawnthing_t::GetModel(void)
|
||||
|
||||
{
|
||||
int num, index;
|
||||
|
||||
num = m_modellist.NumObjects();
|
||||
|
||||
if (!num) {
|
||||
return "";
|
||||
}
|
||||
|
||||
index = (num * random()) + 1;
|
||||
|
||||
if (index > num) {
|
||||
index = num;
|
||||
}
|
||||
|
||||
return m_modellist.ObjectAt(index);
|
||||
}
|
||||
|
||||
// Keeps track of beams that are created by entities that need their positions
|
||||
// updated every frame
|
||||
class beamthing_t : public emitterthing_t
|
||||
{
|
||||
public:
|
||||
str beamname;
|
||||
str shadername;
|
||||
str startTag;
|
||||
str endTag;
|
||||
int numSubdivisions;
|
||||
dtiki_t *tiki;
|
||||
float alpha;
|
||||
float scale;
|
||||
int flags;
|
||||
float length;
|
||||
int life;
|
||||
float min_offset;
|
||||
float max_offset;
|
||||
float overlap;
|
||||
int delay;
|
||||
byte modulate[4];
|
||||
};
|
||||
|
||||
#define MAX_TEMPMODELS 1024
|
||||
#define MAX_BEAMS 4096
|
||||
|
||||
class ClientGameCommandManager : public Listener
|
||||
{
|
||||
private:
|
||||
spawnthing_t m_localemitter; // local emitter used by animation commands
|
||||
ctempmodel_t m_active_tempmodels;
|
||||
ctempmodel_t* m_free_tempmodels;
|
||||
ctempmodel_t m_tempmodels[MAX_TEMPMODELS];
|
||||
cvssource_t m_active_vsssources;
|
||||
cvssource_t* m_free_vsssources;
|
||||
cvssource_t* m_vsssources;
|
||||
int m_iAllocatedvsssources;
|
||||
spawnthing_t* m_spawnthing;
|
||||
Container<spawnthing_t*> m_emitters; // Global emitters set up by client commands
|
||||
int m_seed;
|
||||
commandthing_t m_command_time_manager; // Keeps track of entity numbers and the last
|
||||
// time they executed particular commands
|
||||
specialeffect_t* m_pCurrentSfx;
|
||||
int m_iLastVSSRepulsionTime;
|
||||
float m_fEventWait;
|
||||
|
||||
void (ClientGameCommandManager::*endblockfcn)(void);
|
||||
cvssource_t* AllocateVSSSource();
|
||||
void FreeVSSSource(cvssource_t *p);
|
||||
void SpawnVSSSource(int count, int timealive);
|
||||
void EventViewKick(Event* ev);
|
||||
void Print(Event* ev);
|
||||
void StartBlock(Event* ev);
|
||||
void EndBlock(Event* ev);
|
||||
void UpdateSpawnThing(spawnthing_t* ep);
|
||||
void EmitterStartOff(Event* ev);
|
||||
void SetAlpha(Event* ev);
|
||||
void SetDieTouch(Event* ev);
|
||||
void SetBounceFactor(Event* ev);
|
||||
void SetBounceSound(Event* ev);
|
||||
void SetBounceSoundOnce(Event* ev);
|
||||
void SetModel(Event* ev);
|
||||
void SetLife(Event* ev);
|
||||
void SetColor(Event* ev);
|
||||
void SetColorRange(Event* ev);
|
||||
void SetLightstyle(Event* ev);
|
||||
void SetRadialVelocity(Event* ev);
|
||||
void SetVelocity(Event* ev);
|
||||
void SetAngularVelocity(Event* ev);
|
||||
void SetCount(Event* ev);
|
||||
void SetScale(Event* ev);
|
||||
void SetScaleUpDown(Event* ev);
|
||||
void SetScaleMin(Event* ev);
|
||||
void SetScaleMax(Event* ev);
|
||||
void SetScaleRate(Event* ev);
|
||||
void SetRandomVelocity(Event* ev);
|
||||
void SetRandomVelocityAlongAxis(Event* ev);
|
||||
void SetAccel(Event* ev);
|
||||
void SetFriction(Event* ev);
|
||||
void SetVaryColor(Event* ev);
|
||||
void SetFade(Event* ev);
|
||||
void SetFadeDelay(Event* ev);
|
||||
void SetSpawnRange(Event* ev);
|
||||
void SetSpawnRate(Event* ev);
|
||||
void SetOriginOffset(Event* ev);
|
||||
void SetOffsetAlongAxis(Event* ev);
|
||||
void SetCone(Event* ev);
|
||||
void SetCircle(Event* ev);
|
||||
void SetSphere(Event* ev);
|
||||
void SetInwardSphere(Event* ev);
|
||||
void SetRandomRoll(Event* ev);
|
||||
void SetVolumetric(Event* ev);
|
||||
void SetSwarm(Event* ev);
|
||||
void SetAlign(Event* ev);
|
||||
void SetAlignOnce(Event* ev);
|
||||
void SetCollision(Event* ev);
|
||||
void SetFlickerAlpha(Event* ev);
|
||||
void SetFadeIn(Event* ev);
|
||||
void SetEntityColor(Event* ev);
|
||||
void SetGlobalFade(Event* ev);
|
||||
void SetRadius(Event* ev);
|
||||
void SetParentLink(Event* ev);
|
||||
void SetHardLink(Event* ev);
|
||||
void SetAngles(Event* ev);
|
||||
void ParentAngles(Event* ev);
|
||||
void EmitterAngles(Event* ev);
|
||||
void SetTwinkle(Event* ev);
|
||||
void SetTrail(Event* ev);
|
||||
void SetPhysicsRate(Event* ev);
|
||||
void SetBounceDecal(Event* ev);
|
||||
void UpdateSwarm(ctempmodel_t* p);
|
||||
void BeginOriginSpawn(Event* ev);
|
||||
void EndOriginSpawn(void);
|
||||
void BeginOriginBeamSpawn(Event* ev);
|
||||
void EndOriginBeamSpawn(void);
|
||||
void BeginOriginBeamEmitter(Event* ev);
|
||||
void EndOriginBeamEmitter(void);
|
||||
void BeginTagSpawn(Event* ev);
|
||||
void BeginTagSpawnLinked(Event* ev);
|
||||
void EndTagSpawn(void);
|
||||
void BeginTagBeamSpawn(Event* ev);
|
||||
void EndTagBeamSpawn(void);
|
||||
void BeginTagEmitter(Event* ev);
|
||||
void EndTagEmitter(void);
|
||||
void BeginOriginEmitter(Event* ev);
|
||||
void EndOriginEmitter(void);
|
||||
void BeginTagBeamEmitter(Event* ev);
|
||||
void EndTagBeamEmitter(void);
|
||||
void EmitterOn(Event* ev);
|
||||
void EmitterOff(Event* ev);
|
||||
void RainTouch(Event* ev);
|
||||
void Sound(Event* ev);
|
||||
void SetCurrentTiki(Event* ev);
|
||||
void StopSound(Event* ev);
|
||||
void StopAliasChannel(Event* ev);
|
||||
void LoopSound(Event* ev);
|
||||
void Cache(Event* ev);
|
||||
void CacheImage(Event* ev);
|
||||
void CacheFont(Event* ev);
|
||||
void AliasCache(Event* ev);
|
||||
void Alias(Event* ev);
|
||||
void CacheAlias(Event* ev);
|
||||
void Client(Event* ev);
|
||||
void TagDynamicLight(Event* ev);
|
||||
void OriginDynamicLight(Event* ev);
|
||||
void DynamicLight(Event* ev);
|
||||
void BlockDynamicLight(Event* ev);
|
||||
void EndBlockDynamicLight();
|
||||
void GetOrientation(int tagnum, spawnthing_t* sp);
|
||||
void Swipe(Event* ev);
|
||||
void SwipeOn(Event* ev);
|
||||
void SwipeOff(Event* ev);
|
||||
void AnimateOnce(Event* ev);
|
||||
void SetAnim(Event* ev);
|
||||
void SetDecalRadius(Event* ev);
|
||||
void SetDecalOrientation(Event* ev);
|
||||
void TagList(Event* ev);
|
||||
void SetParallel(Event* ev);
|
||||
void Footstep(Event* ev);
|
||||
void LandingSound(Event* ev);
|
||||
void BodyFallSound(Event* ev);
|
||||
void SetAlwaysDraw(Event* ev);
|
||||
void SetDetail(Event* ev);
|
||||
void SetWindAffect(Event* ev);
|
||||
void SpriteGridLighting(Event* ev);
|
||||
void SetWaterOnly(Event* ev);
|
||||
void SetAlignStretch(Event* ev);
|
||||
void SetClampVel(Event* ev);
|
||||
void SetClampVelAxis(Event* ev);
|
||||
ctempmodel_t* AllocateTempModel(void);
|
||||
qboolean TempModelPhysics(ctempmodel_t* p, float ftime, float time2,
|
||||
float scale);
|
||||
qboolean TempModelRealtimeEffects(ctempmodel_t* p, float ftime, float time2,
|
||||
float scale);
|
||||
qboolean LerpTempModel(refEntity_t* newEnt, ctempmodel_t* p, float frac);
|
||||
void SpawnEffect(int count, int timealive);
|
||||
void SpawnTempModel(int count, int timealive = 0);
|
||||
void FreeTempModel(ctempmodel_t* le);
|
||||
void AnimateTempModel(ctempmodel_t* ent, Vector origin,
|
||||
refEntity_t* newEnt);
|
||||
void OtherTempModelEffects(ctempmodel_t* p, Vector origin,
|
||||
refEntity_t* newEnt);
|
||||
qboolean IsBlockCommand(const str& name);
|
||||
void SetBaseAndAmplitude(Event* ev, Vector& base, Vector& amplitude);
|
||||
|
||||
// Beam stuff
|
||||
void SetSubdivisions(Event* ev);
|
||||
void SetMinOffset(Event* ev);
|
||||
void SetMaxOffset(Event* ev);
|
||||
void SetShader(Event* ev);
|
||||
void SetLength(Event* ev);
|
||||
void SetBeamDelay(Event* ev);
|
||||
void SetBeamToggleDelay(Event* ev);
|
||||
void SetBeamPersist(Event* ev);
|
||||
void SetBeamOffsetEndpoints(Event* ev);
|
||||
void SetBeamSphere(Event* ev);
|
||||
void SetSpread(Event* ev);
|
||||
void SetUseLastTraceEnd(Event* ev);
|
||||
void SetEndAlpha(Event* ev);
|
||||
void SetEyeLimits(Event* ev);
|
||||
void SetEyeMovement(Event* ev);
|
||||
void StartSFX(Event* ev);
|
||||
void StartSFXDelayed(Event* ev);
|
||||
void StartSFXCommand(Event* ev, qboolean bDelayed);
|
||||
void EndIgnoreSfxBlock();
|
||||
void RandomChance(Event* ev);
|
||||
void DelayedRepeat(Event* ev);
|
||||
void CommandDelay(Event* ev);
|
||||
void SpawnTreads(Event* ev);
|
||||
void TreadsOff(Event* ev);
|
||||
bool GetTagPositionAndOrientation(int tagnum, orientation_t* new_or);
|
||||
bool GetTagPositionAndOrientation(str tagname, orientation_t* new_or);
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE(ClientGameCommandManager);
|
||||
|
||||
ClientGameCommandManager();
|
||||
void AddTempModels(void);
|
||||
void UpdateEmitter(dtiki_t* tiki, vec3_t axis[3], int entity_number,
|
||||
int parent_number, Vector entity_origin);
|
||||
void UpdateBeam(dtiki_t *tiki, int entity_number, spawnthing_t* beamthing);
|
||||
void PlaySound(str sound_name, vec3_t origin = NULL,
|
||||
int channel = CHAN_AUTO, float volume = -1,
|
||||
float min_distance = -1, float pitch = -1, int argstype = 0);
|
||||
|
||||
spawnthing_t* InitializeSpawnthing(spawnthing_t* ep);
|
||||
void SpawnEffect(int count, spawnthing_t* sp);
|
||||
void FreeAllTempModels(void);
|
||||
void RestartAllEmitters(void);
|
||||
|
||||
void InitializeTempModels(void);
|
||||
void InitializeTempModelCvars(void);
|
||||
void InitializeEmitters(void);
|
||||
void RemoveClientEntity(int number, dtiki_t* tiki, centity_t* cent,
|
||||
ctempmodel_t* p = NULL);
|
||||
void ClearSwipes(void);
|
||||
void ResetTempModels(void);
|
||||
void SpawnTempModel(int count, spawnthing_t* sp);
|
||||
inline void SetSpawnthing(spawnthing_t* st) { m_spawnthing = st; };
|
||||
spawnthing_t* CreateNewEmitter(str emittername);
|
||||
spawnthing_t* CreateNewEmitter(void);
|
||||
spawnthing_t* GetEmitterByName(str emittername);
|
||||
void DeleteEmitters(dtiki_t* tiki);
|
||||
void CGEvent(centity_t* cent);
|
||||
|
||||
void ProcessPendingEventsForEntity();
|
||||
qboolean PostEventForEntity(Event *ev, float fWait);
|
||||
qboolean SelectProcessEvent(Event *ev);
|
||||
|
||||
void TestEffectEndFunc();
|
||||
void AddVSSSources();
|
||||
void InitializeVSSCvars();
|
||||
void InitializeVSSSources();
|
||||
void ResetVSSSources();
|
||||
void ResetVSSSources(Event* ev);
|
||||
void SetCurrentSFX(specialeffect_t* pSFX);
|
||||
void ClearCurrentSFX();
|
||||
void AddTreadMarkSources();
|
||||
void InitializeTreadMarkCvars();
|
||||
void InitializeTreadMarkSources();
|
||||
void ResetTreadMarkSources();
|
||||
void ResetTreadMarkSources(Event* ev);
|
||||
void InitializeRainCvars();
|
||||
void InitializeBeams();
|
||||
};
|
||||
|
||||
class EmitterLoader : public Listener
|
||||
{
|
||||
private:
|
||||
bool emitterActive;
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE(EmitterLoader);
|
||||
|
||||
EmitterLoader();
|
||||
bool Load(Script&);
|
||||
void ProcessEmitter(Script&);
|
||||
void Emitter(Event* ev);
|
||||
};
|
||||
|
||||
class EffectsEventQueueNode {
|
||||
public:
|
||||
Event* event;
|
||||
int inttime;
|
||||
int flags;
|
||||
int entity_num;
|
||||
|
||||
EffectsEventQueueNode* prev;
|
||||
EffectsEventQueueNode* next;
|
||||
|
||||
#ifdef _DEBUG
|
||||
str name;
|
||||
#endif
|
||||
|
||||
EffectsEventQueueNode() { prev = this; next = this; }
|
||||
EffectsEventQueueNode(Event* event, int inttime, int flags, int entity_num)
|
||||
{
|
||||
this->event = event;
|
||||
this->inttime = inttime;
|
||||
this->flags = flags;
|
||||
this->entity_num = entity_num;
|
||||
}
|
||||
|
||||
int GetEntityNum() { return entity_num; }
|
||||
};
|
||||
|
||||
extern ClientGameCommandManager commandManager;
|
||||
+469
-233
@@ -1,45 +1,32 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
//
|
||||
// cg_consolecmds.c -- text commands typed in at the local console, or
|
||||
// executed by a key binding
|
||||
// DESCRIPTION:
|
||||
// text commands typed in at the local console, or executed by a key binding
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
|
||||
void CG_TargetCommand_f( void ) {
|
||||
int targetNum;
|
||||
char *test;
|
||||
|
||||
targetNum = CG_CrosshairPlayer();
|
||||
if (!targetNum ) {
|
||||
return;
|
||||
}
|
||||
|
||||
test = cgi.Argv( 1 );
|
||||
cgi.SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
|
||||
}
|
||||
|
||||
|
||||
void CG_TargetCommand_f(void);
|
||||
|
||||
/*
|
||||
=================
|
||||
@@ -48,11 +35,11 @@ CG_SizeUp_f
|
||||
Keybinding command
|
||||
=================
|
||||
*/
|
||||
static void CG_SizeUp_f (void) {
|
||||
cgi.Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize->integer+10)));
|
||||
static void CG_SizeUp_f(void)
|
||||
{
|
||||
cgi.Cvar_Set("viewsize", va("%i", (int)(cg_viewsize->integer + 10)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_SizeDown_f
|
||||
@@ -60,11 +47,11 @@ CG_SizeDown_f
|
||||
Keybinding command
|
||||
=================
|
||||
*/
|
||||
static void CG_SizeDown_f (void) {
|
||||
cgi.Cvar_Set("cg_viewsize", va("%i",(int)(cg_viewsize->integer-10)));
|
||||
static void CG_SizeDown_f(void)
|
||||
{
|
||||
cgi.Cvar_Set("viewsize", va("%i", (int)(cg_viewsize->integer - 10)));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
CG_Viewpos_f
|
||||
@@ -72,189 +59,352 @@ CG_Viewpos_f
|
||||
Debugging command to print the current position
|
||||
=============
|
||||
*/
|
||||
static void CG_Viewpos_f (void) {
|
||||
CG_Printf ("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
|
||||
(int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
|
||||
(int)cg.refdefViewAngles[YAW]);
|
||||
static void CG_Viewpos_f(void)
|
||||
{
|
||||
cgi.Printf("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
|
||||
(int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
|
||||
(int)cg.refdefViewAngles[YAW]);
|
||||
}
|
||||
|
||||
void CG_SetDesiredObjectiveAlpha(float fAlpha)
|
||||
{
|
||||
cg.ObjectivesDesiredAlpha = fAlpha;
|
||||
cg.ObjectivesAlphaTime = (float)(cg.time + 250);
|
||||
cg.ObjectivesBaseAlpha = cg.ObjectivesCurrentAlpha;
|
||||
}
|
||||
|
||||
static void CG_ScoresDown_f( void ) {
|
||||
void CG_ScoresDown_f( void )
|
||||
{
|
||||
if (cgs.gametype == GT_SINGLE_PLAYER)
|
||||
{
|
||||
if (!cg.scoresRequestTime) {
|
||||
cg.scoresRequestTime = cg.time;
|
||||
CG_SetDesiredObjectiveAlpha(1.0f);
|
||||
}
|
||||
|
||||
if ( cg.scoresRequestTime + 1000 < cg.time ) {
|
||||
// the scores are more than two seconds out of data,
|
||||
// so request new ones
|
||||
cg.scoresRequestTime = cg.time;
|
||||
cgi.SendClientCommand( "score" );
|
||||
return;
|
||||
}
|
||||
|
||||
// leave the current scores up if they were already
|
||||
// displayed, but if this is the first hit, clear them out
|
||||
if ( !cg.showScores ) {
|
||||
cg.showScores = qtrue;
|
||||
cg.numScores = 0;
|
||||
}
|
||||
} else {
|
||||
// show the cached contents even if they just pressed if it
|
||||
// is within two seconds
|
||||
if ( cg.scoresRequestTime + 2000 >= cg.time )
|
||||
{
|
||||
// send another request
|
||||
cg.showScores = qtrue;
|
||||
CG_PrepScoreBoardInfo();
|
||||
cgi.UI_ShowScoreBoard(cg.scoresMenuName);
|
||||
return;
|
||||
}
|
||||
|
||||
cg.scoresRequestTime = cg.time;
|
||||
cgi.SendClientCommand( "score" );
|
||||
|
||||
if ( !cg.showScores ) {
|
||||
// don't display anything until first score returns
|
||||
cg.showScores = qtrue;
|
||||
CG_PrepScoreBoardInfo();
|
||||
cgi.UI_ShowScoreBoard(cg.scoresMenuName);
|
||||
}
|
||||
cg.scoreBoardShowing = qtrue;
|
||||
cgi.Cvar_Set( "ui_showscores", "1" );
|
||||
}
|
||||
|
||||
static void CG_ScoresUp_f( void ) {
|
||||
if ( cg.showScores ) {
|
||||
cg.showScores = qfalse;
|
||||
cg.scoreFadeTime = cg.time;
|
||||
}
|
||||
cg.scoreBoardShowing = qfalse;
|
||||
cgi.Cvar_Set( "ui_showscores", "0" );
|
||||
void CG_ScoresUp_f( void )
|
||||
{
|
||||
if (cgs.gametype == GT_SINGLE_PLAYER)
|
||||
{
|
||||
if (!cg.scoresRequestTime)
|
||||
{
|
||||
cg.scoresRequestTime = cg.time;
|
||||
CG_SetDesiredObjectiveAlpha(0.0f);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cg.showScores) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.showScores = qfalse;
|
||||
cgi.UI_HideScoreBoard(cg.scoresMenuName);
|
||||
}
|
||||
|
||||
static void CG_TellTarget_f( void ) {
|
||||
int clientNum;
|
||||
char command[128];
|
||||
char *message;
|
||||
baseshader_t* CG_GetShaderUnderCrosshair(qboolean bVerbose, trace_t* pRetTrace)
|
||||
{
|
||||
vec3_t vPos, vEnd;
|
||||
vec3_t axis[3];
|
||||
baseshader_t* pShader;
|
||||
trace_t trace;
|
||||
|
||||
clientNum = CG_CrosshairPlayer();
|
||||
if ( clientNum == -1 ) {
|
||||
return;
|
||||
}
|
||||
AnglesToAxis(cg.refdefViewAngles, axis);
|
||||
vPos[0] = cg.refdef.vieworg[0];
|
||||
vPos[1] = cg.refdef.vieworg[1];
|
||||
vPos[2] = cg.refdef.vieworg[2];
|
||||
VectorMA(vPos, 4096.0, axis[0], vEnd);
|
||||
|
||||
message = cgi.Args();
|
||||
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
|
||||
cgi.SendClientCommand( command );
|
||||
CG_Trace(&trace, vPos, vec3_origin, vec3_origin, vEnd, 0, MASK_SHOT, 0, 0, "CG_GetShaderUnderCrosshair");
|
||||
|
||||
if (trace.startsolid || trace.fraction == 1.0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bVerbose)
|
||||
{
|
||||
cgi.Printf(
|
||||
"Surface hit at (%i %i %i)\n",
|
||||
(int)trace.endpos[0],
|
||||
(int)trace.endpos[1],
|
||||
(int)trace.endpos[2]);
|
||||
}
|
||||
|
||||
pShader = cgi.GetShader(trace.shaderNum);
|
||||
if (pRetTrace) {
|
||||
*pRetTrace = trace;
|
||||
}
|
||||
|
||||
return pShader;
|
||||
}
|
||||
|
||||
static void CG_TellAttacker_f( void ) {
|
||||
int clientNum;
|
||||
char command[128];
|
||||
char *message;
|
||||
|
||||
clientNum = CG_LastAttacker();
|
||||
if ( clientNum == -1 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
message = cgi.Args();
|
||||
Com_sprintf( command, 128, "tell %i %s", clientNum, message );
|
||||
cgi.SendClientCommand( command );
|
||||
static void CG_PrintContentTypes(int iContentFlags)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
static void CG_PrintSurfaceProperties(int iSurfaceFlags)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
static void CG_PrintSurfaceType(int iSurfType)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_GetCHShader(void)
|
||||
{
|
||||
trace_t trace;
|
||||
baseshader_t* pShader;
|
||||
|
||||
pShader = CG_GetShaderUnderCrosshair(qtrue, &trace);
|
||||
cgi.Printf("\n");
|
||||
if (pShader)
|
||||
{
|
||||
if (pShader->surfaceFlags & SURF_SKY)
|
||||
{
|
||||
cgi.Printf("Hit the sky\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.Printf("Shader: %s\n", pShader->shader);
|
||||
cgi.Printf("Shader Contents:");
|
||||
CG_PrintContentTypes(pShader->contentFlags);
|
||||
cgi.Printf("\n");
|
||||
cgi.Printf("Shader Surface Properties:");
|
||||
CG_PrintSurfaceProperties(pShader->surfaceFlags);
|
||||
cgi.Printf("\n");
|
||||
cgi.Printf("Shader Surfacetype: ");
|
||||
CG_PrintSurfaceType(pShader->surfaceFlags);
|
||||
cgi.Printf("\n");
|
||||
cgi.Printf("Trace Contents:");
|
||||
CG_PrintContentTypes(trace.contents);
|
||||
cgi.Printf("\n");
|
||||
cgi.Printf("Trace Surface Properties:");
|
||||
CG_PrintSurfaceProperties(trace.surfaceFlags);
|
||||
cgi.Printf("\n");
|
||||
cgi.Printf("Trace Surfacetype: ");
|
||||
CG_PrintSurfaceType(trace.surfaceFlags);
|
||||
cgi.Printf("\n\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.Printf("No surface selected\n");
|
||||
}
|
||||
}
|
||||
|
||||
void CG_EditCHShader(void)
|
||||
{
|
||||
char name[1024];
|
||||
baseshader_t* pShader;
|
||||
|
||||
pShader = CG_GetShaderUnderCrosshair(qfalse, NULL);
|
||||
if (pShader)
|
||||
{
|
||||
strcpy(name, "editspecificshader ");
|
||||
strcat(name, pShader->shader);
|
||||
strcat(name, "\n");
|
||||
cgi.AddCommand(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.Printf("No surface selected\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_StartOrbit_f
|
||||
==================
|
||||
=============================================================================
|
||||
|
||||
MODEL TESTING
|
||||
|
||||
The viewthing and gun positioning tools from Q2 have been integrated and
|
||||
enhanced into a single model testing facility.
|
||||
|
||||
Model viewing can begin with either "testmodel <modelname>" or "testgun <modelname>".
|
||||
|
||||
The names must be the full pathname after the basedir, like
|
||||
"models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
|
||||
|
||||
Testmodel will create a fake entity 100 units in front of the current view
|
||||
position, directly facing the viewer. It will remain immobile, so you can
|
||||
move around it to view it from different angles.
|
||||
|
||||
Testgun will cause the model to follow the player around and supress the real
|
||||
view weapon model. The default frame 0 of most guns is completely off screen,
|
||||
so you will probably have to cycle a couple frames to see it.
|
||||
|
||||
"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the
|
||||
frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in
|
||||
q3default.cfg.
|
||||
|
||||
Note that none of the model testing features update while the game is paused, so
|
||||
it may be convenient to test with deathmatch set to 1 so that bringing down the
|
||||
console doesn't pause the game.
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
static void CG_StartOrbit_f( void ) {
|
||||
char var[MAX_TOKEN_CHARS];
|
||||
/*
|
||||
=================
|
||||
CG_TestModel_f
|
||||
|
||||
cgi.Cvar_VariableStringBuffer( "developer", var, sizeof( var ) );
|
||||
if ( !atoi(var) ) {
|
||||
return;
|
||||
}
|
||||
if (cg_cameraOrbit->value != 0) {
|
||||
cgi.Cvar_Set ("cg_cameraOrbit", "0");
|
||||
cgi.Cvar_Set("cg_thirdPerson", "0");
|
||||
} else {
|
||||
cgi.Cvar_Set("cg_cameraOrbit", "5");
|
||||
cgi.Cvar_Set("cg_thirdPerson", "1");
|
||||
cgi.Cvar_Set("cg_thirdPersonAngle", "0");
|
||||
cgi.Cvar_Set("cg_thirdPersonRange", "100");
|
||||
}
|
||||
}
|
||||
Creates an entity in front of the current position, which
|
||||
can then be moved around
|
||||
=================
|
||||
*/
|
||||
void CG_TestModel_f (void) {
|
||||
vec3_t angles;
|
||||
|
||||
static void CG_LocationPrint_f(void) {
|
||||
char *buffer;
|
||||
int x,y;
|
||||
|
||||
buffer = cgi.Argv( 1 );
|
||||
x = atoi(buffer);
|
||||
buffer = cgi.Argv( 2 );
|
||||
y = atoi(buffer);
|
||||
buffer = cgi.Argv( 3 );
|
||||
buffer[511] = 0;
|
||||
CG_LocationPrint( buffer, x, y, SMALLCHAR_WIDTH );
|
||||
}
|
||||
|
||||
// su44: in MoHAA, "useweaponclass pistol/rifle/etc"
|
||||
// commands are usually bound to 1,2,3,4,5,6 keys
|
||||
static void CG_UseWeaponClass_f(void) {
|
||||
const char *name;
|
||||
|
||||
if(cgi.Argc() < 2) {
|
||||
CG_Printf("usage: useweaponclass <weaponclassname>\n");
|
||||
memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) );
|
||||
if ( cgi.Argc() < 2 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get weapon classname
|
||||
name = CG_Argv(1);
|
||||
if(!Q_stricmp(name,"pistol")) {
|
||||
cg.iWeaponCommand = 1;
|
||||
} else if(!Q_stricmp(name,"rifle")) {
|
||||
cg.iWeaponCommand = 2;
|
||||
} else if(!Q_stricmp(name,"smg")) {
|
||||
cg.iWeaponCommand = 3;
|
||||
} else if(!Q_stricmp(name,"mg")) {
|
||||
cg.iWeaponCommand = 4;
|
||||
} else if(!Q_stricmp(name,"grenade")) {
|
||||
cg.iWeaponCommand = 5;
|
||||
} else if(!Q_stricmp(name,"heavy")) {
|
||||
cg.iWeaponCommand = 6;
|
||||
} else if(!Q_stricmp(name,"item2")) {
|
||||
cg.iWeaponCommand = 8; // su44: AFAIK it's not used at all in MoHAA
|
||||
} else if(!Q_stricmp(name,"item3")) {
|
||||
cg.iWeaponCommand = 9; // su44: AFAIK it's not used at all in MoHAA
|
||||
} else if(!Q_stricmp(name,"item4")) {
|
||||
cg.iWeaponCommand = 10; // su44: AFAIK it's not used at all in MoHAA
|
||||
} else if(!Q_stricmp(name,"item") || !Q_stricmp(name,"item1")) {
|
||||
cg.iWeaponCommand = 7; // su44: I think it's used for "Papers" item
|
||||
} else {
|
||||
CG_Printf("useweaponclass: unknown weapon %s\n", name);
|
||||
Q_strncpyz (cg.testModelName, cgi.Argv( 1 ), MAX_QPATH );
|
||||
cg.testModelEntity.hModel = cgi.R_RegisterModel( cg.testModelName );
|
||||
|
||||
if ( cgi.Argc() == 3 ) {
|
||||
cg.testModelEntity.backlerp = atof( cgi.Argv( 2 ) );
|
||||
cg.testModelEntity.frame = 1;
|
||||
cg.testModelEntity.oldframe = 0;
|
||||
}
|
||||
cg.iWeaponCommandSend = 0;
|
||||
if (! cg.testModelEntity.hModel ) {
|
||||
cgi.Printf( "Can't register model\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin );
|
||||
|
||||
angles[PITCH] = 0;
|
||||
angles[YAW] = 180 + cg.refdefViewAngles[1];
|
||||
angles[ROLL] = 0;
|
||||
|
||||
AnglesToAxis( angles, cg.testModelEntity.axis );
|
||||
cg.testGun = qfalse;
|
||||
}
|
||||
|
||||
void CG_TestModelNextFrame_f (void) {
|
||||
cg.testModelEntity.frame++;
|
||||
cgi.Printf( "frame %i\n", cg.testModelEntity.frame );
|
||||
}
|
||||
|
||||
void CG_TestModelPrevFrame_f (void) {
|
||||
cg.testModelEntity.frame--;
|
||||
cgi.Printf( "frame %i\n", cg.testModelEntity.frame );
|
||||
}
|
||||
|
||||
void CG_TestModelNextSkin_f (void) {
|
||||
cg.testModelEntity.skinNum++;
|
||||
cgi.Printf( "skin %i\n", cg.testModelEntity.skinNum );
|
||||
}
|
||||
|
||||
void CG_TestModelPrevSkin_f (void) {
|
||||
cg.testModelEntity.skinNum--;
|
||||
if ( cg.testModelEntity.skinNum < 0 ) {
|
||||
cg.testModelEntity.skinNum = 0;
|
||||
}
|
||||
cgi.Printf( "skin %i\n", cg.testModelEntity.skinNum );
|
||||
}
|
||||
|
||||
void CG_AddTestModel (void) {
|
||||
// re-register the model, because the level may have changed
|
||||
cg.testModelEntity.hModel = cgi.R_RegisterModel( cg.testModelName );
|
||||
if (! cg.testModelEntity.hModel ) {
|
||||
cgi.Printf ("Can't register model\n");
|
||||
return;
|
||||
}
|
||||
cgi.R_AddRefEntityToScene( &cg.testModelEntity );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
void (*function)(void);
|
||||
char* cmd;
|
||||
void (*function)(void);
|
||||
} consoleCommand_t;
|
||||
|
||||
static consoleCommand_t commands[] = {
|
||||
{ "testgun", CG_TestGun_f },
|
||||
{ "testmodel", CG_TestModel_f },
|
||||
{ "testmodelanim", CG_TestModelAnim_f },
|
||||
{ "testmodelanimspeedscale", CG_TestModelAnimSpeedScale_f },
|
||||
{ "nextframe", CG_TestModelNextFrame_f },
|
||||
{ "prevframe", CG_TestModelPrevFrame_f },
|
||||
{ "nextskin", CG_TestModelNextSkin_f },
|
||||
{ "prevskin", CG_TestModelPrevSkin_f },
|
||||
{ "viewpos", CG_Viewpos_f },
|
||||
{ "+scores", CG_ScoresDown_f },
|
||||
{ "-scores", CG_ScoresUp_f },
|
||||
{ "+zoom", CG_ZoomDown_f },
|
||||
{ "-zoom", CG_ZoomUp_f },
|
||||
{ "sizeup", CG_SizeUp_f },
|
||||
{ "sizedown", CG_SizeDown_f },
|
||||
{ "weapnext", CG_NextWeapon_f },
|
||||
{ "weapprev", CG_PrevWeapon_f },
|
||||
{ "tell_target", CG_TellTarget_f },
|
||||
{ "tell_attacker", CG_TellAttacker_f },
|
||||
{ "tcmd", CG_TargetCommand_f },
|
||||
{ "startOrbit", CG_StartOrbit_f },
|
||||
//{ "camera", CG_Camera_f },
|
||||
{ "locationprint", CG_LocationPrint_f },
|
||||
// su44: MoHAA commands
|
||||
{ "toggleitem", CG_ToggleItem_f },
|
||||
{ "weapdrop", CG_DropWeapon_f },
|
||||
{ "holster", CG_HolsterWeapon_f },
|
||||
{ "weapnext", CG_NextWeapon_f },
|
||||
{ "weapprev", CG_PrevWeapon_f },
|
||||
{ "useweaponclass", CG_UseWeaponClass_f },
|
||||
static consoleCommand_t commands[] = {
|
||||
{ "useweaponclass", &CG_UseWeaponClass_f },
|
||||
{ "weapnext", &CG_NextWeapon_f },
|
||||
{ "weapprev", &CG_PrevWeapon_f },
|
||||
{ "uselast", &CG_UseLastWeapon_f },
|
||||
{ "holster", &CG_HolsterWeapon_f },
|
||||
{ "weapdrop", &CG_DropWeapon_f },
|
||||
{ "toggleitem", &CG_ToggleItem_f },
|
||||
{ "+scores", &CG_ScoresDown_f },
|
||||
{ "-scores", &CG_ScoresUp_f },
|
||||
{ "viewpos", &CG_Viewpos_f },
|
||||
{ "sizeup", &CG_SizeUp_f },
|
||||
{ "sizedown", &CG_SizeDown_f },
|
||||
{ "cg_eventlist", &CG_EventList_f },
|
||||
{ "cg_eventhelp", &CG_EventHelp_f },
|
||||
{ "cg_dumpevents", &CG_DumpEventHelp_f },
|
||||
{ "cg_pendingevents", &CG_PendingEvents_f },
|
||||
{ "cg_classlist", &CG_ClassList_f },
|
||||
{ "cg_classtree", &CG_ClassTree_f },
|
||||
{ "cg_classevents", &CG_ClassEvents_f },
|
||||
{ "cg_dumpclassevents", &CG_DumpClassEvents_f },
|
||||
{ "cg_dumpallclasses", &CG_DumpAllClasses_f },
|
||||
{ "testemitter", &CG_TestEmitter_f },
|
||||
{ "triggertestemitter", &CG_TriggerTestEmitter_f },
|
||||
{ "prevemittercommand", &CG_PrevEmitterCommand_f },
|
||||
{ "nextemittercommand", &CG_NextEmitterCommand_f },
|
||||
{ "newemittercommand", &CG_NewEmitterCommand_f },
|
||||
{ "deleteemittercommand", &CG_DeleteEmitterCommand_f },
|
||||
{ "dumpemitter", &CG_DumpEmitter_f },
|
||||
{ "loademitter", &CG_LoadEmitter_f },
|
||||
{ "resetvss", &CG_ResetVSSSources },
|
||||
{ "getchshader", &CG_GetCHShader },
|
||||
{ "editchshader", &CG_EditCHShader },
|
||||
{ "messagemode", &CG_MessageMode_f },
|
||||
{ "messagemode_all", &CG_MessageMode_All_f },
|
||||
{ "messagemode_team", &CG_MessageMode_Team_f },
|
||||
{ "messagemode_private", &CG_MessageMode_Private_f },
|
||||
{ "say", &CG_MessageSingleAll_f },
|
||||
{ "sayteam", &CG_MessageSingleTeam_f },
|
||||
{ "teamsay", &CG_MessageSingleTeam_f },
|
||||
{ "sayprivate", &CG_MessageSingleClient_f },
|
||||
{ "sayone", &CG_MessageSingleClient_f },
|
||||
{ "wisper", &CG_MessageSingleClient_f },
|
||||
{ "instamsg_main", &CG_InstaMessageMain_f },
|
||||
{ "instamsg_group_a", &CG_InstaMessageGroupA_f },
|
||||
{ "instamsg_group_b", &CG_InstaMessageGroupB_f },
|
||||
{ "instamsg_group_c", &CG_InstaMessageGroupC_f },
|
||||
{ "instamsg_group_d", &CG_InstaMessageGroupD_f },
|
||||
{ "instamsg_group_e", &CG_InstaMessageGroupE_f },
|
||||
{ "pushmenu_teamselect", &CG_PushMenuTeamSelect_f },
|
||||
{ "pushmenu_weaponselect", &CG_PushMenuWeaponSelect_f },
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_ConsoleCommand
|
||||
@@ -263,23 +413,23 @@ The string has been tokenized and can be retrieved with
|
||||
Cmd_Argc() / Cmd_Argv()
|
||||
=================
|
||||
*/
|
||||
qboolean CG_ConsoleCommand( void ) {
|
||||
const char *cmd;
|
||||
int i;
|
||||
qboolean CG_ConsoleCommand(void)
|
||||
{
|
||||
const char* cmd;
|
||||
int i;
|
||||
|
||||
cmd = CG_Argv(0);
|
||||
cmd = cgi.Argv(0);
|
||||
|
||||
for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
|
||||
if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
|
||||
commands[i].function();
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
|
||||
if (!Q_stricmp(cmd, commands[i].cmd)) {
|
||||
commands[i].function();
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_InitConsoleCommands
|
||||
@@ -288,49 +438,135 @@ Let the client system know about all of our commands
|
||||
so it can perform tab completion
|
||||
=================
|
||||
*/
|
||||
void CG_InitConsoleCommands( void ) {
|
||||
int i;
|
||||
void CG_InitConsoleCommands(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) {
|
||||
cgi.AddCommand( commands[i].cmd, NULL );
|
||||
}
|
||||
for (i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
|
||||
cgi.AddCommand(commands[i].cmd);
|
||||
}
|
||||
|
||||
//
|
||||
// the game server will interpret these commands, which will be automatically
|
||||
// forwarded to the server after they are not recognized locally
|
||||
//
|
||||
// wombat: mohaa servers understand the following
|
||||
cgi.AddCommand( "dog", NULL ); // Sets the god mode cheat or toggles it.
|
||||
cgi.AddCommand ("notarget", NULL ); // Toggles the notarget cheat.
|
||||
cgi.AddCommand ("noclip", NULL ); // Toggles the noclip cheat.
|
||||
|
||||
cgi.AddCommand ("weapdrop", NULL ); // Drops the player's current weapon.
|
||||
cgi.AddCommand ("reload", NULL ); // Reloads the player's weapon
|
||||
cgi.AddCommand ("give", NULL ); // Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount.
|
||||
cgi.AddCommand ("jump", NULL ); // Makes the player jump.
|
||||
cgi.AddCommand ("holster", NULL ); // Holsters all wielded weapons, or unholsters previously put away weapons
|
||||
// su44
|
||||
cgi.AddCommand ("join_team", NULL ); // Join the specified team (allies or axis)
|
||||
cgi.AddCommand ("auto_join_team", NULL ); // Join the team with fewer players
|
||||
cgi.AddCommand ("spectator", NULL ); // Become a spectator
|
||||
|
||||
// wombat: mohaa arena what is that???
|
||||
cgi.AddCommand ("join_arena", NULL ); // Join the specified arena
|
||||
cgi.AddCommand ("leave_arena", NULL ); // Leave the current arena
|
||||
cgi.AddCommand ("create_team", NULL ); // Create a team in the current arena
|
||||
cgi.AddCommand ("leave_team", NULL ); // Leave the current team
|
||||
cgi.AddCommand ("arena_ui", NULL ); // Refresh the arena UI
|
||||
|
||||
cgi.AddCommand ("callvote", NULL ); // Player calls a vote
|
||||
cgi.AddCommand ("vote", NULL ); // Player votes either yes or no
|
||||
|
||||
cgi.AddCommand ("primarydmweapon", NULL ); // Sets the player's primary DM weapon
|
||||
// primarydmweapon rifle / smg / mg / heavy / shotgun
|
||||
|
||||
cgi.AddCommand ("kill", NULL );
|
||||
cgi.AddCommand ("say", NULL );
|
||||
cgi.AddCommand ("sayone", NULL ); // talk to one client
|
||||
cgi.AddCommand ("sayprivate", NULL ); // same as sayone??
|
||||
cgi.AddCommand ("sayteam", NULL ); // talk to team
|
||||
cgi.AddCommand ("teamsay", NULL ); // talk to team
|
||||
cgi.AddCommand("callvote");
|
||||
cgi.AddCommand("vote");
|
||||
}
|
||||
|
||||
void CG_Mapinfo_f(void)
|
||||
{
|
||||
cgi.Printf("---------------------\n");
|
||||
cgi.R_PrintBSPFileSizes();
|
||||
cgi.CM_PrintBSPFileSizes();
|
||||
cgi.Printf("---------------------\n");
|
||||
}
|
||||
|
||||
void CG_PushMenuTeamSelect_f(void)
|
||||
{
|
||||
if (cgs.gametype == GT_SINGLE_PLAYER) {
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_getplayermodel\n");
|
||||
switch (cgs.gametype) {
|
||||
case GT_FFA:
|
||||
cgi.Cmd_Execute(EXEC_NOW, "pushmenu SelectFFAModel\n");
|
||||
break;
|
||||
case GT_OBJECTIVE:
|
||||
cgi.Cmd_Execute(EXEC_NOW, "pushmenu ObjSelectTeam\n");
|
||||
break;
|
||||
default:
|
||||
cgi.Cmd_Execute(EXEC_NOW, "pushmenu SelectTeam\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CG_PushMenuWeaponSelect_f(void)
|
||||
{
|
||||
if (cgs.gametype == GT_SINGLE_PLAYER) {
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.Cmd_Execute(EXEC_NOW, "pushmenu SelectPrimaryWeapon\n");
|
||||
}
|
||||
|
||||
void CG_UseWeaponClass_f(void)
|
||||
{
|
||||
const char* cmd;
|
||||
|
||||
cmd = cgi.Argv(1);
|
||||
|
||||
if (!Q_stricmp(cmd, "pistol")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_PISTOL;
|
||||
} else if (!Q_stricmp(cmd, "rifle")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_RIFLE;
|
||||
} else if (!Q_stricmp(cmd, "smg")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_SMG;
|
||||
} else if (!Q_stricmp(cmd, "mg")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_MG;
|
||||
} else if (!Q_stricmp(cmd, "grenade")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_GRENADE;
|
||||
} else if (!Q_stricmp(cmd, "heavy")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_HEAVY;
|
||||
} else if (!Q_stricmp(cmd, "item1") || !Q_stricmp(cmd, "item")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM1;
|
||||
} else if (!Q_stricmp(cmd, "item2")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM2;
|
||||
} else if (!Q_stricmp(cmd, "item3")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM3;
|
||||
} else if (!Q_stricmp(cmd, "item4")) {
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM4;
|
||||
}
|
||||
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
void CG_NextWeapon_f(void)
|
||||
{
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_NEXT_WEAPON;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
void CG_PrevWeapon_f(void)
|
||||
{
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_PREV_WEAPON;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
void CG_UseLastWeapon_f(void)
|
||||
{
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_LAST_WEAPON;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
void CG_HolsterWeapon_f(void)
|
||||
{
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_HOLSTER;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
void CG_DropWeapon_f(void)
|
||||
{
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_DROP;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
void CG_ToggleItem_f(void)
|
||||
{
|
||||
cg.iWeaponCommand = WEAPON_COMMAND_USE_ITEM1;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
int CG_WeaponCommandButtonBits(void)
|
||||
{
|
||||
int iShiftedWeaponCommand;
|
||||
|
||||
if (!cg.iWeaponCommand) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cg.iWeaponCommandSend++;
|
||||
if (cg.iWeaponCommandSend > 2) {
|
||||
cg.iWeaponCommand = 0;
|
||||
}
|
||||
|
||||
iShiftedWeaponCommand = cg.iWeaponCommand << 7;
|
||||
return iShiftedWeaponCommand & WEAPON_COMMAND_MASK;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_drawtools.c -- helper functions called by cg_draw, cg_scoreboard, cg_info, etc
|
||||
#include "cg_local.h"
|
||||
|
||||
/*
|
||||
================
|
||||
CG_AdjustFrom640
|
||||
|
||||
Adjusted for resolution and screen aspect ratio
|
||||
================
|
||||
*/
|
||||
void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
|
||||
#if 0
|
||||
// adjust for wide screens
|
||||
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
|
||||
*x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) );
|
||||
}
|
||||
#endif
|
||||
// scale for screen sizes
|
||||
*x *= cgs.screenXScale;
|
||||
*y *= cgs.screenYScale;
|
||||
*w *= cgs.screenXScale;
|
||||
*h *= cgs.screenYScale;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FillRect
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
=================
|
||||
*/
|
||||
void CG_FillRect( float x, float y, float width, float height, const float *color ) {
|
||||
cgi.R_SetColor( color );
|
||||
|
||||
CG_AdjustFrom640( &x, &y, &width, &height );
|
||||
cgi.R_DrawStretchPic( x, y, width, height, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
|
||||
cgi.R_SetColor( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawSides
|
||||
|
||||
Coords are virtual 640x480
|
||||
================
|
||||
*/
|
||||
void CG_DrawSides(float x, float y, float w, float h, float size) {
|
||||
CG_AdjustFrom640( &x, &y, &w, &h );
|
||||
size *= cgs.screenXScale;
|
||||
cgi.R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
cgi.R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
}
|
||||
|
||||
void CG_DrawTopBottom(float x, float y, float w, float h, float size) {
|
||||
CG_AdjustFrom640( &x, &y, &w, &h );
|
||||
size *= cgs.screenYScale;
|
||||
cgi.R_DrawStretchPic( x, y, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
cgi.R_DrawStretchPic( x, y + h - size, w, size, 0, 0, 0, 0, cgs.media.whiteShader );
|
||||
}
|
||||
/*
|
||||
================
|
||||
UI_DrawRect
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
=================
|
||||
*/
|
||||
void CG_DrawRect( float x, float y, float width, float height, float size, const float *color ) {
|
||||
cgi.R_SetColor( color );
|
||||
|
||||
CG_DrawTopBottom(x, y, width, height, size);
|
||||
CG_DrawSides(x, y, width, height, size);
|
||||
|
||||
cgi.R_SetColor( NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_DrawPic
|
||||
|
||||
Coordinates are 640*480 virtual values
|
||||
=================
|
||||
*/
|
||||
void CG_DrawPic( float x, float y, float width, float height, qhandle_t hShader ) {
|
||||
CG_AdjustFrom640( &x, &y, &width, &height );
|
||||
cgi.R_DrawStretchPic( x, y, width, height, 0, 0, 1, 1, hShader );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_DrawStrlen
|
||||
|
||||
Returns character count, skiping color escape codes
|
||||
=================
|
||||
*/
|
||||
int CG_DrawStrlen( const char *str ) {
|
||||
const char *s = str;
|
||||
int count = 0;
|
||||
|
||||
// while ( *s ) {
|
||||
// if ( Q_IsColorString( s ) ) {
|
||||
// s += 2;
|
||||
// } else {
|
||||
// count++;
|
||||
// s++;
|
||||
// }
|
||||
// }
|
||||
return cgi.R_Text_Width( &cgs.media.verdana, str, -1, qtrue );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
CG_TileClearBox
|
||||
|
||||
This repeats a 64*64 tile graphic to fill the screen around a sized down
|
||||
refresh window.
|
||||
=============
|
||||
*/
|
||||
static void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) {
|
||||
float s1, t1, s2, t2;
|
||||
|
||||
s1 = x/64.0;
|
||||
t1 = y/64.0;
|
||||
s2 = (x+w)/64.0;
|
||||
t2 = (y+h)/64.0;
|
||||
cgi.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader );
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_TileClear
|
||||
|
||||
Clear around a sized down screen
|
||||
==============
|
||||
*/
|
||||
void CG_TileClear( void ) {
|
||||
int top, bottom, left, right;
|
||||
int w, h;
|
||||
|
||||
w = cgs.glconfig.vidWidth;
|
||||
h = cgs.glconfig.vidHeight;
|
||||
|
||||
if ( cg.refdef.x == 0 && cg.refdef.y == 0 &&
|
||||
cg.refdef.width == w && cg.refdef.height == h ) {
|
||||
return; // full screen rendering
|
||||
}
|
||||
|
||||
top = cg.refdef.y;
|
||||
bottom = top + cg.refdef.height-1;
|
||||
left = cg.refdef.x;
|
||||
right = left + cg.refdef.width-1;
|
||||
|
||||
// clear above view screen
|
||||
CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader );
|
||||
|
||||
// clear below view screen
|
||||
CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader );
|
||||
|
||||
// clear left of view screen
|
||||
CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader );
|
||||
|
||||
// clear right of view screen
|
||||
CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FadeColor
|
||||
================
|
||||
*/
|
||||
float *CG_FadeColor( int startMsec, int totalMsec ) {
|
||||
static vec4_t color;
|
||||
int t;
|
||||
|
||||
if ( startMsec == 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
t = cg.time - startMsec;
|
||||
|
||||
if ( t >= totalMsec ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fade out
|
||||
if ( totalMsec - t < FADE_TIME ) {
|
||||
color[3] = ( totalMsec - t ) * 1.0/FADE_TIME;
|
||||
} else {
|
||||
color[3] = 1.0;
|
||||
}
|
||||
color[0] = color[1] = color[2] = 1;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_DrawStringExt
|
||||
|
||||
Draws a multi-colored string with a drop shadow, optionally forcing
|
||||
to a fixed color.
|
||||
|
||||
Coordinates are at 640 by 480 virtual resolution
|
||||
==================
|
||||
*/
|
||||
void CG_DrawStringExt( int x, int y, const char *string, const float *setColor,
|
||||
qboolean forceColor, qboolean shadow, int charWidth, int charHeight, int maxChars ) {
|
||||
if(string == 0 || string[0] == 0)
|
||||
return;
|
||||
cgi.R_SetColor(setColor);
|
||||
cgi.R_Text_Paint(&cgs.media.verdana, x, y, 1, 1, string, 0, maxChars, qfalse, qfalse);
|
||||
}
|
||||
void CG_DrawBigString( int x, int y, const char *s, float alpha ) {
|
||||
float color[4];
|
||||
|
||||
color[0] = color[1] = color[2] = 1.0;
|
||||
color[3] = alpha;
|
||||
CG_DrawStringExt( x, y, s, color, qfalse, qtrue, BIGCHAR_WIDTH, BIGCHAR_HEIGHT, 0 );
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,453 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_effects.c -- these functions generate localentities, usually as a result
|
||||
// of event processing
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_BubbleTrail
|
||||
|
||||
Bullets shot underwater
|
||||
==================
|
||||
*/
|
||||
void CG_BubbleTrail( vec3_t start, vec3_t end, float spacing ) {
|
||||
//vec3_t move;
|
||||
//vec3_t vec;
|
||||
//float len;
|
||||
//int i;
|
||||
|
||||
//if ( cg_noProjectileTrail->integer ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//VectorCopy (start, move);
|
||||
//VectorSubtract (end, start, vec);
|
||||
//len = VectorNormalize (vec);
|
||||
|
||||
//// advance a random amount first
|
||||
//i = rand() % (int)spacing;
|
||||
//VectorMA( move, i, vec, move );
|
||||
|
||||
//VectorScale (vec, spacing, vec);
|
||||
|
||||
//for ( ; i < len; i += spacing ) {
|
||||
// localEntity_t *le;
|
||||
// refEntity_t *re;
|
||||
|
||||
// le = CG_AllocLocalEntity();
|
||||
// le->leFlags = LEF_PUFF_DONT_SCALE;
|
||||
// le->leType = LE_MOVE_SCALE_FADE;
|
||||
// le->startTime = cg.time;
|
||||
// le->endTime = cg.time + 1000 + random() * 250;
|
||||
// le->lifeRate = 1.0 / ( le->endTime - le->startTime );
|
||||
|
||||
// re = &le->refEntity;
|
||||
// re->shaderTime = cg.time / 1000.0f;
|
||||
|
||||
// re->reType = RT_SPRITE;
|
||||
// re->rotation = 0;
|
||||
// re->radius = 3;
|
||||
// re->customShader = cgs.media.waterBubbleShader;
|
||||
// re->shaderRGBA[0] = 0xff;
|
||||
// re->shaderRGBA[1] = 0xff;
|
||||
// re->shaderRGBA[2] = 0xff;
|
||||
// re->shaderRGBA[3] = 0xff;
|
||||
|
||||
// le->color[3] = 1.0;
|
||||
|
||||
// le->pos.trType = TR_LINEAR;
|
||||
// le->pos.trTime = cg.time;
|
||||
// VectorCopy( move, le->pos.trBase );
|
||||
// le->pos.trDelta[0] = crandom()*5;
|
||||
// le->pos.trDelta[1] = crandom()*5;
|
||||
// le->pos.trDelta[2] = crandom()*5 + 6;
|
||||
|
||||
// VectorAdd (move, vec, move);
|
||||
//}
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CG_SmokePuff
|
||||
|
||||
Adds a smoke puff or blood trail localEntity.
|
||||
=====================
|
||||
*/
|
||||
localEntity_t *CG_SmokePuff( const vec3_t p, const vec3_t vel,
|
||||
float radius,
|
||||
float r, float g, float b, float a,
|
||||
float duration,
|
||||
int startTime,
|
||||
int fadeInTime,
|
||||
int leFlags,
|
||||
qhandle_t hShader ) {
|
||||
// static int seed = 0x92;
|
||||
// localEntity_t *le;
|
||||
// refEntity_t *re;
|
||||
//// int fadeInTime = startTime + duration / 2;
|
||||
//
|
||||
// le = CG_AllocLocalEntity();
|
||||
// le->leFlags = leFlags;
|
||||
// le->radius = radius;
|
||||
//
|
||||
// re = &le->refEntity;
|
||||
// re->rotation = Q_random( &seed ) * 360;
|
||||
// re->radius = radius;
|
||||
// re->shaderTime = startTime / 1000.0f;
|
||||
//
|
||||
// le->leType = LE_MOVE_SCALE_FADE;
|
||||
// le->startTime = startTime;
|
||||
// le->fadeInTime = fadeInTime;
|
||||
// le->endTime = startTime + duration;
|
||||
// if ( fadeInTime > startTime ) {
|
||||
// le->lifeRate = 1.0 / ( le->endTime - le->fadeInTime );
|
||||
// }
|
||||
// else {
|
||||
// le->lifeRate = 1.0 / ( le->endTime - le->startTime );
|
||||
// }
|
||||
// le->color[0] = r;
|
||||
// le->color[1] = g;
|
||||
// le->color[2] = b;
|
||||
// le->color[3] = a;
|
||||
//
|
||||
//
|
||||
// le->pos.trType = TR_LINEAR;
|
||||
// le->pos.trTime = startTime;
|
||||
// VectorCopy( vel, le->pos.trDelta );
|
||||
// VectorCopy( p, le->pos.trBase );
|
||||
//
|
||||
// VectorCopy( p, re->origin );
|
||||
// re->customShader = hShader;
|
||||
//
|
||||
// // rage pro can't alpha fade, so use a different shader
|
||||
// if ( cgs.glconfig.hardwareType == GLHW_RAGEPRO ) {
|
||||
// re->customShader = cgs.media.smokePuffRageProShader;
|
||||
// re->shaderRGBA[0] = 0xff;
|
||||
// re->shaderRGBA[1] = 0xff;
|
||||
// re->shaderRGBA[2] = 0xff;
|
||||
// re->shaderRGBA[3] = 0xff;
|
||||
// } else {
|
||||
// re->shaderRGBA[0] = le->color[0] * 0xff;
|
||||
// re->shaderRGBA[1] = le->color[1] * 0xff;
|
||||
// re->shaderRGBA[2] = le->color[2] * 0xff;
|
||||
// re->shaderRGBA[3] = 0xff;
|
||||
// }
|
||||
//
|
||||
// re->reType = RT_SPRITE;
|
||||
// re->radius = le->radius;
|
||||
//
|
||||
// return le;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_ScorePlum
|
||||
==================
|
||||
*/
|
||||
void CG_ScorePlum( int client, vec3_t org, int score ) {
|
||||
localEntity_t *le;
|
||||
refEntity_t *re;
|
||||
vec3_t angles;
|
||||
static vec3_t lastPos;
|
||||
|
||||
// only visualize for the client that scored
|
||||
if (client != cg.predictedPlayerState.clientNum || cg_scorePlum->integer == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
le = CG_AllocLocalEntity();
|
||||
le->leFlags = 0;
|
||||
le->leType = LE_SCOREPLUM;
|
||||
le->startTime = cg.time;
|
||||
le->endTime = cg.time + 4000;
|
||||
le->lifeRate = 1.0 / ( le->endTime - le->startTime );
|
||||
|
||||
|
||||
le->color[0] = le->color[1] = le->color[2] = le->color[3] = 1.0;
|
||||
le->radius = score;
|
||||
|
||||
VectorCopy( org, le->pos.trDelta );
|
||||
if (org[2] >= lastPos[2] - 20 && org[2] <= lastPos[2] + 20) {
|
||||
le->pos.trDelta[ 2 ] -= 20;
|
||||
}
|
||||
|
||||
//CG_Printf( "Plum origin %i %i %i -- %i\n", (int)org[0], (int)org[1], (int)org[2], (int)Distance(org, lastPos));
|
||||
VectorCopy(org, lastPos);
|
||||
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
re->reType = RT_SPRITE;
|
||||
re->radius = 16;
|
||||
|
||||
VectorClear(angles);
|
||||
AnglesToAxis( angles, re->axis );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_MakeExplosion
|
||||
====================
|
||||
*/
|
||||
localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir,
|
||||
qhandle_t hModel, qhandle_t shader,
|
||||
int msec, qboolean isSprite ) {
|
||||
float ang;
|
||||
localEntity_t *ex;
|
||||
int offset;
|
||||
vec3_t tmpVec, newOrigin;
|
||||
|
||||
if ( msec <= 0 ) {
|
||||
CG_Error( "CG_MakeExplosion: msec = %i", msec );
|
||||
}
|
||||
|
||||
// skew the time a bit so they aren't all in sync
|
||||
offset = rand() & 63;
|
||||
|
||||
ex = CG_AllocLocalEntity();
|
||||
if ( isSprite ) {
|
||||
ex->leType = LE_SPRITE_EXPLOSION;
|
||||
|
||||
// randomly rotate sprite orientation
|
||||
ex->refEntity.rotation = rand() % 360;
|
||||
VectorScale( dir, 16, tmpVec );
|
||||
VectorAdd( tmpVec, origin, newOrigin );
|
||||
} else {
|
||||
ex->leType = LE_EXPLOSION;
|
||||
VectorCopy( origin, newOrigin );
|
||||
|
||||
// set axis with random rotate
|
||||
if ( !dir ) {
|
||||
AxisClear( ex->refEntity.axis );
|
||||
} else {
|
||||
ang = rand() % 360;
|
||||
VectorCopy( dir, ex->refEntity.axis[0] );
|
||||
RotateAroundDirection( ex->refEntity.axis, ang );
|
||||
}
|
||||
}
|
||||
|
||||
ex->startTime = cg.time - offset;
|
||||
ex->endTime = ex->startTime + msec;
|
||||
|
||||
// bias the time so all shader effects start correctly
|
||||
ex->refEntity.shaderTime = ex->startTime / 1000.0f;
|
||||
|
||||
ex->refEntity.model = hModel;
|
||||
ex->refEntity.customShader = shader;
|
||||
|
||||
// set origin
|
||||
VectorCopy( newOrigin, ex->refEntity.origin );
|
||||
VectorCopy( newOrigin, ex->refEntity.oldorigin );
|
||||
|
||||
ex->color[0] = ex->color[1] = ex->color[2] = 1.0;
|
||||
|
||||
return ex;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_Bleed
|
||||
|
||||
This is the spurt of blood when a character gets hit
|
||||
=================
|
||||
*/
|
||||
void CG_Bleed( vec3_t origin, int entityNum ) {
|
||||
localEntity_t *ex;
|
||||
|
||||
if ( !cg_blood->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ex = CG_AllocLocalEntity();
|
||||
ex->leType = LE_EXPLOSION;
|
||||
|
||||
ex->startTime = cg.time;
|
||||
ex->endTime = ex->startTime + 500;
|
||||
|
||||
VectorCopy ( origin, ex->refEntity.origin);
|
||||
ex->refEntity.reType = RT_SPRITE;
|
||||
ex->refEntity.rotation = rand() % 360;
|
||||
ex->refEntity.radius = 24;
|
||||
|
||||
ex->refEntity.customShader = 0; //cgs.media.bloodExplosionShader;
|
||||
|
||||
// don't show player's own blood in view
|
||||
if ( entityNum == cg.snap->ps.clientNum ) {
|
||||
ex->refEntity.renderfx |= RF_THIRD_PERSON;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_LaunchGib
|
||||
==================
|
||||
*/
|
||||
void CG_LaunchGib( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
|
||||
localEntity_t *le;
|
||||
refEntity_t *re;
|
||||
|
||||
le = CG_AllocLocalEntity();
|
||||
re = &le->refEntity;
|
||||
|
||||
le->leType = LE_FRAGMENT;
|
||||
le->startTime = cg.time;
|
||||
le->endTime = le->startTime + 5000 + random() * 3000;
|
||||
|
||||
VectorCopy( origin, re->origin );
|
||||
AxisCopy( axisDefault, re->axis );
|
||||
re->model = hModel;
|
||||
|
||||
VectorCopy( origin, le->pos.trDelta );
|
||||
VectorCopy( velocity, le->pos.trDelta );
|
||||
le->pos.trTime = cg.time;
|
||||
|
||||
le->bounceFactor = 0.6f;
|
||||
|
||||
le->leBounceSoundType = LEBS_BLOOD;
|
||||
le->leMarkType = LEMT_BLOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_GibPlayer
|
||||
|
||||
Generated a bunch of gibs launching out from the bodies location
|
||||
===================
|
||||
*/
|
||||
#define GIB_VELOCITY 250
|
||||
#define GIB_JUMP 250
|
||||
void CG_GibPlayer( vec3_t playerOrigin ) {
|
||||
//vec3_t origin, velocity;
|
||||
|
||||
//if ( !cg_blood->integer ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//if ( rand() & 1 ) {
|
||||
// CG_LaunchGib( origin, velocity, cgs.media.gibSkull );
|
||||
//} else {
|
||||
// CG_LaunchGib( origin, velocity, cgs.media.gibBrain );
|
||||
//}
|
||||
|
||||
//// allow gibs to be turned off for speed
|
||||
//if ( !cg_gibs->integer ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibAbdomen );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibArm );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibChest );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibFist );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibFoot );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibForearm );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibIntestine );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
|
||||
|
||||
//VectorCopy( playerOrigin, origin );
|
||||
//velocity[0] = crandom()*GIB_VELOCITY;
|
||||
//velocity[1] = crandom()*GIB_VELOCITY;
|
||||
//velocity[2] = GIB_JUMP + crandom()*GIB_VELOCITY;
|
||||
//CG_LaunchGib( origin, velocity, cgs.media.gibLeg );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_LaunchGib
|
||||
==================
|
||||
*/
|
||||
void CG_LaunchExplode( vec3_t origin, vec3_t velocity, qhandle_t hModel ) {
|
||||
localEntity_t *le;
|
||||
refEntity_t *re;
|
||||
|
||||
le = CG_AllocLocalEntity();
|
||||
re = &le->refEntity;
|
||||
|
||||
le->leType = LE_FRAGMENT;
|
||||
le->startTime = cg.time;
|
||||
le->endTime = le->startTime + 10000 + random() * 6000;
|
||||
|
||||
VectorCopy( origin, re->origin );
|
||||
AxisCopy( axisDefault, re->axis );
|
||||
re->model = hModel;
|
||||
|
||||
VectorCopy( origin, le->pos.trDelta );
|
||||
VectorCopy( velocity, le->pos.trDelta );
|
||||
le->pos.trTime = cg.time;
|
||||
|
||||
le->bounceFactor = 0.1f;
|
||||
|
||||
le->leBounceSoundType = LEBS_BRASS;
|
||||
le->leMarkType = LEMT_NONE;
|
||||
}
|
||||
|
||||
+492
-375
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
@@ -20,15 +20,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
typedef struct UIBindButton_s {
|
||||
UIButton baseClass;
|
||||
str m_bindcommand;
|
||||
int m_bindindex;
|
||||
qboolean m_getkey;
|
||||
qboolean m_alternate;
|
||||
str m_entersound;
|
||||
str m_activesound;
|
||||
str m_last_keyname;
|
||||
UIReggedMaterial *m_mat;
|
||||
} UIBindButton;
|
||||
// DESCRIPTION:
|
||||
// handle entity events at snapshot or playerstate transitions
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_EntityEvent
|
||||
|
||||
An entity has an event value
|
||||
==============
|
||||
*/
|
||||
|
||||
void CG_EntityEvent( centity_t *cent, vec3_t position )
|
||||
{
|
||||
}
|
||||
@@ -1,613 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 su44
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// cg_eventSystem.c
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "../qcommon/tiki_local.h"
|
||||
|
||||
typedef struct event_s {
|
||||
centity_t *ent;
|
||||
char buffer[1024];
|
||||
int execTime; // event should be executed and fried if cg.time >= ev->execTime
|
||||
struct event_s *next,*prev; // linked list
|
||||
} event_t;
|
||||
|
||||
#define MAX_PENDING_EVENTS 512
|
||||
|
||||
static event_t events[MAX_PENDING_EVENTS];
|
||||
static event_t cg_pendingEvents; // double linked list
|
||||
static event_t *cg_freeEvents; // single linked list
|
||||
|
||||
void CG_InitEventSystem() {
|
||||
int i;
|
||||
|
||||
memset( events, 0, sizeof( events ) );
|
||||
cg_pendingEvents.next = &cg_pendingEvents;
|
||||
cg_pendingEvents.prev = &cg_pendingEvents;
|
||||
cg_freeEvents = events;
|
||||
for ( i = 0 ; i < MAX_PENDING_EVENTS - 1 ; i++ ) {
|
||||
events[i].next = &events[i+1];
|
||||
}
|
||||
}
|
||||
/*
|
||||
Generates a random float component for MoHAA events.
|
||||
If random is specified, the component will range from 0 to specified value.
|
||||
If crandom is specified, the component will range from -specified to +specified value.
|
||||
If range is specified, the component needs two values; it will randomly pick a number in the range
|
||||
from the first number to the first number plus the second number.
|
||||
This is used by "randvel", "randvelaxis", "offset", "offsetalongaxis", "angles", MoHAA events
|
||||
*/
|
||||
float CG_ParseEventFloatParm(char **text) {
|
||||
char *token;
|
||||
float value;
|
||||
token = COM_ParseExt( text, qfalse );
|
||||
if(!Q_stricmp(token,"random")) {
|
||||
token = COM_ParseExt( text, qfalse );
|
||||
value = random()*atof(token);
|
||||
} else if(!Q_stricmp(token,"crandom")) {
|
||||
token = COM_ParseExt( text, qfalse );
|
||||
value = crandom()*atof(token);
|
||||
} else if(!Q_stricmp(token,"range")) {
|
||||
float range;
|
||||
token = COM_ParseExt( text, qfalse );
|
||||
value = atof(token);
|
||||
|
||||
token = COM_ParseExt( text, qfalse );
|
||||
range = atof(token);
|
||||
|
||||
value += random()*range;
|
||||
} else {
|
||||
#if 0
|
||||
CG_Printf("CG_ParseEventFloatParm: unknown first parm, expected 'random', 'crandom' or 'range', found %s\n",token);
|
||||
value = 0;
|
||||
#else
|
||||
value = atof(token);
|
||||
#endif
|
||||
}
|
||||
return value;
|
||||
}
|
||||
// this is used by both "tagspawn" and "originspawn" events
|
||||
void CG_ProcessSpawnEvent(centity_t *ent, vec3_t spawnOrigin, vec3_t spawnAngles, char *text) {
|
||||
char *token;
|
||||
qhandle_t h;
|
||||
tiki_t *tiki;
|
||||
vec3_t v;
|
||||
localEntity_t *le;
|
||||
char *dot;
|
||||
|
||||
// skip optional paramter(s) ? see rechamber anim of weapons/kar98.tik
|
||||
do {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
if(token[0]==0) {
|
||||
CG_Printf("'***spawn' event without parameters block\n");
|
||||
return;
|
||||
}
|
||||
} while(token[0] != '(');
|
||||
if(token[1] == 0) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
} else {
|
||||
token++;
|
||||
}
|
||||
|
||||
le = CG_AllocLocalEntity();
|
||||
le->endTime = cg.time + 10000;
|
||||
le->leType = LE_SKIP;
|
||||
//le->leFlags = LEF_TUMBLE;
|
||||
le->pos.trTime = cg.time - (rand()&15);
|
||||
VectorCopy( spawnOrigin, le->pos.trDelta );
|
||||
VectorCopy(spawnOrigin,le->refEntity.origin);
|
||||
VectorCopy( spawnAngles, le->angles.trDelta );
|
||||
AnglesToAxis(spawnAngles,le->refEntity.axis);
|
||||
tiki = le->tiki;
|
||||
// parse parameters ( ... ) block
|
||||
while(token[0] != ')') {
|
||||
if(token[0]==0) {
|
||||
CG_Printf("'***spawn' missing ')' in tiki %s\n",tiki->name);
|
||||
return;
|
||||
}
|
||||
Q_strlwr(token);
|
||||
if(!strcmp(token,"spawnrange")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"spawnrate")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"count")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"model")) {
|
||||
// both .tik and .spr models are used here
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
h = cgi.R_RegisterModel(token);
|
||||
le->refEntity.model = h;
|
||||
le->leType = LE_FRAGMENT;
|
||||
dot = strchr(token,'.');
|
||||
if(dot && !Q_stricmp(dot+1,"tik")) {
|
||||
le->tiki = cgi.TIKI_RegisterModel(token);
|
||||
}
|
||||
} else if(!strcmp(token,"color")) {
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
|
||||
} else if(!strcmp(token,"varycolor")) {
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
|
||||
} else if(!strcmp(token,"alpha")) {
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
|
||||
} else if(!strcmp(token,"offset")) {
|
||||
token = COM_ParseExt( &text, qfalse ); // x
|
||||
token = COM_ParseExt( &text, qfalse ); // y
|
||||
token = COM_ParseExt( &text, qfalse ); // z
|
||||
|
||||
} else if(!strcmp(token,"offsetalongaxis")) {
|
||||
v[0] = CG_ParseEventFloatParm(&text); // x
|
||||
v[1] = CG_ParseEventFloatParm(&text); // y
|
||||
v[2] = CG_ParseEventFloatParm(&text); // z
|
||||
|
||||
} else if(!strcmp(token,"randvelaxis")) {
|
||||
v[0] = CG_ParseEventFloatParm(&text); // x
|
||||
v[1] = CG_ParseEventFloatParm(&text); // y
|
||||
v[2] = CG_ParseEventFloatParm(&text); // z
|
||||
|
||||
} else if(!strcmp(token,"scale")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"scalemin")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"scalemax")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"scalerate")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"velocity")) {
|
||||
token = COM_ParseExt( &text, qtrue ); // forwardVelocity
|
||||
|
||||
} else if(!strcmp(token,"angles")) {
|
||||
v[0] = CG_ParseEventFloatParm(&text);
|
||||
v[1] = CG_ParseEventFloatParm(&text);
|
||||
v[2] = CG_ParseEventFloatParm(&text);
|
||||
VectorCopy( v, le->angles.trDelta );
|
||||
AnglesToAxis(v,le->refEntity.axis);
|
||||
|
||||
} else if(!strcmp(token,"randvel")) {
|
||||
v[0] = CG_ParseEventFloatParm(&text);
|
||||
v[1] = CG_ParseEventFloatParm(&text);
|
||||
v[2] = CG_ParseEventFloatParm(&text);
|
||||
VectorCopy(v,le->pos.trDelta);
|
||||
} else if(!strcmp(token,"emitterangles")) {
|
||||
token = COM_ParseExt( &text, qfalse ); // pitchofs
|
||||
token = COM_ParseExt( &text, qfalse ); // yawofs
|
||||
token = COM_ParseExt( &text, qfalse ); // rollofs
|
||||
} else if(!strcmp(token,"avelocity")) {
|
||||
// crandom keyword is used for avelocity in weapons/mp40.tik
|
||||
v[YAW] = CG_ParseEventFloatParm(&text); // yawVel
|
||||
v[PITCH] = CG_ParseEventFloatParm(&text); // pitchVel
|
||||
v[ROLL] = CG_ParseEventFloatParm(&text); // rollVel
|
||||
|
||||
//VectorCopy(v,le->apos.trDelta);
|
||||
|
||||
} else if(!strcmp(token,"accel")) {
|
||||
// NOTE: This acceleration is applied using the world axis
|
||||
token = COM_ParseExt( &text, qfalse ); // accelX
|
||||
token = COM_ParseExt( &text, qfalse ); // accelY
|
||||
token = COM_ParseExt( &text, qfalse ); // accelZ
|
||||
|
||||
} else if(!strcmp(token,"physicsrate")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
if(!Q_stricmp(token,"every")) {
|
||||
|
||||
}
|
||||
} else if(!strcmp(token,"life")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
le->endTime = cg.time + atof(token)*1000;
|
||||
} else if(!strcmp(token,"fadedelay")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else if(!strcmp(token,"alignstretch")) {
|
||||
token = COM_ParseExt( &text, qfalse ); // scaleMultiplier
|
||||
|
||||
} else if(!strcmp(token,"alignonce")) {
|
||||
|
||||
} else if(!strcmp(token,"align")) {
|
||||
|
||||
} else if(!strcmp(token,"collision")) {
|
||||
|
||||
} else if(!strcmp(token,"fade")) {
|
||||
|
||||
} else if(!strcmp(token,"randomroll")) {
|
||||
|
||||
} else if(!strcmp(token,"spritegridlighting")) {
|
||||
|
||||
} else if(!strcmp(token,"volumetric")) {
|
||||
// set the effect to spawn volumetric sources rather than tempmodels
|
||||
|
||||
} else if(!strcmp(token,"wateronly")) {
|
||||
// makes the temp model remove itself if it leaves water
|
||||
|
||||
} else if(!strcmp(token,"wind")) {
|
||||
// makes the temp model be affected by wind
|
||||
|
||||
} else if(!strcmp(token,"bouncefactor")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
le->bounceFactor = atof(token);
|
||||
} else if(!strcmp(token,"bouncesoundonce")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
|
||||
} else if(!strcmp(token,"friction")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
} else {
|
||||
//CG_Printf("Uknown '***spawn' parameter %s\n",token);
|
||||
}
|
||||
COM_ParseExt( &text, qtrue );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CG_ProcessEventText(centity_t *ent, const char *eventText) {
|
||||
char str[128];
|
||||
char *text;
|
||||
char *token;
|
||||
float f;
|
||||
int i;
|
||||
int boneName;
|
||||
tiki_t *tiki;
|
||||
vec3_t v,a;
|
||||
|
||||
|
||||
text = (char*)eventText;
|
||||
again:
|
||||
// if(cg_printEvents.integer)
|
||||
// CG_Printf("CG_ProcessEventText: event %s\n",eventText);
|
||||
|
||||
// get event name
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
Q_strlwr(token);
|
||||
if(!strcmp(token,"sound")) {
|
||||
// syntax: sound( String soundName,
|
||||
// [ String channelName ], [ Float volume ],
|
||||
// [ Float min_distance ], [ Float pitch ],
|
||||
// [ Float randompitch ], [ String randomvolume ] )
|
||||
char *name;
|
||||
//float volume, minDist, pitch, randompitch;
|
||||
soundChannel_t channel;
|
||||
ubersound_t* sound;
|
||||
name = COM_ParseExt( &text, qtrue );
|
||||
sound = CG_GetUbersound(name);
|
||||
|
||||
if (!sound)
|
||||
return;
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
|
||||
if ( token[0] ) {
|
||||
if ( !Q_strncmp( token, "auto", MAX_QPATH ) )
|
||||
channel = CHAN_AUTO;
|
||||
else if ( !Q_strncmp( token, "body", MAX_QPATH ) )
|
||||
channel = CHAN_BODY;
|
||||
else if ( !Q_strncmp( token, "item", MAX_QPATH ) )
|
||||
channel = CHAN_ITEM;
|
||||
else if ( !Q_strncmp( token, "weaponidle", MAX_QPATH ) )
|
||||
channel = CHAN_WEAPONIDLE;
|
||||
else if ( !Q_strncmp( token, "voice", MAX_QPATH ) )
|
||||
channel = CHAN_VOICE;
|
||||
else if ( !Q_strncmp( token, "local", MAX_QPATH ) )
|
||||
channel = CHAN_LOCAL;
|
||||
else if ( !Q_strncmp( token, "weapon", MAX_QPATH ) )
|
||||
channel = CHAN_WEAPON;
|
||||
else if ( !Q_strncmp( token, "dialog_secondary", MAX_QPATH ) )
|
||||
channel = CHAN_DIALOG_SECONDARY;
|
||||
else if ( !Q_strncmp( token, "dialog", MAX_QPATH ) )
|
||||
channel = CHAN_DIALOG;
|
||||
else if ( !Q_strncmp( token, "menu", MAX_QPATH ) )
|
||||
channel = CHAN_MENU;
|
||||
else {
|
||||
//CG_Printf( "Event sound unrecognized channel %s for %s\n", token, name );
|
||||
channel = sound->channel;
|
||||
}
|
||||
//token = COM_ParseExt( &text, qtrue );
|
||||
} else channel = sound->channel;
|
||||
|
||||
/* if ( token[0] ) {
|
||||
volume = atof( token );
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
}
|
||||
minDist = atof( COM_ParseExt( &text, qtrue ) );
|
||||
pitch = atof( COM_ParseExt( &text, qtrue ) );
|
||||
randompitch = atof( COM_ParseExt( &text, qtrue ) );
|
||||
randomvolume = COM_ParseExt( &text, qtrue );*/
|
||||
#if 0
|
||||
cgi.S_StartSound( ent->currentState.origin, -1, channel, sound->sfxHandle );
|
||||
#else
|
||||
cgi.S_StartSound( 0, ent->currentState.number, channel, sound->sfxHandle );
|
||||
#endif
|
||||
} else if(!strcmp(token,"stopsound")) {
|
||||
// syntax: stopsound( String channelName )
|
||||
// TODO
|
||||
} else if(!strcmp(token,"loopsound")) {
|
||||
// syntax: loopsound( String soundName, [ Float volume ],
|
||||
// [ Float min_distance ], Float pitch )
|
||||
char *name;
|
||||
//float volume, minDist, pitch;
|
||||
ubersound_t* snd;
|
||||
name = COM_ParseExt( &text, qtrue );
|
||||
snd = CG_GetUbersound(name);
|
||||
/* volume = atof( COM_ParseExt( &text, qtrue ) );
|
||||
minDist = atof( COM_ParseExt( &text, qtrue ) );
|
||||
pitch = atof( COM_ParseExt( &text, qtrue ) );
|
||||
*/
|
||||
if (snd)
|
||||
cgi.S_AddLoopingSound( ent->currentState.number, ent->currentState.origin, vec3_origin, snd->sfxHandle );
|
||||
} else if(!strcmp(token,"stoploopsound")) {
|
||||
cgi.S_StopLoopingSound( ent->currentState.number );
|
||||
} else if(!strcmp(token,"stopaliaschannel")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
} else if(!strcmp(token,"viewkick")) {
|
||||
// viewkick( Float pitchmin, Float pitchmax,
|
||||
// Float yawmin, Float yawmax, Float recenterspeed,
|
||||
// String patters, Float pitchmax, Float yawmax )
|
||||
// TODO
|
||||
} else if(!strcmp(token,"cache")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
//CG_Printf("Caching %s...\n",token);
|
||||
cgi.R_RegisterModel(token);
|
||||
} else if(!strcmp(token,"commanddelay")) {
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
f = atof(token);
|
||||
CG_PostEvent(ent,text,f*1000);
|
||||
} else if(!strcmp(token,"originspawn")) {
|
||||
CG_ProcessSpawnEvent(ent,ent->lerpOrigin, ent->lerpAngles, text);
|
||||
} else if(!strcmp(token,"tagspawn")) {
|
||||
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
|
||||
if(!tiki) {
|
||||
CG_Printf("'tagspawn' event cast on entity with null TIKI\n");
|
||||
return;
|
||||
}
|
||||
// parse tagname
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
// find tag in tiki
|
||||
boneName = cgi.TIKI_GetBoneNameIndex(token);
|
||||
for(i = 0; i < tiki->numBones; i++) {
|
||||
if(tiki->boneNames[i] == boneName) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == tiki->numBones) {
|
||||
CG_Printf("Cant find bone %s in tiki %s for 'tagspawn' event\n",token,tiki->name);
|
||||
return;
|
||||
}
|
||||
if(ent->bones == 0) {
|
||||
CG_Printf("'tagspawn' event cast on entity with null bones ptr\n");
|
||||
return;
|
||||
}
|
||||
CG_CentBoneIndexLocal2World(i,ent,v,a);
|
||||
CG_ProcessSpawnEvent(ent,v,a,text);
|
||||
} else if(!strcmp(token,"tagspawnlinked")) {
|
||||
return; // FIXME!
|
||||
} else if(!strcmp(token,"tagdlight")) {
|
||||
float r,g,b,intensity;
|
||||
// tagdlight( String tagName, Float red, Float green,
|
||||
// Float blue, Float intensity, Float life,
|
||||
// [ String intvel ], [ String type1 ] )
|
||||
/*
|
||||
Spawn a dynamic light from the specified tag
|
||||
The red,green,blue parms are the color of the light
|
||||
The intensity is the radius of the light
|
||||
type is the type of light to create (lensflare,viewlensflare,additive)
|
||||
*/
|
||||
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
|
||||
if(!tiki) {
|
||||
CG_Printf("'tagdlight' event cast on entity with null TIKI\n");
|
||||
return;
|
||||
}
|
||||
// parse tagname
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
// find tag in tiki
|
||||
boneName = cgi.TIKI_GetBoneNameIndex(token);
|
||||
for(i = 0; i < tiki->numBones; i++) {
|
||||
if(tiki->boneNames[i] == boneName) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == tiki->numBones) {
|
||||
CG_Printf("Cant find bone %s in tiki %s for 'tagdlight' event\n",token,tiki->name);
|
||||
return;
|
||||
}
|
||||
if(ent->bones == 0) {
|
||||
CG_Printf("'tagdlight' event cast on entity with null bones ptr\n");
|
||||
return;
|
||||
}
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
r = atof(token);
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
g = atof(token);
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
b = atof(token);
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
intensity = atof(token);
|
||||
// optional parameters
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
if(token[0]) {
|
||||
// TODO
|
||||
token = COM_ParseExt( &text, qtrue );
|
||||
if(token[0]) {
|
||||
if(!Q_stricmp(token,"addictive")) {
|
||||
|
||||
} else if(!Q_stricmp(token,"lensflare")) {
|
||||
|
||||
} else if(!Q_stricmp(token,"viewlensflare")) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
CG_CentBoneIndexLocal2World(i,ent,v,0);
|
||||
cgi.R_AddLightToScene(v,intensity,r,g,b);
|
||||
} else if(!strcmp(token,"sfx")) {
|
||||
goto again;
|
||||
|
||||
} else if(!strcmp(token,"bodyfall")) {
|
||||
|
||||
} else if(!strcmp(token,"footstep")) {
|
||||
int iRunning;
|
||||
int iEquipment;
|
||||
//footstep( String tag, String sRunning, [ Integer iEquipment ] )
|
||||
// plays a footstep sound that is appropriate to the surface
|
||||
// we are currently stepping on.
|
||||
// sRunning should be set to run, walk, or ladder
|
||||
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
|
||||
if(!tiki) {
|
||||
CG_Printf("'footstep' event cast on entity with null TIKI\n");
|
||||
return;
|
||||
}
|
||||
// parse tagname
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
strcpy(str,token);
|
||||
/*
|
||||
// find tag in tiki
|
||||
boneName = cgi.TIKI_GetBoneNameIndex(token);
|
||||
for(i = 0; i < tiki->numBones; i++) {
|
||||
if(tiki->boneNames[i] == boneName) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == tiki->numBones) {
|
||||
CG_Printf("Cant find bone %s in tiki %s for 'footstep' event\n",token,tiki->name);
|
||||
return;
|
||||
}
|
||||
if(ent->bones == 0) {
|
||||
CG_Printf("'footstep' event cast on entity with null bones ptr\n");
|
||||
return;
|
||||
}
|
||||
*/
|
||||
// sRunning
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
if(!Q_stricmp(token,"run")) {
|
||||
//iRunning = ??;
|
||||
} else if(!Q_stricmp(token,"walk")) {
|
||||
//iRunning = ??;
|
||||
} else if(!Q_stricmp(token,"ladder")) {
|
||||
//iRunning = ??;
|
||||
} else if(!Q_stricmp(token,"R")) {
|
||||
//iRunning = ??;
|
||||
} else if(!Q_stricmp(token,"L")) {
|
||||
//iRunning = ??;
|
||||
} else {
|
||||
//iRunning = ??;
|
||||
CG_Printf("'footstep' event: unknown sRunning type %s\n",token);
|
||||
}
|
||||
// Integer iEquipment
|
||||
token = COM_ParseExt( &text, qfalse );
|
||||
iEquipment = 0;
|
||||
if(token[0]) {
|
||||
iEquipment = atoi(token);
|
||||
}
|
||||
|
||||
iRunning = 0;
|
||||
CG_Footstep(str,ent,/*0,*/iRunning,iEquipment);
|
||||
|
||||
} else if(!strcmp(token,"emitteroff")) {
|
||||
|
||||
} else if(!strcmp(token,"emitteron")) {
|
||||
|
||||
} else {
|
||||
CG_Printf("CG_ProcessEventText: unknown event %s\n",token);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CG_FreeEvent(event_t *ev) {
|
||||
if ( !ev->prev ) {
|
||||
CG_Error( "CG_FreeEvent: not active" );
|
||||
}
|
||||
|
||||
// remove from the doubly linked active list
|
||||
ev->prev->next = ev->next;
|
||||
ev->next->prev = ev->prev;
|
||||
|
||||
// the free list is only singly linked
|
||||
ev->next = cg_freeEvents;
|
||||
cg_freeEvents = ev;
|
||||
}
|
||||
event_t *CG_AllocEvent() {
|
||||
event_t *ev;
|
||||
|
||||
if ( !cg_freeEvents ) {
|
||||
CG_Printf("CG_AllocEvent: no free events\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ev = cg_freeEvents;
|
||||
cg_freeEvents = cg_freeEvents->next;
|
||||
|
||||
memset( ev, 0, sizeof( *ev ) );
|
||||
|
||||
// link into the active list
|
||||
ev->next = cg_pendingEvents.next;
|
||||
ev->prev = &cg_pendingEvents;
|
||||
cg_pendingEvents.next->prev = ev;
|
||||
cg_pendingEvents.next = ev;
|
||||
return ev;
|
||||
}
|
||||
|
||||
void CG_PostEvent(centity_t *ent, const char *eventText, int eventDelay) {
|
||||
event_t *ev;
|
||||
ev = CG_AllocEvent();
|
||||
if(!ev)
|
||||
return; // failed to alloc an event
|
||||
ev->ent = ent;
|
||||
strcpy(ev->buffer,eventText);
|
||||
ev->execTime = cg.time + eventDelay;
|
||||
}
|
||||
|
||||
void CG_ProcessEvent(event_t *ev) {
|
||||
CG_ProcessEventText(ev->ent,ev->buffer);
|
||||
CG_FreeEvent(ev);
|
||||
}
|
||||
|
||||
void CG_ProcessPendingEvents() {
|
||||
event_t *ev, *next;
|
||||
ev = cg_pendingEvents.next;
|
||||
for ( ; ev != &cg_pendingEvents ; ev = next ) {
|
||||
// grab next now, so if the event is freed we
|
||||
// still have it
|
||||
next = ev->next;
|
||||
if ( cg.time >= ev->execTime ) {
|
||||
// execute it
|
||||
CG_ProcessEventText(ev->ent, ev->buffer);
|
||||
// and free
|
||||
CG_FreeEvent(ev);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// light style code
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
LIGHT STYLE CODE
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
#define MAX_LIGHTSTYLE_LENGTH 128
|
||||
#define MAX_LIGHTSTYLE_NAME_LENGTH 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[ MAX_LIGHTSTYLE_NAME_LENGTH ];
|
||||
qboolean hasalpha;
|
||||
int length;
|
||||
float map[ MAX_LIGHTSTYLE_LENGTH ][ 4 ];
|
||||
} clightstyle_t;
|
||||
|
||||
clightstyle_t cg_lightstyle[ MAX_LIGHTSTYLES * 2 ];
|
||||
|
||||
/*
|
||||
================
|
||||
CG_LightStyleColor
|
||||
================
|
||||
*/
|
||||
qboolean CG_LightStyleColor( int style, int realtime, float color[4], qboolean clamp )
|
||||
{
|
||||
clightstyle_t *ls;
|
||||
int i, time;
|
||||
float frac;
|
||||
qboolean at_end;
|
||||
|
||||
time = realtime / 50;
|
||||
frac = ( realtime - ( time * 50.0f ) ) / 50.0f;
|
||||
memset( color, 0, sizeof( color ) );
|
||||
if ( ( style < 0 ) || ( style >= ( MAX_LIGHTSTYLES * 2 ) ) )
|
||||
{
|
||||
cgi.DPrintf ("CG_LightStyleColor: style out of range.\n");
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
ls = &cg_lightstyle[ style ];
|
||||
|
||||
if ( !ls->length )
|
||||
{
|
||||
cgi.DPrintf ("CG_LightStyleColor: style %d has zero length.\n", style);
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
// by default we are not at the end
|
||||
at_end = qfalse;
|
||||
if ( clamp )
|
||||
{
|
||||
if ( time >= ls->length )
|
||||
{
|
||||
time = ls->length - 1;
|
||||
at_end = qtrue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
time %= ls->length;
|
||||
}
|
||||
|
||||
//
|
||||
// only lerp if we are before the end
|
||||
//
|
||||
if ( time == ls->length - 1 )
|
||||
{
|
||||
memcpy( color, ls->map[ time ], 4 * sizeof( ls->map[ time ][ 0 ] ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < 4; i++ )
|
||||
{
|
||||
color[ i ] = ls->map[ time ][ i ] + frac * ( ls->map[ time + 1 ][ i ] - ls->map[ time ][ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ls->hasalpha )
|
||||
color[ 3 ] = 1;
|
||||
|
||||
return at_end;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
LoadTGA
|
||||
=============
|
||||
*/
|
||||
static qboolean LoadTGA(const char * name, byte ** pic, int *width, int *height, qboolean * hasalpha )
|
||||
{
|
||||
int columns, rows, numPixels;
|
||||
byte *pixbuf;
|
||||
int row, column;
|
||||
byte *buf_p;
|
||||
byte *buffer;
|
||||
TargaHeader targa_header;
|
||||
byte *targa_rgba;
|
||||
byte targa_palette[ 256 * 4 ];
|
||||
int i;
|
||||
|
||||
*pic = NULL;
|
||||
*hasalpha = false;
|
||||
|
||||
//
|
||||
// load the file
|
||||
//
|
||||
cgi.FS_ReadFile(name, (void **)&buffer, qtrue);
|
||||
if (!buffer)
|
||||
{
|
||||
cgi.DPrintf( "TGA File not found: %s\n", name );
|
||||
return false;
|
||||
}
|
||||
|
||||
buf_p = buffer;
|
||||
|
||||
targa_header.id_length = *buf_p++;
|
||||
targa_header.colormap_type = *buf_p++;
|
||||
targa_header.image_type = *buf_p++;
|
||||
|
||||
targa_header.colormap_index = LittleShort ( *((short *)buf_p) );
|
||||
buf_p += 2;
|
||||
targa_header.colormap_length = LittleShort ( *((short *)buf_p) );
|
||||
buf_p += 2;
|
||||
targa_header.colormap_size = *buf_p++ / 8;
|
||||
targa_header.x_origin = LittleShort ( *((short *)buf_p) );
|
||||
buf_p += 2;
|
||||
targa_header.y_origin = LittleShort ( *((short *)buf_p) );
|
||||
buf_p += 2;
|
||||
targa_header.width = LittleShort ( *((short *)buf_p) );
|
||||
buf_p += 2;
|
||||
targa_header.height = LittleShort ( *((short *)buf_p) );
|
||||
buf_p += 2;
|
||||
targa_header.pixel_size = *buf_p++;
|
||||
targa_header.attributes = *buf_p++;
|
||||
|
||||
if (targa_header.image_type!=1
|
||||
&& targa_header.image_type!=2
|
||||
&& targa_header.image_type!=10)
|
||||
{
|
||||
cgi.DPrintf("LoadTGA: Only type 1, 2 and 10 targa RGB images supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( (targa_header.colormap_type !=0 && targa_header.colormap_type !=1)
|
||||
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24 && targa_header.pixel_size!=8))
|
||||
{
|
||||
cgi.DPrintf("LoadTGA: Only 24, 32 and colormap images supported (no colormaps)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
columns = targa_header.width;
|
||||
rows = targa_header.height;
|
||||
numPixels = columns * rows;
|
||||
|
||||
if (width)
|
||||
*width = columns;
|
||||
if (height)
|
||||
*height = rows;
|
||||
|
||||
targa_rgba = ( byte * )cgi.Malloc( numPixels * 4 );
|
||||
*pic = targa_rgba;
|
||||
|
||||
if (targa_header.id_length != 0)
|
||||
buf_p += targa_header.id_length; // skip TARGA image comment
|
||||
|
||||
for (i=0;i<targa_header.colormap_length;i++)
|
||||
{
|
||||
|
||||
byte blue = *buf_p++;
|
||||
byte green = *buf_p++;
|
||||
byte red = *buf_p++;
|
||||
byte alpha = 0xff;
|
||||
|
||||
if (targa_header.colormap_size == 4)
|
||||
alpha = *buf_p++;
|
||||
|
||||
targa_palette[i*4+0] = red;
|
||||
targa_palette[i*4+1] = green;
|
||||
targa_palette[i*4+2] = blue;
|
||||
targa_palette[i*4+3] = alpha;
|
||||
if (alpha != 0xff)
|
||||
*hasalpha = true;
|
||||
}
|
||||
|
||||
if (targa_header.image_type==1)
|
||||
{
|
||||
for(row=rows-1; row>=0; row--)
|
||||
{
|
||||
pixbuf = targa_rgba + row*columns;
|
||||
for(column=0; column<columns; column++)
|
||||
{
|
||||
switch (targa_header.pixel_size)
|
||||
{
|
||||
case 8:
|
||||
*pixbuf++ = targa_palette[ *buf_p * 4 + 0];
|
||||
*pixbuf++ = targa_palette[ *buf_p * 4 + 1];
|
||||
*pixbuf++ = targa_palette[ *buf_p * 4 + 2];
|
||||
*pixbuf++ = targa_palette[ *buf_p * 4 + 3];
|
||||
buf_p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targa_header.image_type==2) { // Uncompressed, RGB images
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; column++) {
|
||||
unsigned char red,green,blue,alphabyte;
|
||||
switch (targa_header.pixel_size) {
|
||||
case 24:
|
||||
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
if (alphabyte != 0xff)
|
||||
*hasalpha = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (targa_header.image_type==10) { // Runlength encoded RGB images
|
||||
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
|
||||
for(row=rows-1; row>=0; row--) {
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
for(column=0; column<columns; ) {
|
||||
packetHeader= *buf_p++;
|
||||
packetSize = 1 + (packetHeader & 0x7f);
|
||||
if (packetHeader & 0x80) { // run-length packet
|
||||
switch (targa_header.pixel_size) {
|
||||
case 32:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = *buf_p++;
|
||||
if (alphabyte != 0xff)
|
||||
*hasalpha = true;
|
||||
break;
|
||||
case 24:
|
||||
default:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = 255;
|
||||
break;
|
||||
}
|
||||
|
||||
for(j=0;j<packetSize;j++) {
|
||||
*pixbuf++=red;
|
||||
*pixbuf++=green;
|
||||
*pixbuf++=blue;
|
||||
*pixbuf++=alphabyte;
|
||||
column++;
|
||||
if (column==columns) { // run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // non run-length packet
|
||||
for(j=0;j<packetSize;j++) {
|
||||
switch (targa_header.pixel_size) {
|
||||
default:
|
||||
case 24:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = 255;
|
||||
break;
|
||||
case 32:
|
||||
blue = *buf_p++;
|
||||
green = *buf_p++;
|
||||
red = *buf_p++;
|
||||
alphabyte = *buf_p++;
|
||||
*pixbuf++ = red;
|
||||
*pixbuf++ = green;
|
||||
*pixbuf++ = blue;
|
||||
*pixbuf++ = alphabyte;
|
||||
if (alphabyte != 0xff)
|
||||
*hasalpha = true;
|
||||
break;
|
||||
}
|
||||
column++;
|
||||
if (column==columns) { // pixel packet run spans across rows
|
||||
column=0;
|
||||
if (row>0)
|
||||
row--;
|
||||
else
|
||||
goto breakOut;
|
||||
pixbuf = targa_rgba + row*columns*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
breakOut:;
|
||||
}
|
||||
}
|
||||
cgi.FS_FreeFile( buffer );
|
||||
return true;
|
||||
}
|
||||
|
||||
void createLightstyleFromTGA( int num, const char *filename )
|
||||
{
|
||||
byte *data=0;
|
||||
int i, j, width, height;
|
||||
qboolean hasalpha;
|
||||
|
||||
if (!LoadTGA(filename, &data, &width, &height, &hasalpha))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( width > MAX_LIGHTSTYLE_LENGTH )
|
||||
{
|
||||
cgi.DPrintf("createLightstyleFromTGA: Light style too large, truncating.\n",filename);
|
||||
width = MAX_LIGHTSTYLE_LENGTH;
|
||||
}
|
||||
|
||||
strncpy( cg_lightstyle[ num ].name, filename, MAX_LIGHTSTYLE_NAME_LENGTH );
|
||||
cg_lightstyle[ num ].hasalpha = hasalpha;
|
||||
cg_lightstyle[ num ].length = width;
|
||||
|
||||
for( i = 0; i < width; i++ )
|
||||
{
|
||||
for ( j = 0; j < 4; j++ )
|
||||
{
|
||||
cg_lightstyle[ num ].map[ i ][ j ] = ( float )data[ ( i * 4 ) + j ] / 255.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if ( data )
|
||||
cgi.Free( data );
|
||||
}
|
||||
|
||||
void CG_SetLightStyle( int num, const char *s )
|
||||
{
|
||||
const char *r, *g, *b, *a;
|
||||
int j, k, n;
|
||||
size_t len;
|
||||
float t;
|
||||
|
||||
if ( ( num < 0 ) || ( num >= ( MAX_LIGHTSTYLES * 2 ) ) )
|
||||
{
|
||||
cgi.DPrintf ("CG_SetLightStyle: num out of range.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen( s );
|
||||
|
||||
if ( !Q_stricmp( &s[ len - 4 ], ".tga" ) )
|
||||
{
|
||||
createLightstyleFromTGA( num, s );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !s )
|
||||
return;
|
||||
|
||||
r = strchr( s, 'R' );
|
||||
g = strchr( s, 'G' );
|
||||
b = strchr( s, 'B' );
|
||||
a = strchr( s, 'A' );
|
||||
|
||||
n = 0;
|
||||
if (r)
|
||||
n++;
|
||||
if (g)
|
||||
n++;
|
||||
if (b)
|
||||
n++;
|
||||
if (a)
|
||||
n++;
|
||||
if (!n)
|
||||
n++;
|
||||
|
||||
if (!a)
|
||||
cg_lightstyle[ num ].hasalpha = false;
|
||||
else
|
||||
cg_lightstyle[ num ].hasalpha = true;
|
||||
|
||||
j = strlen (s) / n;
|
||||
if (j >= MAX_LIGHTSTYLE_LENGTH)
|
||||
{
|
||||
cgi.DPrintf ( "svc_lightstyle length=%i", j);
|
||||
j = MAX_LIGHTSTYLE_LENGTH - 1;
|
||||
}
|
||||
|
||||
if ( !r && !g && !b && !a )
|
||||
{
|
||||
cg_lightstyle[ num ].length = j;
|
||||
for( k = 0; k < j; k++ )
|
||||
{
|
||||
t = ( float )( s[ k ] - 'a' ) * 127.5f / 12.5;
|
||||
if ( t > 255 )
|
||||
{
|
||||
t = 255.0f;
|
||||
}
|
||||
cg_lightstyle[ num ].map[ k ][ 0 ] = t / 255.0f;
|
||||
cg_lightstyle[ num ].map[ k ][ 1 ] = t / 255.0f;
|
||||
cg_lightstyle[ num ].map[ k ][ 2 ] = t / 255.0f;
|
||||
cg_lightstyle[ num ].map[ k ][ 3 ] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
n = 0;
|
||||
// red
|
||||
k = 0;
|
||||
t = 0;
|
||||
if ( r )
|
||||
{
|
||||
r++;
|
||||
while( ( r[ k ] >= 'a' ) && ( r[ k ] <= 'z' ) )
|
||||
{
|
||||
t = ( float )( r[ k ] - 'a' ) * 127.5f / 12.5;
|
||||
if ( t > 255 )
|
||||
{
|
||||
t = 255.0f;
|
||||
}
|
||||
cg_lightstyle[ num ].map[ k ][ 0 ] = t / 255.0f;
|
||||
k++;
|
||||
}
|
||||
n = k;
|
||||
}
|
||||
while( k < MAX_LIGHTSTYLE_LENGTH )
|
||||
{
|
||||
cg_lightstyle[ num ].map[ k++ ][ 0 ] = t / 255.0f;
|
||||
}
|
||||
|
||||
// green
|
||||
k = 0;
|
||||
t = 0;
|
||||
if ( g )
|
||||
{
|
||||
g++;
|
||||
while( ( g[ k ] >= 'a' ) && ( g[ k ] <= 'z' ) )
|
||||
{
|
||||
t = ( float )( g[ k ] - 'a' ) * 127.5f / 12.5;
|
||||
if ( t > 255 )
|
||||
{
|
||||
t = 255.0f;
|
||||
}
|
||||
cg_lightstyle[ num ].map[ k ][ 1 ] = t / 255.0f;
|
||||
k++;
|
||||
}
|
||||
n = Q_max( n, k );
|
||||
}
|
||||
while( k < MAX_LIGHTSTYLE_LENGTH )
|
||||
{
|
||||
cg_lightstyle[ num ].map[ k++ ][ 1 ] = t / 255.0f;
|
||||
}
|
||||
|
||||
// blue
|
||||
k = 0;
|
||||
t = 0;
|
||||
if ( b )
|
||||
{
|
||||
b++;
|
||||
while( ( b[ k ] >= 'a' ) && ( b[ k ] <= 'z' ) )
|
||||
{
|
||||
t = ( float )( b[ k ] - 'a' ) * 127.5f / 12.5;
|
||||
if ( t > 255 )
|
||||
{
|
||||
t = 255.0f;
|
||||
}
|
||||
cg_lightstyle[ num ].map[ k ][ 2 ] = t / 255.0f;
|
||||
k++;
|
||||
}
|
||||
n = Q_max( n, k );
|
||||
}
|
||||
while( k < MAX_LIGHTSTYLE_LENGTH )
|
||||
{
|
||||
cg_lightstyle[ num ].map[ k++ ][ 2 ] = t / 255.0f;
|
||||
}
|
||||
|
||||
// alpha
|
||||
k = 0;
|
||||
t = 255;
|
||||
if ( a )
|
||||
{
|
||||
a++;
|
||||
while( ( a[ k ] >= 'a' ) && ( a[ k ] <= 'z' ) )
|
||||
{
|
||||
t = ( float )( a[ k ] - 'a' ) * 127.5f / 25;
|
||||
if ( t > 255 )
|
||||
{
|
||||
t = 255.0f;
|
||||
}
|
||||
cg_lightstyle[ num ].map[ k ][ 3 ] = t / 255.0f;
|
||||
k++;
|
||||
}
|
||||
n = Q_max( n, k );
|
||||
}
|
||||
while( k < MAX_LIGHTSTYLE_LENGTH )
|
||||
{
|
||||
cg_lightstyle[ num ].map[ k++ ][ 3 ] = t / 255.0f;
|
||||
}
|
||||
|
||||
cg_lightstyle[ num ].length = n;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_GetLightStyle
|
||||
================
|
||||
*/
|
||||
int CG_GetLightStyle( const char * name )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = MAX_LIGHTSTYLES; i < MAX_LIGHTSTYLES * 2; i++ )
|
||||
{
|
||||
if ( !Q_stricmp( cg_lightstyle[ i ].name, name ) )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_GetFreeLightStyle
|
||||
================
|
||||
*/
|
||||
int CG_GetFreeLightStyle( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = MAX_LIGHTSTYLES; i < MAX_LIGHTSTYLES * 2; i++ )
|
||||
{
|
||||
if ( !cg_lightstyle[ i ].name[ 0 ] )
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_ClearLightStyles
|
||||
================
|
||||
*/
|
||||
void CG_ClearLightStyles( void )
|
||||
{
|
||||
memset( cg_lightstyle, 0, sizeof( cg_lightstyle ) );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_RegisterLightStyle
|
||||
================
|
||||
*/
|
||||
int CG_RegisterLightStyle( const char * name )
|
||||
{
|
||||
int num;
|
||||
|
||||
num = CG_GetLightStyle( name );
|
||||
if ( num == -1 )
|
||||
{
|
||||
num = CG_GetFreeLightStyle();
|
||||
if ( num != -1 )
|
||||
{
|
||||
CG_SetLightStyle( num, name );
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.DPrintf ("CG_RegisterLightStyle: no free spots for lightstyle %s.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
+675
-769
File diff suppressed because it is too large.
Load diff
@@ -1,683 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
|
||||
// cg_localents.c -- every frame, generate renderer commands for locally
|
||||
// processed entities, like smoke puffs, gibs, shells, etc.
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
#define MAX_LOCAL_ENTITIES 512
|
||||
localEntity_t cg_localEntities[MAX_LOCAL_ENTITIES];
|
||||
localEntity_t cg_activeLocalEntities; // double linked list
|
||||
localEntity_t *cg_freeLocalEntities; // single linked list
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_InitLocalEntities
|
||||
|
||||
This is called at startup and for tournement restarts
|
||||
===================
|
||||
*/
|
||||
void CG_InitLocalEntities( void ) {
|
||||
int i;
|
||||
|
||||
memset( cg_localEntities, 0, sizeof( cg_localEntities ) );
|
||||
cg_activeLocalEntities.next = &cg_activeLocalEntities;
|
||||
cg_activeLocalEntities.prev = &cg_activeLocalEntities;
|
||||
cg_freeLocalEntities = cg_localEntities;
|
||||
for ( i = 0 ; i < MAX_LOCAL_ENTITIES - 1 ; i++ ) {
|
||||
cg_localEntities[i].next = &cg_localEntities[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_FreeLocalEntity
|
||||
==================
|
||||
*/
|
||||
void CG_FreeLocalEntity( localEntity_t *le ) {
|
||||
if ( !le->prev ) {
|
||||
CG_Error( "CG_FreeLocalEntity: not active" );
|
||||
}
|
||||
|
||||
// remove from the doubly linked active list
|
||||
le->prev->next = le->next;
|
||||
le->next->prev = le->prev;
|
||||
|
||||
// the free list is only singly linked
|
||||
le->next = cg_freeLocalEntities;
|
||||
cg_freeLocalEntities = le;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AllocLocalEntity
|
||||
|
||||
Will allways succeed, even if it requires freeing an old active entity
|
||||
===================
|
||||
*/
|
||||
localEntity_t *CG_AllocLocalEntity( void ) {
|
||||
localEntity_t *le;
|
||||
|
||||
if ( !cg_freeLocalEntities ) {
|
||||
// no free entities, so free the one at the end of the chain
|
||||
// remove the oldest active entity
|
||||
CG_FreeLocalEntity( cg_activeLocalEntities.prev );
|
||||
}
|
||||
|
||||
le = cg_freeLocalEntities;
|
||||
cg_freeLocalEntities = cg_freeLocalEntities->next;
|
||||
|
||||
memset( le, 0, sizeof( *le ) );
|
||||
|
||||
// link into the active list
|
||||
le->next = cg_activeLocalEntities.next;
|
||||
le->prev = &cg_activeLocalEntities;
|
||||
cg_activeLocalEntities.next->prev = le;
|
||||
cg_activeLocalEntities.next = le;
|
||||
return le;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================================================================================
|
||||
|
||||
FRAGMENT PROCESSING
|
||||
|
||||
A fragment localentity interacts with the environment in some way (hitting walls),
|
||||
or generates more localentities along a trail.
|
||||
|
||||
====================================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
================
|
||||
CG_BloodTrail
|
||||
|
||||
Leave expanding blood puffs behind gibs
|
||||
================
|
||||
*/
|
||||
void CG_BloodTrail( localEntity_t *le ) {
|
||||
//int t;
|
||||
//int t2;
|
||||
//int step;
|
||||
//vec3_t newOrigin;
|
||||
//localEntity_t *blood;
|
||||
|
||||
//step = 150;
|
||||
//t = step * ( (cg.time - cg.frametime + step ) / step );
|
||||
//t2 = step * ( cg.time / step );
|
||||
|
||||
//for ( ; t <= t2; t += step ) {
|
||||
// BG_EvaluateTrajectory( &le->pos, t, newOrigin );
|
||||
|
||||
// blood = CG_SmokePuff( newOrigin, vec3_origin,
|
||||
// 20, // radius
|
||||
// 1, 1, 1, 1, // color
|
||||
// 2000, // trailTime
|
||||
// t, // startTime
|
||||
// 0, // fadeInTime
|
||||
// 0, // flags
|
||||
// cgs.media.bloodTrailShader );
|
||||
// // use the optimized version
|
||||
// blood->leType = LE_FALL_SCALE_FADE;
|
||||
// // drop a total of 40 units over its lifetime
|
||||
// blood->pos.trDelta[2] = 40;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FragmentBounceMark
|
||||
================
|
||||
*/
|
||||
void CG_FragmentBounceMark( localEntity_t *le, trace_t *trace ) {
|
||||
//int radius;
|
||||
|
||||
//if ( le->leMarkType == LEMT_BLOOD ) {
|
||||
|
||||
// radius = 16 + (rand()&31);
|
||||
// CG_ImpactMark( cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random()*360,
|
||||
// 1,1,1,1, qtrue, radius, qfalse );
|
||||
//} else if ( le->leMarkType == LEMT_BURN ) {
|
||||
|
||||
// radius = 8 + (rand()&15);
|
||||
// CG_ImpactMark( cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random()*360,
|
||||
// 1,1,1,1, qtrue, radius, qfalse );
|
||||
//}
|
||||
|
||||
|
||||
//// don't allow a fragment to make multiple marks, or they
|
||||
//// pile up while settling
|
||||
//le->leMarkType = LEMT_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_FragmentBounceSound
|
||||
================
|
||||
*/
|
||||
void CG_FragmentBounceSound( localEntity_t *le, trace_t *trace ) {
|
||||
// don't allow a fragment to make multiple bounce sounds,
|
||||
// or it gets too noisy as they settle
|
||||
le->leBounceSoundType = LEBS_NONE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_ReflectVelocity
|
||||
================
|
||||
*/
|
||||
void CG_ReflectVelocity( localEntity_t *le, trace_t *trace ) {
|
||||
vec3_t velocity;
|
||||
float dot;
|
||||
int hitTime;
|
||||
|
||||
// reflect the velocity on the trace plane
|
||||
hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
|
||||
BG_EvaluateTrajectoryDelta( &le->pos, hitTime, velocity );
|
||||
dot = DotProduct( velocity, trace->plane.normal );
|
||||
VectorMA( velocity, -2*dot, trace->plane.normal, le->pos.trDelta );
|
||||
|
||||
VectorScale( le->pos.trDelta, le->bounceFactor, le->pos.trDelta );
|
||||
|
||||
VectorCopy( trace->endpos, le->pos.trDelta );
|
||||
le->pos.trTime = cg.time;
|
||||
|
||||
|
||||
// check for stop, making sure that even on low FPS systems it doesn't bobble
|
||||
if ( trace->allsolid ||
|
||||
( trace->plane.normal[2] > 0 &&
|
||||
( le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2] ) ) ) {
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_AddFragment
|
||||
================
|
||||
*/
|
||||
void CG_AddFragment( localEntity_t *le ) {
|
||||
vec3_t newOrigin;
|
||||
trace_t trace;
|
||||
refEntity_t *e;
|
||||
tiki_t *tiki;
|
||||
|
||||
// if that's a tiki, we need to animate it
|
||||
if(le->tiki) {
|
||||
float time = 0;
|
||||
int anim = 0;
|
||||
e = &le->refEntity;
|
||||
tiki = le->tiki;
|
||||
e->bones = cgi.TIKI_GetBones(tiki->numBones);
|
||||
cgi.TIKI_AppendFrameBoundsAndRadius(tiki,anim,time,&e->radius,e->bounds);
|
||||
cgi.TIKI_SetChannels(tiki,anim,time,1,e->bones);
|
||||
cgi.TIKI_Animate(tiki,e->bones);
|
||||
}
|
||||
|
||||
// calculate new position
|
||||
BG_EvaluateTrajectory( &le->pos, cg.time, newOrigin );
|
||||
|
||||
// trace a line from previous position to new position
|
||||
CG_Trace( &trace, le->refEntity.origin, NULL, NULL, newOrigin, -1, CONTENTS_SOLID );
|
||||
if ( trace.fraction == 1.0 ) {
|
||||
// still in free fall
|
||||
VectorCopy( newOrigin, le->refEntity.origin );
|
||||
|
||||
if ( le->leFlags & LEF_TUMBLE ) {
|
||||
vec3_t angles;
|
||||
|
||||
BG_EvaluateTrajectory( &le->angles, cg.time, angles );
|
||||
AnglesToAxis( angles, le->refEntity.axis );
|
||||
}
|
||||
cgi.R_AddRefEntityToScene( &le->refEntity );
|
||||
|
||||
// add a blood trail
|
||||
if ( le->leBounceSoundType == LEBS_BLOOD ) {
|
||||
CG_BloodTrail( le );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// if it is in a nodrop zone, remove it
|
||||
// this keeps gibs from waiting at the bottom of pits of death
|
||||
// and floating levels
|
||||
if ( cgi.CM_PointContents( trace.endpos, 0 ) & CONTENTS_NODROP ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
// leave a mark
|
||||
CG_FragmentBounceMark( le, &trace );
|
||||
|
||||
// do a bouncy sound
|
||||
CG_FragmentBounceSound( le, &trace );
|
||||
|
||||
// reflect the velocity on the trace plane
|
||||
CG_ReflectVelocity( le, &trace );
|
||||
|
||||
cgi.R_AddRefEntityToScene( &le->refEntity );
|
||||
}
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
|
||||
TRIVIAL LOCAL ENTITIES
|
||||
|
||||
These only do simple scaling or modulation before passing to the renderer
|
||||
=====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_AddFadeRGB
|
||||
====================
|
||||
*/
|
||||
void CG_AddFadeRGB( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
c = ( le->endTime - cg.time ) * le->lifeRate;
|
||||
c *= 0xff;
|
||||
|
||||
re->shaderRGBA[0] = le->color[0] * c;
|
||||
re->shaderRGBA[1] = le->color[1] * c;
|
||||
re->shaderRGBA[2] = le->color[2] * c;
|
||||
re->shaderRGBA[3] = le->color[3] * c;
|
||||
|
||||
cgi.R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_AddMoveScaleFade
|
||||
==================
|
||||
*/
|
||||
static void CG_AddMoveScaleFade( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
vec3_t delta;
|
||||
float len;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
if ( le->fadeInTime > le->startTime && cg.time < le->fadeInTime ) {
|
||||
// fade / grow time
|
||||
c = 1.0 - (float) ( le->fadeInTime - cg.time ) / ( le->fadeInTime - le->startTime );
|
||||
}
|
||||
else {
|
||||
// fade / grow time
|
||||
c = ( le->endTime - cg.time ) * le->lifeRate;
|
||||
}
|
||||
|
||||
re->shaderRGBA[3] = 0xff * c * le->color[3];
|
||||
|
||||
if ( !( le->leFlags & LEF_PUFF_DONT_SCALE ) ) {
|
||||
re->radius = le->radius * ( 1.0 - c ) + 8;
|
||||
}
|
||||
|
||||
BG_EvaluateTrajectory( &le->pos, cg.time, re->origin );
|
||||
|
||||
// if the view would be "inside" the sprite, kill the sprite
|
||||
// so it doesn't add too much overdraw
|
||||
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
|
||||
len = VectorLength( delta );
|
||||
if ( len < le->radius ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AddScaleFade
|
||||
|
||||
For rocket smokes that hang in place, fade out, and are
|
||||
removed if the view passes through them.
|
||||
There are often many of these, so it needs to be simple.
|
||||
===================
|
||||
*/
|
||||
static void CG_AddScaleFade( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
vec3_t delta;
|
||||
float len;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
// fade / grow time
|
||||
c = ( le->endTime - cg.time ) * le->lifeRate;
|
||||
|
||||
re->shaderRGBA[3] = 0xff * c * le->color[3];
|
||||
re->radius = le->radius * ( 1.0 - c ) + 8;
|
||||
|
||||
// if the view would be "inside" the sprite, kill the sprite
|
||||
// so it doesn't add too much overdraw
|
||||
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
|
||||
len = VectorLength( delta );
|
||||
if ( len < le->radius ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_AddFallScaleFade
|
||||
|
||||
This is just an optimized CG_AddMoveScaleFade
|
||||
For blood mists that drift down, fade out, and are
|
||||
removed if the view passes through them.
|
||||
There are often 100+ of these, so it needs to be simple.
|
||||
=================
|
||||
*/
|
||||
static void CG_AddFallScaleFade( localEntity_t *le ) {
|
||||
refEntity_t *re;
|
||||
float c;
|
||||
vec3_t delta;
|
||||
float len;
|
||||
|
||||
re = &le->refEntity;
|
||||
|
||||
// fade time
|
||||
c = ( le->endTime - cg.time ) * le->lifeRate;
|
||||
|
||||
re->shaderRGBA[3] = 0xff * c * le->color[3];
|
||||
|
||||
re->origin[ 2 ] = le->pos.trDelta[ 2 ] - ( 1.0 - c ) * le->pos.trDelta[ 2 ];
|
||||
|
||||
re->radius = le->radius * ( 1.0 - c ) + 16;
|
||||
|
||||
// if the view would be "inside" the sprite, kill the sprite
|
||||
// so it doesn't add too much overdraw
|
||||
VectorSubtract( re->origin, cg.refdef.vieworg, delta );
|
||||
len = VectorLength( delta );
|
||||
if ( len < le->radius ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.R_AddRefEntityToScene( re );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_AddExplosion
|
||||
================
|
||||
*/
|
||||
static void CG_AddExplosion( localEntity_t *ex ) {
|
||||
refEntity_t *ent;
|
||||
|
||||
ent = &ex->refEntity;
|
||||
|
||||
// add the entity
|
||||
cgi.R_AddRefEntityToScene(ent);
|
||||
|
||||
// add the dlight
|
||||
if ( ex->light ) {
|
||||
float light;
|
||||
|
||||
light = (float)( cg.time - ex->startTime ) / ( ex->endTime - ex->startTime );
|
||||
if ( light < 0.5 ) {
|
||||
light = 1.0;
|
||||
} else {
|
||||
light = 1.0 - ( light - 0.5 ) * 2;
|
||||
}
|
||||
light = ex->light * light;
|
||||
cgi.R_AddLightToScene(ent->origin, light, ex->lightColor[0], ex->lightColor[1], ex->lightColor[2] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_AddSpriteExplosion
|
||||
================
|
||||
*/
|
||||
static void CG_AddSpriteExplosion( localEntity_t *le ) {
|
||||
refEntity_t re;
|
||||
float c;
|
||||
|
||||
re = le->refEntity;
|
||||
|
||||
c = ( le->endTime - cg.time ) / ( float ) ( le->endTime - le->startTime );
|
||||
if ( c > 1 ) {
|
||||
c = 1.0; // can happen during connection problems
|
||||
}
|
||||
|
||||
re.shaderRGBA[0] = 0xff;
|
||||
re.shaderRGBA[1] = 0xff;
|
||||
re.shaderRGBA[2] = 0xff;
|
||||
re.shaderRGBA[3] = 0xff * c * 0.33;
|
||||
|
||||
re.reType = RT_SPRITE;
|
||||
re.radius = 42 * ( 1.0 - c ) + 30;
|
||||
|
||||
cgi.R_AddRefEntityToScene( &re );
|
||||
|
||||
// add the dlight
|
||||
if ( le->light ) {
|
||||
float light;
|
||||
|
||||
light = (float)( cg.time - le->startTime ) / ( le->endTime - le->startTime );
|
||||
if ( light < 0.5 ) {
|
||||
light = 1.0;
|
||||
} else {
|
||||
light = 1.0 - ( light - 0.5 ) * 2;
|
||||
}
|
||||
light = le->light * light;
|
||||
cgi.R_AddLightToScene(re.origin, light, le->lightColor[0], le->lightColor[1], le->lightColor[2] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AddScorePlum
|
||||
===================
|
||||
*/
|
||||
#define NUMBER_SIZE 8
|
||||
|
||||
void CG_AddScorePlum( localEntity_t *le ) {
|
||||
//refEntity_t *re;
|
||||
//vec3_t origin, delta, dir, vec, up = {0, 0, 1};
|
||||
//float c, len;
|
||||
//int i, score, digits[10], numdigits, negative;
|
||||
|
||||
//re = &le->refEntity;
|
||||
|
||||
//c = ( le->endTime - cg.time ) * le->lifeRate;
|
||||
|
||||
//score = le->radius;
|
||||
//if (score < 0) {
|
||||
// re->shaderRGBA[0] = 0xff;
|
||||
// re->shaderRGBA[1] = 0x11;
|
||||
// re->shaderRGBA[2] = 0x11;
|
||||
//}
|
||||
//else {
|
||||
// re->shaderRGBA[0] = 0xff;
|
||||
// re->shaderRGBA[1] = 0xff;
|
||||
// re->shaderRGBA[2] = 0xff;
|
||||
// if (score >= 50) {
|
||||
// re->shaderRGBA[1] = 0;
|
||||
// } else if (score >= 20) {
|
||||
// re->shaderRGBA[0] = re->shaderRGBA[1] = 0;
|
||||
// } else if (score >= 10) {
|
||||
// re->shaderRGBA[2] = 0;
|
||||
// } else if (score >= 2) {
|
||||
// re->shaderRGBA[0] = re->shaderRGBA[2] = 0;
|
||||
// }
|
||||
|
||||
//}
|
||||
//if (c < 0.25)
|
||||
// re->shaderRGBA[3] = 0xff * 4 * c;
|
||||
//else
|
||||
// re->shaderRGBA[3] = 0xff;
|
||||
|
||||
//re->radius = NUMBER_SIZE / 2;
|
||||
|
||||
//VectorCopy(le->pos.trBase, origin);
|
||||
//origin[2] += 110 - c * 100;
|
||||
|
||||
//VectorSubtract(cg.refdef.vieworg, origin, dir);
|
||||
//CrossProduct(dir, up, vec);
|
||||
//VectorNormalize(vec);
|
||||
|
||||
//VectorMA(origin, -10 + 20 * sin(c * 2 * M_PI), vec, origin);
|
||||
|
||||
//// if the view would be "inside" the sprite, kill the sprite
|
||||
//// so it doesn't add too much overdraw
|
||||
//VectorSubtract( origin, cg.refdef.vieworg, delta );
|
||||
//len = VectorLength( delta );
|
||||
//if ( len < 20 ) {
|
||||
// CG_FreeLocalEntity( le );
|
||||
// return;
|
||||
//}
|
||||
|
||||
//negative = qfalse;
|
||||
//if (score < 0) {
|
||||
// negative = qtrue;
|
||||
// score = -score;
|
||||
//}
|
||||
|
||||
//for (numdigits = 0; !(numdigits && !score); numdigits++) {
|
||||
// digits[numdigits] = score % 10;
|
||||
// score = score / 10;
|
||||
//}
|
||||
|
||||
//if (negative) {
|
||||
// digits[numdigits] = 10;
|
||||
// numdigits++;
|
||||
//}
|
||||
|
||||
//for (i = 0; i < numdigits; i++) {
|
||||
// VectorMA(origin, (float) (((float) numdigits / 2) - i) * NUMBER_SIZE, vec, re->origin);
|
||||
// re->customShader = cgs.media.numberShaders[digits[numdigits-1-i]];
|
||||
// cgi.R_AddRefEntityToScene( re );
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//==============================================================================
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_AddLocalEntities
|
||||
|
||||
===================
|
||||
*/
|
||||
void CG_AddLocalEntities( void ) {
|
||||
localEntity_t *le, *next;
|
||||
|
||||
// walk the list backwards, so any new local entities generated
|
||||
// (trails, marks, etc) will be present this frame
|
||||
le = cg_activeLocalEntities.prev;
|
||||
for ( ; le != &cg_activeLocalEntities ; le = next ) {
|
||||
// grab next now, so if the local entity is freed we
|
||||
// still have it
|
||||
next = le->prev;
|
||||
|
||||
if ( cg.time >= le->endTime ) {
|
||||
CG_FreeLocalEntity( le );
|
||||
continue;
|
||||
}
|
||||
switch ( le->leType ) {
|
||||
default:
|
||||
CG_Error( "Bad leType: %i", le->leType );
|
||||
break;
|
||||
case LE_SKIP:
|
||||
// do nothing
|
||||
break;
|
||||
case LE_MARK:
|
||||
break;
|
||||
|
||||
case LE_SPRITE_EXPLOSION:
|
||||
CG_AddSpriteExplosion( le );
|
||||
break;
|
||||
|
||||
case LE_EXPLOSION:
|
||||
CG_AddExplosion( le );
|
||||
break;
|
||||
|
||||
case LE_FRAGMENT: // gibs and brass
|
||||
CG_AddFragment( le );
|
||||
break;
|
||||
|
||||
case LE_MOVE_SCALE_FADE: // water bubbles
|
||||
CG_AddMoveScaleFade( le );
|
||||
break;
|
||||
|
||||
case LE_FADE_RGB: // teleporters, railtrails
|
||||
CG_AddFadeRGB( le );
|
||||
break;
|
||||
|
||||
case LE_FALL_SCALE_FADE: // gib blood trails
|
||||
CG_AddFallScaleFade( le );
|
||||
break;
|
||||
|
||||
case LE_SCALE_FADE: // rocket trails
|
||||
CG_AddScaleFade( le );
|
||||
break;
|
||||
|
||||
case LE_SCOREPLUM:
|
||||
CG_AddScorePlum( le );
|
||||
break;
|
||||
|
||||
#ifdef MISSIONPACK
|
||||
case LE_KAMIKAZE:
|
||||
CG_AddKamikaze( le );
|
||||
break;
|
||||
case LE_INVULIMPACT:
|
||||
CG_AddInvulnerabilityImpact( le );
|
||||
break;
|
||||
case LE_INVULJUICED:
|
||||
CG_AddInvulnerabilityJuiced( le );
|
||||
break;
|
||||
case LE_SHOWREFENTITY:
|
||||
CG_AddRefEntity( le );
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+691
-677
File diff suppressed because it is too large.
Load diff
+346
-1905
File diff suppressed because it is too large.
Load diff
+1142
-304
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// Nature effects
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_commands.h"
|
||||
|
||||
cvar_t* cg_rain;
|
||||
cvar_t* cg_rain_drawcoverage;
|
||||
|
||||
void RainTouch(ctempmodel_t* ct, trace_t* trace)
|
||||
{
|
||||
Vector norm, neworg;
|
||||
|
||||
ct->ent.hModel = cgi.R_RegisterModel("splash_z.spr");
|
||||
ct->cgd.velocity = vec_zero;
|
||||
ct->cgd.accel = vec_zero;
|
||||
ct->killTime = cg.time + 400;
|
||||
norm = trace->plane.normal;
|
||||
norm.x = -norm.x;
|
||||
norm.y = -norm.y;
|
||||
ct->cgd.angles = norm.toAngles();
|
||||
ct->ent.scale = 0.3f;
|
||||
ct->cgd.scaleRate = 4.0;
|
||||
ct->cgd.flags |= T_FADE;
|
||||
|
||||
neworg = trace->endpos + norm * 0.2f;
|
||||
VectorCopy(neworg, ct->ent.origin);
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::RainTouch(Event* ev)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::InitializeRainCvars()
|
||||
{
|
||||
int i;
|
||||
|
||||
cg_rain = cgi.Cvar_Get("cg_rain", "0", CVAR_ARCHIVE);
|
||||
cg_rain_drawcoverage = cgi.Cvar_Get("cg_rain_drawcoverage", "0", CVAR_SAVEGAME | CVAR_SERVER_CREATED | CVAR_SYSTEMINFO);
|
||||
|
||||
cg.rain.density = 0.0;
|
||||
cg.rain.speed = 2048.0f;
|
||||
cg.rain.length = 90.0f;
|
||||
cg.rain.min_dist = 512.0f;
|
||||
cg.rain.width = 1.0f;
|
||||
cg.rain.speed_vary = 512;
|
||||
cg.rain.slant = 50;
|
||||
|
||||
for (i = 0; i < MAX_RAIN_SHADERS; i++) {
|
||||
cg.rain.shader[i][0] = 0;
|
||||
}
|
||||
|
||||
cg.rain.numshaders = 0;
|
||||
}
|
||||
|
||||
void CG_Rain(centity_t* cent)
|
||||
{
|
||||
int iLife;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t vOmins, vOmaxs, vOe;
|
||||
float fcolor[4];
|
||||
vec3_t vStart, vEnd;
|
||||
int iNumSpawn;
|
||||
int i;
|
||||
int iRandom;
|
||||
float fDensity;
|
||||
vec3_t vLength;
|
||||
const char* shadername;
|
||||
|
||||
fcolor[0] = 1.0;
|
||||
fcolor[1] = 1.0;
|
||||
fcolor[2] = 1.0;
|
||||
fcolor[3] = 1.0;
|
||||
|
||||
if (!cg_rain->integer || paused->integer) {
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.R_ModelBounds(cgs.inlineDrawModel[cent->currentState.modelindex], mins, maxs);
|
||||
|
||||
vOmins[0] = mins[0] + cent->lerpOrigin[0];
|
||||
if (vOmins[0] < cg.snap->ps.origin[0] - cg.rain.min_dist) {
|
||||
vOmins[0] = cg.snap->ps.origin[0] - cg.rain.min_dist;
|
||||
}
|
||||
|
||||
vOmins[1] = mins[1] + cent->lerpOrigin[1];
|
||||
if (vOmins[1] < cg.snap->ps.origin[1] - cg.rain.min_dist) {
|
||||
vOmins[1] = cg.snap->ps.origin[1] - cg.rain.min_dist;
|
||||
}
|
||||
|
||||
vOmins[2] = mins[2] + cent->lerpOrigin[2];
|
||||
|
||||
vOmaxs[0] = maxs[0] + cent->lerpOrigin[0];
|
||||
if (vOmaxs[0] > cg.rain.min_dist + cg.snap->ps.origin[0]) {
|
||||
vOmaxs[0] = cg.rain.min_dist + cg.snap->ps.origin[0];
|
||||
}
|
||||
|
||||
vOmaxs[1] = maxs[1] + cent->lerpOrigin[1];
|
||||
if (vOmaxs[1] > cg.rain.min_dist + cg.snap->ps.origin[1]) {
|
||||
vOmaxs[1] = cg.rain.min_dist + cg.snap->ps.origin[1];
|
||||
}
|
||||
|
||||
vOmaxs[2] = maxs[2] + cent->lerpOrigin[2];
|
||||
|
||||
if (vOmins[0] > vOmaxs[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (vOmins[1] > vOmaxs[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cg_rain_drawcoverage->integer)
|
||||
{
|
||||
cgi.R_DebugLine(
|
||||
Vector(vOmins[0], vOmins[1], vOmins[2]),
|
||||
Vector(vOmaxs[0], vOmins[1], vOmins[2]),
|
||||
1.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
cgi.R_DebugLine(
|
||||
Vector(vOmaxs[0], vOmins[1], vOmins[2]),
|
||||
Vector(vOmaxs[0], vOmaxs[1], vOmins[2]),
|
||||
1.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
cgi.R_DebugLine(
|
||||
Vector(vOmaxs[0], vOmaxs[1], vOmins[2]),
|
||||
Vector(vOmins[0], vOmaxs[1], vOmins[2]),
|
||||
1.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
|
||||
cgi.R_DebugLine(
|
||||
Vector(vOmins[0], vOmaxs[1], vOmins[2]),
|
||||
Vector(vOmins[0], vOmins[1], vOmins[2]),
|
||||
1.0, 0.0, 0.0, 1.0
|
||||
);
|
||||
}
|
||||
|
||||
VectorSubtract(vOmaxs, vOmins, vOe);
|
||||
fDensity = cg.rain.density / 200.0;
|
||||
iNumSpawn = (int)(sqrt(vOe[0] * vOe[1]) * fDensity);
|
||||
if (iNumSpawn > MAX_BEAMS) {
|
||||
iNumSpawn = MAX_BEAMS;
|
||||
}
|
||||
|
||||
iRandom = rand();
|
||||
|
||||
if (cg.rain.numshaders) {
|
||||
shadername = cg.rain.shader[iRandom % cg.rain.numshaders];
|
||||
}
|
||||
else {
|
||||
shadername = cg.rain.shader[0];
|
||||
}
|
||||
|
||||
for (i = 0; i < iNumSpawn; ++i)
|
||||
{
|
||||
iLife = (int)(vOe[2] / ((float)(iRandom % cg.rain.speed_vary) + cg.rain.speed) * 1000.0);
|
||||
vStart[0] = (float)(iRandom % (int)(vOe[0] + 1.0)) + vOmins[0];
|
||||
iRandom = ((214013 * iRandom + 2531011) >> 16) & 0x7FFF;
|
||||
vStart[1] = (float)(iRandom % (int)(vOe[1] + 1.0)) + vOmins[1];
|
||||
vStart[2] = vOmaxs[2];
|
||||
|
||||
if (cg.snap)
|
||||
{
|
||||
vLength[0] = cg.snap->ps.origin[0] - vStart[0];
|
||||
vLength[1] = cg.snap->ps.origin[1] - vStart[1];
|
||||
vLength[2] = 0.0;
|
||||
if (cg.rain.min_dist * cg.rain.min_dist < VectorLengthSquared(vLength)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
vEnd[0] = (float)(iRandom % cg.rain.slant) + vStart[0] + vss_wind_x->value;
|
||||
iRandom = ((214013 * iRandom + 2531011) >> 16) & 0x7FFF;
|
||||
vEnd[1] = (float)(iRandom % cg.rain.slant) + vStart[1] + vss_wind_y->value;
|
||||
vEnd[2] = vOmins[2];
|
||||
|
||||
CG_CreateBeam(
|
||||
vStart,
|
||||
vec_zero,
|
||||
0,
|
||||
1,
|
||||
1.0,
|
||||
cg.rain.width,
|
||||
BEAM_INVERTED_FAST,
|
||||
1000.0,
|
||||
iLife,
|
||||
qtrue,
|
||||
vEnd,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
shadername,
|
||||
fcolor,
|
||||
0,
|
||||
0.0,
|
||||
cg.rain.length,
|
||||
1.0,
|
||||
0,
|
||||
"raineffect"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,653 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 su44
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// cg_parsemsg.c
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
#define MAX_HDELEMENTS 256
|
||||
|
||||
hdelement_t hdelements[MAX_HDELEMENTS];
|
||||
|
||||
typedef struct {
|
||||
float i_vBarrel[3];
|
||||
float i_vStart[3];
|
||||
float (*i_vEnd)[3];
|
||||
int i_iNumBullets;
|
||||
qboolean iLarge;
|
||||
int iTracerVisible;
|
||||
qboolean bIgnoreEntities;
|
||||
} bullet_tracer_t;
|
||||
|
||||
#define MAX_IMPACTS 64
|
||||
#define MAX_BULLER_TRACERS 32
|
||||
#define MAX_BULLET_TRACE_BULLETS 1024
|
||||
|
||||
// bullet tracers
|
||||
static bullet_tracer_t bullet_tracers[MAX_BULLER_TRACERS];
|
||||
static int bullet_tracers_count;
|
||||
static float bullet_tracer_bullets[MAX_BULLET_TRACE_BULLETS][3];
|
||||
static int bullet_tracer_bullets_count;
|
||||
|
||||
// wall impacts
|
||||
static vec3_t wall_impact_pos[MAX_IMPACTS];
|
||||
static vec3_t wall_impact_norm[MAX_IMPACTS];
|
||||
static int wall_impact_large[MAX_IMPACTS];
|
||||
static int wall_impact_type[MAX_IMPACTS]; // 0,2,3,4,5
|
||||
static int wall_impact_count;
|
||||
// flesh impacts
|
||||
static vec3_t flesh_impact_pos[MAX_IMPACTS];
|
||||
static vec3_t flesh_impact_norm[MAX_IMPACTS];
|
||||
static int flesh_impact_large[MAX_IMPACTS];
|
||||
static int flesh_impact_type[MAX_IMPACTS];
|
||||
static int flesh_impact_count;
|
||||
|
||||
static int current_entity_number;
|
||||
|
||||
void CG_MakeBulletHole(float *i_vPos, float *i_vNorm, int iLarge,
|
||||
trace_t *pPreTrace, qboolean bMakeSound) {
|
||||
char *s;
|
||||
|
||||
#if 0
|
||||
// su44: make an "explosion" effect here so I can debug bullet holes coordinates
|
||||
CG_MakeExplosion(i_vPos,vec3_origin,0,cgi.R_RegisterShader("heavy_pipe"),250,qtrue);
|
||||
#endif
|
||||
s = "bhole_";
|
||||
|
||||
// TODO: choose an appropriate decal shader and play hit sound
|
||||
|
||||
CG_ImpactMark(cgi.R_RegisterShader("bhole_wood"),i_vPos,i_vNorm,0,1,1,1,1,qfalse,8,qfalse);
|
||||
}
|
||||
|
||||
void CG_AddBulletImpacts() {
|
||||
int i;
|
||||
char *s;
|
||||
int type;
|
||||
|
||||
for(i = 0; i < wall_impact_count; i++) {
|
||||
CG_MakeBulletHole(wall_impact_pos[i],wall_impact_norm[i],
|
||||
wall_impact_large[i],0,qtrue);
|
||||
|
||||
type = wall_impact_type[i];
|
||||
if(type) {
|
||||
if ( wall_impact_type[i] < 2 || wall_impact_type[i] > 3 )
|
||||
s = "snd_bh_metal";
|
||||
else
|
||||
s = "snd_bh_wood";
|
||||
//CG_PlaySound(s,wall_impact_pos[i],-1,
|
||||
}
|
||||
}
|
||||
for(i = 0; i < flesh_impact_count; i++) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void CG_MakeBubbleTrail(float *i_vStart, float *i_vEnd, int iLarge) {
|
||||
// TODO
|
||||
}
|
||||
// this is called from CG_MakeBulletTracerInternal
|
||||
static void CG_BulletTracerEffect(float *i_vStart, float *i_vEnd)
|
||||
{
|
||||
byte fTracerColor[4]; // su44: in MoHAA it was "float[4]"
|
||||
int iLife;
|
||||
vec3_t vNewStart;
|
||||
int v2;
|
||||
|
||||
VectorCopy(i_vStart,vNewStart);
|
||||
|
||||
v2 = 1;
|
||||
|
||||
iLife = 20;
|
||||
fTracerColor[0] = 255;
|
||||
fTracerColor[1] = 255;
|
||||
fTracerColor[2] = 255;
|
||||
fTracerColor[3] = 255;
|
||||
CG_CreateBeam(
|
||||
vNewStart, // start
|
||||
vec3_origin, // dir
|
||||
0, // owner
|
||||
1, // model
|
||||
1.0, // alpha
|
||||
1.0, // scale
|
||||
8192, // flags
|
||||
1000.0, // len
|
||||
iLife, // life
|
||||
1, // qboolean create
|
||||
i_vEnd, // endpointvec
|
||||
0, // min_ofs
|
||||
0, // maxs_ofs
|
||||
0, // overlap
|
||||
1, // numSubdivions
|
||||
0, // delay
|
||||
"tracer", // beamshadername
|
||||
fTracerColor, // modulate (in FAKK that's a byte[4], in MoH that's float[4])
|
||||
0, // numSphereBeams
|
||||
0.0, // sphereradius
|
||||
v2, //toggleDelay
|
||||
1.0, //endapha
|
||||
0, // renderfx
|
||||
"tracereffect"); // name
|
||||
}
|
||||
|
||||
static void CG_MakeBulletTracerInternal(float *i_vBarrel, float *i_vStart,
|
||||
float (*i_vEnd)[3], int i_iNumBullets, qboolean iLarge,
|
||||
int iTracerVisible, qboolean bIgnoreEntities) {
|
||||
trace_t tr;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < i_iNumBullets; i++) {
|
||||
CG_BulletTracerEffect(i_vBarrel,i_vEnd[i]);
|
||||
CG_Trace(&tr,i_vBarrel,vec3_origin,vec3_origin,i_vEnd[i],-1,MASK_SHOT);
|
||||
if(tr.fraction != 1.f && tr.allsolid == qfalse) {
|
||||
CG_MakeBulletHole(tr.endpos,tr.plane.normal,iLarge,&tr,qfalse);
|
||||
} else {
|
||||
// su44: it happens quite often. Is it a bug?
|
||||
//CG_Printf("CG_MakeBulletTracerInternal: missed\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void CG_MakeBulletTracer(float *i_vBarrel, float *i_vStart,
|
||||
float (*i_vEnd)[3], int i_iNumBullets, qboolean iLarge,
|
||||
int iTracerVisible, qboolean bIgnoreEntities) {
|
||||
bullet_tracer_t *bt;
|
||||
int i;
|
||||
if(bullet_tracers_count < MAX_BULLER_TRACERS) {
|
||||
if(i_iNumBullets + bullet_tracer_bullets_count < MAX_BULLET_TRACE_BULLETS) {
|
||||
bt = bullet_tracers + bullet_tracers_count;
|
||||
VectorCopy(i_vBarrel,bt->i_vBarrel);
|
||||
VectorCopy(i_vStart,bt->i_vStart);
|
||||
bt->i_vEnd = &bullet_tracer_bullets[bullet_tracer_bullets_count];
|
||||
bt->i_iNumBullets = i_iNumBullets;
|
||||
bt->iLarge = iLarge;
|
||||
bt->iTracerVisible = iTracerVisible;
|
||||
bt->bIgnoreEntities = bIgnoreEntities;
|
||||
bullet_tracers_count++;
|
||||
for(i = 0; i < i_iNumBullets; i++) {
|
||||
VectorCopy(i_vEnd[i],bullet_tracer_bullets[bullet_tracer_bullets_count]);
|
||||
bullet_tracer_bullets_count++;
|
||||
}
|
||||
} else {
|
||||
CG_Printf("CG_MakeBulletTracerInternal: MAX_BULLET_TRACE_BULLETS exceeded\n");
|
||||
}
|
||||
} else {
|
||||
CG_Printf("CG_MakeBulletTracer: MAX_BULLER_TRACERS exceeded\n");
|
||||
}
|
||||
}
|
||||
|
||||
// su44: this should be called after CG_AddPacketEntities and before CG_DrawActive
|
||||
void CG_AddBulletTracers() {
|
||||
int i;
|
||||
bullet_tracer_t *bt;
|
||||
|
||||
bt = bullet_tracers;
|
||||
for(i = 0; i < bullet_tracers_count; i++,bt++) {
|
||||
CG_MakeBulletTracerInternal(bt->i_vBarrel,bt->i_vStart,bt->i_vEnd,bt->i_iNumBullets,
|
||||
bt->iLarge,bt->iTracerVisible,bt->bIgnoreEntities);
|
||||
}
|
||||
bullet_tracers_count = 0;
|
||||
bullet_tracer_bullets_count = 0;
|
||||
}
|
||||
|
||||
static void CG_MakeExplosionEffect(float *vPos, int iType) {
|
||||
CG_MakeExplosion(vPos,vec3_origin,0,cgi.R_RegisterShader("gren_explosion"),1000,qtrue);
|
||||
}
|
||||
|
||||
static void CG_MakeEffect_Normal(int iEffect, vec3_t vPos, vec3_t vNormal) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
static void CG_SpawnEffectModel(const char *model, vec3_t origin) {
|
||||
localEntity_t *le;
|
||||
vec3_t spawnAngles = { 0, 0, 0 };
|
||||
qhandle_t h;
|
||||
|
||||
le = CG_AllocLocalEntity();
|
||||
le->endTime = cg.time + 5000;
|
||||
le->leType = LE_SKIP;
|
||||
le->pos.trTime = cg.time - (rand()&15);
|
||||
VectorCopy( origin, le->pos.trDelta );
|
||||
VectorCopy(origin,le->refEntity.origin);
|
||||
VectorCopy( spawnAngles, le->angles.trDelta );
|
||||
AnglesToAxis(spawnAngles,le->refEntity.axis);
|
||||
|
||||
h = cgi.R_RegisterModel(model);
|
||||
le->refEntity.model = h;
|
||||
le->leType = LE_FRAGMENT;
|
||||
le->tiki = cgi.TIKI_RegisterModel(model);
|
||||
}
|
||||
|
||||
void CG_HudDrawElements() {
|
||||
int i;
|
||||
hdelement_t *hdi;
|
||||
|
||||
//if ( cg_huddraw_force.integer || cg_hud.integer )
|
||||
{
|
||||
hdi = hdelements;
|
||||
for ( i = 0; i < MAX_HDELEMENTS; i++, hdi++ ) {
|
||||
if ( hdi->hShader || hdi->string[0] ) {
|
||||
if ( hdi->vColor[3] != 0.f ) {
|
||||
float x = hdi->iX;
|
||||
float y = hdi->iY;
|
||||
float w = hdi->iWidth;
|
||||
float h = hdi->iHeight;
|
||||
|
||||
if ( hdi->iHorizontalAlign == 1 ) {
|
||||
if ( hdi->bVirtualScreen )
|
||||
x = 320.f - w * 0.5f + x;
|
||||
else
|
||||
x = cgs.glconfig.vidWidth * 0.5f - w * 0.5f + x;
|
||||
} else {
|
||||
if ( hdi->iHorizontalAlign == 2 ) {
|
||||
if ( hdi->bVirtualScreen )
|
||||
x = x + 640.f;
|
||||
else
|
||||
x = cgs.glconfig.vidWidth + x;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hdi->iVerticalAlign == 1 ) {
|
||||
if ( hdi->bVirtualScreen )
|
||||
y = 240.f - h * 0.5f + y;
|
||||
else
|
||||
y = cgs.glconfig.vidHeight * 0.5f - h * 0.5f + y;
|
||||
} else {
|
||||
if ( hdi->iVerticalAlign == 2 ) {
|
||||
if ( hdi->bVirtualScreen )
|
||||
y = y + 480.f;
|
||||
else
|
||||
y = cgs.glconfig.vidHeight + y;
|
||||
}
|
||||
}
|
||||
|
||||
cgi.R_SetColor(hdi->vColor);
|
||||
|
||||
// su44: that's wrong
|
||||
if(hdi->bVirtualScreen) {
|
||||
if(x > 640)
|
||||
x -= 640;
|
||||
if(x < 0)
|
||||
x += 640;
|
||||
if(y > 480)
|
||||
y -= 480;
|
||||
if(y < 0)
|
||||
y += 480;
|
||||
}
|
||||
|
||||
if ( hdi->string[0] ) {
|
||||
if ( hdi->pFont.glyphs[0].glyph ) {
|
||||
cgi.R_Text_Paint(&hdi->pFont, x, y, 1, 1, hdi->string,0,-1, qfalse, hdi->bVirtualScreen);
|
||||
} else {
|
||||
cgi.R_Text_Paint(&cgs.media.verdana, x, y, 1, 1, hdi->string,0,-1, qfalse, hdi->bVirtualScreen);
|
||||
}
|
||||
} else {
|
||||
if ( hdi->bVirtualScreen )
|
||||
CG_AdjustFrom640(&x, &y, &w, &h);
|
||||
|
||||
cgi.R_DrawStretchPic(x, y, w, h, 0.f, 0.f, 1.f, 1.f, hdi->hShader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CG_HudDrawShader (int iInfo) {
|
||||
hdelement_t *hdi = hdelements + iInfo;
|
||||
if(hdi->shaderName[0]) {
|
||||
hdi->hShader = cgi.R_RegisterShaderNoMip(hdi->shaderName);
|
||||
} else {
|
||||
hdi->hShader = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void CG_HudDrawFont (int iInfo) {
|
||||
hdelement_t *hdi = hdelements + iInfo;
|
||||
if(hdi->fontName[0]) {
|
||||
cgi.R_RegisterFont(hdi->fontName,0,&hdi->pFont);
|
||||
} else {
|
||||
memset(&hdi->pFont,0,sizeof(hdi->pFont));
|
||||
}
|
||||
}
|
||||
|
||||
static void CG_PlaySound(char *sound_name, float *origin, int channel,
|
||||
float volume, float min_distance, float pitch, int argstype) {
|
||||
ubersound_t* sound;
|
||||
|
||||
sound = CG_GetUbersound(sound_name);
|
||||
|
||||
if(sound)
|
||||
cgi.S_StartSound( origin, -1, sound->channel, sound->sfxHandle );
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CG_ParseCGMessage
|
||||
=====================
|
||||
*/
|
||||
void CG_ParseCGMessage() {
|
||||
int msgtype;
|
||||
vec3_t vecStart, vecTmp, vecEnd, vecArray[64];
|
||||
int iCount, iLarge;
|
||||
int i, iTemp;
|
||||
char *s;
|
||||
hdelement_t *hde;
|
||||
|
||||
// thats a hack, it should be done somewhere else [?]
|
||||
wall_impact_count = 0;
|
||||
flesh_impact_count = 0;
|
||||
|
||||
do {
|
||||
msgtype = cgi.MSG_ReadBits( 6 );
|
||||
if(cg_debugCGMessages->integer) {
|
||||
Com_Printf( "CG_ParseCGMessage: command type %i\n", msgtype );
|
||||
}
|
||||
switch ( msgtype ) {
|
||||
case 1: // BulletTracer (visible?)
|
||||
vecTmp[0] = cgi.MSG_ReadCoord();
|
||||
vecTmp[1] = cgi.MSG_ReadCoord();
|
||||
vecTmp[2] = cgi.MSG_ReadCoord();
|
||||
case 2: // BulletTracer (invisible?)
|
||||
case 5: // BubbleTrail
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
if ( msgtype != 1 ) {
|
||||
vecTmp[0] = vecStart[0];
|
||||
vecTmp[1] = vecStart[1];
|
||||
vecTmp[2] = vecStart[2];
|
||||
}
|
||||
vecArray[0][0] = cgi.MSG_ReadCoord();
|
||||
vecArray[0][1] = cgi.MSG_ReadCoord();
|
||||
vecArray[0][2] = cgi.MSG_ReadCoord();
|
||||
|
||||
iLarge = cgi.MSG_ReadBits( 1 );
|
||||
if(msgtype==5) {
|
||||
CG_MakeBubbleTrail(vecStart,vecArray[0],iLarge);
|
||||
} else if(msgtype==1) {
|
||||
// su44: I am not sure about the last parameters...
|
||||
CG_MakeBulletTracer(vecTmp, vecStart, vecArray, 1, iLarge, 1, 1);
|
||||
} else { //msgtype == 2
|
||||
CG_MakeBulletTracer(vecTmp, vecStart, vecArray, 1, iLarge, 0, 1);
|
||||
}
|
||||
break;
|
||||
case 3: // BulletTracer multiple times
|
||||
vecTmp[0] = cgi.MSG_ReadCoord();
|
||||
vecTmp[1] = cgi.MSG_ReadCoord();
|
||||
vecTmp[2] = cgi.MSG_ReadCoord();
|
||||
iTemp = cgi.MSG_ReadBits( 6 );
|
||||
case 4: // BulletTracer multiple times (shotgun shot)
|
||||
if ( msgtype == 4 )
|
||||
iTemp = 0;
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
|
||||
iLarge = cgi.MSG_ReadBits( 1 );
|
||||
iCount = cgi.MSG_ReadBits( 6 );
|
||||
|
||||
// this check is missing in MOHAA code, so this has buffer overflow risk in AA
|
||||
if ( iCount > 64 )
|
||||
Com_Error( ERR_DROP, "CG message type 4 sent too many data.\n" );
|
||||
for (i=0;i<iCount;i++) {
|
||||
vecArray[i][0] = cgi.MSG_ReadCoord();
|
||||
vecArray[i][1] = cgi.MSG_ReadCoord();
|
||||
vecArray[i][2] = cgi.MSG_ReadCoord();
|
||||
}
|
||||
CG_MakeBulletTracer(vecTmp, vecStart, vecArray, iCount, iLarge, iTemp, 1);
|
||||
break;
|
||||
case 6: // wall impact
|
||||
case 7: // flesh impact
|
||||
case 8: // flesh impact (?)
|
||||
case 9: // wall impact (?)
|
||||
case 10: // wall impact (?)
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
|
||||
cgi.MSG_ReadDir( vecEnd );
|
||||
iLarge = cgi.MSG_ReadBits( 1 );
|
||||
switch (msgtype) {
|
||||
case 6:
|
||||
if(wall_impact_count < MAX_IMPACTS) {
|
||||
VectorCopy(vecStart,wall_impact_pos[wall_impact_count]);
|
||||
VectorCopy(vecEnd,wall_impact_norm[wall_impact_count]);
|
||||
wall_impact_large[wall_impact_count] = iLarge;
|
||||
wall_impact_type[wall_impact_count] = 0;
|
||||
wall_impact_count++;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
if(flesh_impact_count < MAX_IMPACTS) {
|
||||
// inverse hit normal, I dont know why,
|
||||
// but that's done by MoHAA
|
||||
VectorInverse(vecEnd);
|
||||
VectorCopy(vecStart,flesh_impact_pos[flesh_impact_count]);
|
||||
VectorCopy(vecEnd,flesh_impact_norm[flesh_impact_count]);
|
||||
flesh_impact_large[flesh_impact_count] = iLarge;
|
||||
flesh_impact_count++;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
if(flesh_impact_count < MAX_IMPACTS) {
|
||||
// same here?
|
||||
VectorInverse(vecEnd);
|
||||
VectorCopy(vecStart,flesh_impact_pos[flesh_impact_count]);
|
||||
VectorCopy(vecEnd,flesh_impact_norm[flesh_impact_count]);
|
||||
flesh_impact_large[flesh_impact_count] = iLarge;
|
||||
flesh_impact_count++;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
if(wall_impact_count < MAX_IMPACTS) {
|
||||
VectorCopy(vecStart,wall_impact_pos[wall_impact_count]);
|
||||
VectorCopy(vecEnd,wall_impact_norm[wall_impact_count]);
|
||||
wall_impact_large[wall_impact_count] = iLarge;
|
||||
if(iLarge) {
|
||||
wall_impact_type[wall_impact_count] = 3;
|
||||
} else {
|
||||
wall_impact_type[wall_impact_count] = 2;
|
||||
}
|
||||
wall_impact_count++;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
if(wall_impact_count < MAX_IMPACTS) {
|
||||
VectorCopy(vecStart,wall_impact_pos[wall_impact_count]);
|
||||
VectorCopy(vecEnd,wall_impact_norm[wall_impact_count]);
|
||||
wall_impact_large[wall_impact_count] = iLarge;
|
||||
if(iLarge) {
|
||||
wall_impact_type[wall_impact_count] = 5;
|
||||
} else {
|
||||
wall_impact_type[wall_impact_count] = 4;
|
||||
}
|
||||
wall_impact_count++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
vecEnd[0] = cgi.MSG_ReadCoord();
|
||||
vecEnd[1] = cgi.MSG_ReadCoord();
|
||||
vecEnd[2] = cgi.MSG_ReadCoord();
|
||||
CG_MeleeImpact(vecStart,vecEnd);
|
||||
break;
|
||||
case 12: // m1 frag/stiel grenade explosion
|
||||
case 13: // bazooka/panzershrek projectile explosion
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
CG_MakeExplosionEffect(vecStart,msgtype);
|
||||
break;
|
||||
default: //unknown message
|
||||
Com_Error(ERR_DROP, "CG_ParseCGMessage: Unknown CG Message %i", msgtype);
|
||||
break;
|
||||
case 14:
|
||||
case 15: // MakeEffect
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19: // oil barrel effect
|
||||
case 20:
|
||||
case 21: // oil barrel effect top
|
||||
case 22: // oil barrel effect top - first hit
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
cgi.MSG_ReadDir( vecEnd );
|
||||
CG_MakeEffect_Normal(msgtype/* + 67*/,vecStart,vecEnd);
|
||||
break;
|
||||
case 23: // broke crate
|
||||
case 24: // broke glass window
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
i = cgi.MSG_ReadByte();
|
||||
if(msgtype == 23) {
|
||||
s = va("models/fx/crates/debris_%i.tik",i);
|
||||
} else {
|
||||
s = va("models/fx/windows/debris_%i.tik",i);
|
||||
}
|
||||
CG_SpawnEffectModel(s, vecStart);
|
||||
break;
|
||||
case 25: // Bullet tracer
|
||||
vecTmp[0] = cgi.MSG_ReadCoord();
|
||||
vecTmp[1] = cgi.MSG_ReadCoord();
|
||||
vecTmp[2] = cgi.MSG_ReadCoord();
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
|
||||
vecArray[0][0] = cgi.MSG_ReadCoord();
|
||||
vecArray[0][1] = cgi.MSG_ReadCoord();
|
||||
vecArray[0][2] = cgi.MSG_ReadCoord();
|
||||
|
||||
iLarge = cgi.MSG_ReadBits( 1 );
|
||||
|
||||
CG_MakeBulletTracer(vecTmp,vecStart,vecArray,1,iLarge,0,1);
|
||||
break;
|
||||
case 26: // Bullet tracer
|
||||
vecTmp[0] = 0;
|
||||
vecTmp[1] = 0;
|
||||
vecTmp[2] = 0;
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
|
||||
vecArray[0][0] = cgi.MSG_ReadCoord();
|
||||
vecArray[0][1] = cgi.MSG_ReadCoord();
|
||||
vecArray[0][2] = cgi.MSG_ReadCoord();
|
||||
|
||||
iLarge = cgi.MSG_ReadBits( 1 );
|
||||
CG_MakeBulletTracer(vecTmp,vecStart,vecArray,1,iLarge,0,1);
|
||||
break;
|
||||
case 27: // HUD drawing...
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
Q_strncpyz( hde->shaderName, cgi.MSG_ReadString(), sizeof(hde->shaderName) );
|
||||
hde->string[0] = 0;
|
||||
memset(&hde->pFont,0,sizeof(hde->pFont));
|
||||
hde->fontName[0] = 0;
|
||||
|
||||
CG_HudDrawShader(i);
|
||||
break;
|
||||
case 28: // HUD drawing...
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
hde->iHorizontalAlign = cgi.MSG_ReadBits( 2 );
|
||||
hde->iHorizontalAlign = cgi.MSG_ReadBits( 2 );
|
||||
break;
|
||||
case 29:
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
hde->iX = cgi.MSG_ReadShort();
|
||||
hde->iY = cgi.MSG_ReadShort();
|
||||
hde->iWidth = cgi.MSG_ReadShort();
|
||||
hde->iHeight = cgi.MSG_ReadShort();
|
||||
break;
|
||||
case 30:
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
hde->bVirtualScreen = cgi.MSG_ReadBits( 1 );
|
||||
break;
|
||||
case 31: // huddraw_color
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
hde->vColor[0] = cgi.MSG_ReadByte()*0.003921568859368563;
|
||||
hde->vColor[1] = cgi.MSG_ReadByte()*0.003921568859368563;
|
||||
hde->vColor[2] = cgi.MSG_ReadByte()*0.003921568859368563;
|
||||
break;
|
||||
case 32: // huddraw_alpha
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
hde->vColor[3] = cgi.MSG_ReadByte()*0.003921568859368563;
|
||||
break;
|
||||
case 33: // huddraw_string
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
hde->hShader = 0;
|
||||
Q_strncpyz( hde->string, cgi.MSG_ReadString(), sizeof(hde->string) );
|
||||
break;
|
||||
case 34: // huddraw_font
|
||||
i = cgi.MSG_ReadByte();
|
||||
hde = hdelements + i;
|
||||
Q_strncpyz( hde->fontName, cgi.MSG_ReadString(), sizeof(hde->fontName) );
|
||||
hde->hShader = 0;
|
||||
hde->shaderName[0] = 0;
|
||||
CG_HudDrawFont(i);
|
||||
break;
|
||||
case 35:
|
||||
case 36:
|
||||
// TODO - play sound (?)
|
||||
//CG_PlaySound(s, 0, 5, 2.0, -1.0, vecStart, 1);
|
||||
break;
|
||||
case 37: // voicechat message (squad command, taunt, etc...)
|
||||
vecStart[0] = cgi.MSG_ReadCoord();
|
||||
vecStart[1] = cgi.MSG_ReadCoord();
|
||||
vecStart[2] = cgi.MSG_ReadCoord();
|
||||
|
||||
iTemp = cgi.MSG_ReadBits( 1 );
|
||||
// read client index
|
||||
i = cgi.MSG_ReadBits( 6 );
|
||||
// read voicechat sound alias
|
||||
s = cgi.MSG_ReadString();
|
||||
|
||||
if(iTemp) {
|
||||
current_entity_number = i;
|
||||
|
||||
}
|
||||
//CG_Printf("Case 37: iTemp %i, i %i, s %s\n",iTemp,i,s);
|
||||
// play an aliased sound from uberdialog.scr
|
||||
// wombat: only if there is a sound to be played
|
||||
if ( *s )
|
||||
CG_PlaySound(s,vecStart,5,-1.0,-1.0,-1.0,0);
|
||||
break;
|
||||
}
|
||||
} while ( cgi.MSG_ReadBits(1) );
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
@@ -20,7 +20,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
typedef struct UIFAKKLoadGameClass_s {
|
||||
UIListCtrl baseClass;
|
||||
bool m_bRemovePending;
|
||||
} UIFAKKLoadGameClass;
|
||||
// DESCRIPTION:
|
||||
// CGM buffer parser
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void CG_AddBulletTracers();
|
||||
void CG_AddBulletImpacts();
|
||||
void CG_ParseCGMessage();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// Player functions for the cgame
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_commands.h"
|
||||
|
||||
/*
|
||||
|
||||
player entities generate a great deal of information from implicit ques
|
||||
taken from the entityState_t
|
||||
|
||||
*/
|
||||
|
||||
//=====================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_ResetPlayerEntity
|
||||
|
||||
A player just came into view or teleported, so reset all animation info
|
||||
===============
|
||||
*/
|
||||
void CG_ResetPlayerEntity( centity_t *cent )
|
||||
{
|
||||
cent->errorTime = -99999; // guarantee no error decay added
|
||||
cent->extrapolated = qfalse;
|
||||
|
||||
VectorCopy(cent->currentState.origin, cent->lerpOrigin);
|
||||
VectorCopy(cent->lerpOrigin, cent->rawOrigin);
|
||||
|
||||
VectorCopy(cent->currentState.angles, cent->lerpAngles);
|
||||
VectorCopy(cent->lerpAngles, cent->rawAngles);
|
||||
|
||||
if (cent->currentState.number == cg.snap->ps.clientNum)
|
||||
{
|
||||
// initialize the camera position
|
||||
VectorCopy(cent->lerpOrigin, cg.currentViewPos);
|
||||
// initialize the camera angles
|
||||
VectorCopy(cent->lerpAngles, cg.currentViewAngles);
|
||||
}
|
||||
|
||||
// Reset splash info
|
||||
cent->splash_still_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_Player
|
||||
===============
|
||||
*/
|
||||
void CG_Player( centity_t *cent )
|
||||
{
|
||||
//CG_PlayerSplash( cent );
|
||||
}
|
||||
@@ -1,396 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_players.c -- handle the media and animation for player entities
|
||||
#include "cg_local.h"
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
CLIENT INFO
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
======================
|
||||
CG_NewClientInfo
|
||||
======================
|
||||
*/
|
||||
// su44: it seems MoHAA's CS_PLAYERS
|
||||
// contains only player names.
|
||||
void CG_NewClientInfo( int clientNum ) {
|
||||
clientInfo_t *ci;
|
||||
clientInfo_t newInfo;
|
||||
const char *configstring;
|
||||
const char *v;
|
||||
|
||||
ci = &cgs.clientinfo[clientNum];
|
||||
|
||||
configstring = CG_ConfigString( clientNum + CS_PLAYERS );
|
||||
if ( !configstring[0] ) {
|
||||
memset( ci, 0, sizeof( *ci ) );
|
||||
return; // player just left
|
||||
}
|
||||
|
||||
// build into a temp buffer so the defer checks can use
|
||||
// the old value
|
||||
memset( &newInfo, 0, sizeof( newInfo ) );
|
||||
|
||||
// isolate the player's name
|
||||
v = Info_ValueForKey(configstring, "name");
|
||||
Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
|
||||
|
||||
// replace whatever was there with the new one
|
||||
*ci = newInfo;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_PlayerFloatSprite
|
||||
|
||||
Float a sprite over the player's head
|
||||
===============
|
||||
*/
|
||||
static void CG_PlayerFloatSprite( centity_t *cent, qhandle_t shader ) {
|
||||
int rf;
|
||||
refEntity_t ent;
|
||||
int b;
|
||||
|
||||
if ( cent->currentState.number == cg.snap->ps.clientNum && !cg.renderingThirdPerson ) {
|
||||
rf = RF_THIRD_PERSON; // only show in mirrors
|
||||
} else {
|
||||
rf = 0;
|
||||
}
|
||||
|
||||
memset( &ent, 0, sizeof( ent ) );
|
||||
// su44: try to get "eyes bone" bone position and use it to position the sprite
|
||||
if(cent->bones && cgs.gameTIKIs[cent->currentState.modelindex] &&
|
||||
(b = cgi.TIKI_GetBoneIndex(cgs.gameTIKIs[cent->currentState.modelindex],"eyes bone")) != -1) {
|
||||
vec3_t dummy;
|
||||
CG_BoneLocal2World(¢->bones[b],cent->lerpOrigin,cent->lerpAngles,ent.origin,dummy);
|
||||
ent.origin[2] += 24;
|
||||
} else {
|
||||
VectorCopy( cent->lerpOrigin, ent.origin );
|
||||
ent.origin[2] += 98;
|
||||
}
|
||||
ent.reType = RT_SPRITE;
|
||||
ent.customShader = shader;
|
||||
ent.radius = 8;
|
||||
ent.renderfx = rf;
|
||||
ent.shaderRGBA[0] = 255;
|
||||
ent.shaderRGBA[1] = 255;
|
||||
ent.shaderRGBA[2] = 255;
|
||||
ent.shaderRGBA[3] = 255;
|
||||
cgi.R_AddRefEntityToScene( &ent );
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_ExtractPlayerTeam
|
||||
|
||||
su44: extract player team from entityState_t::eFlags
|
||||
and save it to cg.clientinfo
|
||||
===============
|
||||
*/
|
||||
void CG_ExtractPlayerTeam( centity_t *cent ) {
|
||||
clientInfo_t *ci;
|
||||
if( cent->currentState.number >= cgs.maxclients ) {
|
||||
CG_Error("CG_ExtractPlayerTeam on non-client entity (%i)", cent->currentState.number );
|
||||
}
|
||||
|
||||
ci = &cgs.clientinfo[cent->currentState.number];
|
||||
|
||||
// MoHAA sends ET_PLAYER team in entityFlags
|
||||
if(cent->currentState.eFlags & EF_AXIS) {
|
||||
ci->team = TEAM_AXIS;
|
||||
} else if(cent->currentState.eFlags & EF_ALLIES) {
|
||||
ci->team = TEAM_ALLIES;
|
||||
//} else if(cent->currentState.eFlags & EF_SPECTATOR) {
|
||||
// ci->team = TEAM_SPECTATOR;
|
||||
} else {
|
||||
ci->team = TEAM_FREEFORALL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_PlayerSprites
|
||||
|
||||
Float sprites over the player's head
|
||||
===============
|
||||
*/
|
||||
void CG_PlayerSprites( centity_t *cent ) {
|
||||
//int team;
|
||||
|
||||
//if ( cent->currentState.eFlags & EF_CONNECTION ) {
|
||||
// CG_PlayerFloatSprite( cent, cgs.media.connectionShader );
|
||||
// return;
|
||||
//}
|
||||
|
||||
//if ( cent->currentState.eFlags & EF_TALK ) {
|
||||
// CG_PlayerFloatSprite( cent, cgs.media.balloonShader );
|
||||
// return;
|
||||
//}
|
||||
|
||||
//team = cgs.clientinfo[ cent->currentState.clientNum ].team;
|
||||
//if ( !(cent->currentState.eFlags & EF_DEAD) &&
|
||||
// cg.snap->ps.stats[STAT_TEAM] == team &&
|
||||
// cgs.gametype >= GT_TEAM) {
|
||||
// if (cg_drawFriend->integer) {
|
||||
// //CG_PlayerFloatSprite( cent, cgs.media.friendShader );
|
||||
// }
|
||||
// return;
|
||||
//}
|
||||
|
||||
// show team icons over friend heads
|
||||
if(cgs.gametype >= GT_TEAM && !(cent->currentState.eFlags & EF_DEAD)) {
|
||||
if(cent->currentState.eFlags & EF_AXIS && cg.snap->ps.stats[STAT_TEAM] == TEAM_AXIS) {
|
||||
CG_PlayerFloatSprite(cent,cgi.R_RegisterShader("textures/hud/axis.tga"));
|
||||
} else if(cent->currentState.eFlags & EF_ALLIES && cg.snap->ps.stats[STAT_TEAM] == TEAM_ALLIES) {
|
||||
CG_PlayerFloatSprite(cent,cgi.R_RegisterShader("textures/hud/allies.tga"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_PlayerShadow
|
||||
|
||||
Returns the Z component of the surface being shadowed
|
||||
|
||||
should it return a full plane instead of a Z?
|
||||
===============
|
||||
*/
|
||||
#define SHADOW_DISTANCE 128
|
||||
static qboolean CG_PlayerShadow( centity_t *cent, float *shadowPlane ) {
|
||||
vec3_t end, mins = {-15, -15, 0}, maxs = {15, 15, 2};
|
||||
trace_t trace;
|
||||
float alpha;
|
||||
|
||||
*shadowPlane = 0;
|
||||
|
||||
if ( cg_shadows->integer == 0 ) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// send a trace down from the player to the ground
|
||||
VectorCopy( cent->lerpOrigin, end );
|
||||
end[2] -= SHADOW_DISTANCE;
|
||||
|
||||
cgi.CM_BoxTrace( &trace, cent->lerpOrigin, end, mins, maxs, 0, MASK_PLAYERSOLID, qfalse );
|
||||
|
||||
// no shadow if too high
|
||||
if ( trace.fraction == 1.0 || trace.startsolid || trace.allsolid ) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
*shadowPlane = trace.endpos[2] + 1;
|
||||
|
||||
if ( cg_shadows->integer != 1 ) { // no mark for stencil or projection shadows
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
// fade the shadow out with height
|
||||
alpha = 1.0 - trace.fraction;
|
||||
|
||||
// hack / FPE - bogus planes?
|
||||
//assert( DotProduct( trace.plane.normal, trace.plane.normal ) != 0.0f )
|
||||
|
||||
// add the mark as a temporary, so it goes directly to the renderer
|
||||
// without taking a spot in the cg_marks array
|
||||
CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal,
|
||||
/*cent->pe.legs.yawAngle*/ 0 , alpha,alpha,alpha,1, qfalse, 24, qtrue );
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_PlayerSplash
|
||||
|
||||
Draw a mark at the water surface
|
||||
===============
|
||||
*/
|
||||
static void CG_PlayerSplash( centity_t *cent ) {
|
||||
//vec3_t start, end;
|
||||
//trace_t trace;
|
||||
//int contents;
|
||||
//polyVert_t verts[4];
|
||||
|
||||
//if ( !cg_shadows->integer ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//VectorCopy( cent->lerpOrigin, end );
|
||||
//end[2] -= 24;
|
||||
|
||||
//// if the feet aren't in liquid, don't make a mark
|
||||
//// this won't handle moving water brushes, but they wouldn't draw right anyway...
|
||||
//contents = cgi.CM_PointContents( end, 0 );
|
||||
//if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//VectorCopy( cent->lerpOrigin, start );
|
||||
//start[2] += 32;
|
||||
|
||||
//// if the head isn't out of liquid, don't make a mark
|
||||
//contents = cgi.CM_PointContents( start, 0 );
|
||||
//if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//// trace down to find the surface
|
||||
//cgi.CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) );
|
||||
|
||||
//if ( trace.fraction == 1.0 ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//// create a mark polygon
|
||||
//VectorCopy( trace.endpos, verts[0].xyz );
|
||||
//verts[0].xyz[0] -= 32;
|
||||
//verts[0].xyz[1] -= 32;
|
||||
//verts[0].st[0] = 0;
|
||||
//verts[0].st[1] = 0;
|
||||
//verts[0].modulate[0] = 255;
|
||||
//verts[0].modulate[1] = 255;
|
||||
//verts[0].modulate[2] = 255;
|
||||
//verts[0].modulate[3] = 255;
|
||||
|
||||
//VectorCopy( trace.endpos, verts[1].xyz );
|
||||
//verts[1].xyz[0] -= 32;
|
||||
//verts[1].xyz[1] += 32;
|
||||
//verts[1].st[0] = 0;
|
||||
//verts[1].st[1] = 1;
|
||||
//verts[1].modulate[0] = 255;
|
||||
//verts[1].modulate[1] = 255;
|
||||
//verts[1].modulate[2] = 255;
|
||||
//verts[1].modulate[3] = 255;
|
||||
|
||||
//VectorCopy( trace.endpos, verts[2].xyz );
|
||||
//verts[2].xyz[0] += 32;
|
||||
//verts[2].xyz[1] += 32;
|
||||
//verts[2].st[0] = 1;
|
||||
//verts[2].st[1] = 1;
|
||||
//verts[2].modulate[0] = 255;
|
||||
//verts[2].modulate[1] = 255;
|
||||
//verts[2].modulate[2] = 255;
|
||||
//verts[2].modulate[3] = 255;
|
||||
|
||||
//VectorCopy( trace.endpos, verts[3].xyz );
|
||||
//verts[3].xyz[0] += 32;
|
||||
//verts[3].xyz[1] -= 32;
|
||||
//verts[3].st[0] = 1;
|
||||
//verts[3].st[1] = 0;
|
||||
//verts[3].modulate[0] = 255;
|
||||
//verts[3].modulate[1] = 255;
|
||||
//verts[3].modulate[2] = 255;
|
||||
//verts[3].modulate[3] = 255;
|
||||
|
||||
//cgi.R_AddPolyToScene( cgs.media.wakeMarkShader, 4, verts );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_LightVerts
|
||||
=================
|
||||
*/
|
||||
int CG_LightVerts( vec3_t normal, int numVerts, polyVert_t *verts )
|
||||
{
|
||||
#if 0
|
||||
int i, j;
|
||||
float incoming;
|
||||
vec3_t ambientLight;
|
||||
vec3_t lightDir;
|
||||
vec3_t directedLight;
|
||||
|
||||
for (i = 0; i < numVerts; i++) {
|
||||
incoming = DotProduct (normal, lightDir);
|
||||
if ( incoming <= 0 ) {
|
||||
verts[i].modulate[0] = ambientLight[0];
|
||||
verts[i].modulate[1] = ambientLight[1];
|
||||
verts[i].modulate[2] = ambientLight[2];
|
||||
verts[i].modulate[3] = 255;
|
||||
continue;
|
||||
}
|
||||
j = ( ambientLight[0] + incoming * directedLight[0] );
|
||||
if ( j > 255 ) {
|
||||
j = 255;
|
||||
}
|
||||
verts[i].modulate[0] = j;
|
||||
|
||||
j = ( ambientLight[1] + incoming * directedLight[1] );
|
||||
if ( j > 255 ) {
|
||||
j = 255;
|
||||
}
|
||||
verts[i].modulate[1] = j;
|
||||
|
||||
j = ( ambientLight[2] + incoming * directedLight[2] );
|
||||
if ( j > 255 ) {
|
||||
j = 255;
|
||||
}
|
||||
verts[i].modulate[2] = j;
|
||||
|
||||
verts[i].modulate[3] = 255;
|
||||
}
|
||||
#endif
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_Player
|
||||
===============
|
||||
*/
|
||||
void CG_Player( centity_t *cent ) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
//=====================================================================
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_ResetPlayerEntity
|
||||
|
||||
A player just came into view or teleported, so reset all animation info
|
||||
===============
|
||||
*/
|
||||
void CG_ResetPlayerEntity( centity_t *cent ) {
|
||||
cent->errorTime = -99999; // guarantee no error decay added
|
||||
cent->extrapolated = qfalse;
|
||||
|
||||
//BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
|
||||
//BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
|
||||
|
||||
VectorCopy( cent->currentState.origin, cent->lerpOrigin );
|
||||
VectorCopy( cent->currentState.angles, cent->lerpAngles );
|
||||
|
||||
VectorCopy( cent->lerpOrigin, cent->rawOrigin );
|
||||
VectorCopy( cent->lerpAngles, cent->rawAngles );
|
||||
}
|
||||
|
||||
+12
-152
@@ -1,182 +1,42 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_playerstate.c -- this file acts on changes in a new playerState_t
|
||||
|
||||
// DESCRIPTION:
|
||||
//
|
||||
// this file acts on changes in a new playerState_t.
|
||||
// With normal play, this will be done after local prediction, but when
|
||||
// following another player or playing back a demo, it will be checked
|
||||
// when the snapshot transitions like all the other entities
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_DamageFeedback
|
||||
==============
|
||||
*/
|
||||
void CG_DamageFeedback( int yawByte, int pitchByte, int damage ) {
|
||||
float left, front, up;
|
||||
float kick;
|
||||
int health;
|
||||
float scale;
|
||||
vec3_t dir;
|
||||
vec3_t angles;
|
||||
float dist;
|
||||
float yaw, pitch;
|
||||
|
||||
// show the attacking player's head and name in corner
|
||||
cg.attackerTime = cg.time;
|
||||
|
||||
// the lower on health you are, the greater the view kick will be
|
||||
health = cg.snap->ps.stats[STAT_HEALTH];
|
||||
if ( health < 40 ) {
|
||||
scale = 1;
|
||||
} else {
|
||||
scale = 40.0 / health;
|
||||
}
|
||||
kick = damage * scale;
|
||||
|
||||
if (kick < 5)
|
||||
kick = 5;
|
||||
if (kick > 10)
|
||||
kick = 10;
|
||||
|
||||
// if yaw and pitch are both 255, make the damage always centered (falling, etc)
|
||||
if ( yawByte == 255 && pitchByte == 255 ) {
|
||||
cg.damageX = 0;
|
||||
cg.damageY = 0;
|
||||
cg.v_dmg_roll = 0;
|
||||
cg.v_dmg_pitch = -kick;
|
||||
} else {
|
||||
// positional
|
||||
pitch = pitchByte / 255.0 * 360;
|
||||
yaw = yawByte / 255.0 * 360;
|
||||
|
||||
angles[PITCH] = pitch;
|
||||
angles[YAW] = yaw;
|
||||
angles[ROLL] = 0;
|
||||
|
||||
AngleVectors( angles, dir, NULL, NULL );
|
||||
VectorSubtract( vec3_origin, dir, dir );
|
||||
|
||||
front = DotProduct (dir, cg.refdef.viewaxis[0] );
|
||||
left = DotProduct (dir, cg.refdef.viewaxis[1] );
|
||||
up = DotProduct (dir, cg.refdef.viewaxis[2] );
|
||||
|
||||
dir[0] = front;
|
||||
dir[1] = left;
|
||||
dir[2] = 0;
|
||||
dist = VectorLength( dir );
|
||||
if ( dist < 0.1 ) {
|
||||
dist = 0.1f;
|
||||
}
|
||||
|
||||
cg.v_dmg_roll = kick * left;
|
||||
|
||||
cg.v_dmg_pitch = -kick * front;
|
||||
|
||||
if ( front <= 0.1 ) {
|
||||
front = 0.1f;
|
||||
}
|
||||
cg.damageX = -left / front;
|
||||
cg.damageY = up / dist;
|
||||
}
|
||||
|
||||
// clamp the position
|
||||
if ( cg.damageX > 1.0 ) {
|
||||
cg.damageX = 1.0;
|
||||
}
|
||||
if ( cg.damageX < - 1.0 ) {
|
||||
cg.damageX = -1.0;
|
||||
}
|
||||
|
||||
if ( cg.damageY > 1.0 ) {
|
||||
cg.damageY = 1.0;
|
||||
}
|
||||
if ( cg.damageY < - 1.0 ) {
|
||||
cg.damageY = -1.0;
|
||||
}
|
||||
|
||||
// don't let the screen flashes vary as much
|
||||
if ( kick > 10 ) {
|
||||
kick = 10;
|
||||
}
|
||||
cg.damageValue = kick;
|
||||
cg.v_dmg_time = cg.time + DAMAGE_TIME;
|
||||
cg.damageTime = cg.snap->serverTime;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CG_Respawn
|
||||
|
||||
A respawn happened this snapshot
|
||||
================
|
||||
*/
|
||||
void CG_Respawn( void ) {
|
||||
// no error decay on player movement
|
||||
cg.thisFrameTeleport = qtrue;
|
||||
|
||||
// display weapons available
|
||||
cg.weaponSelectTime = cg.time;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_TransitionPlayerState
|
||||
|
||||
===============
|
||||
*/
|
||||
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) {
|
||||
return;//this souhld be empty
|
||||
////////////////////
|
||||
// check for changing follow mode
|
||||
if ( ps->clientNum != ops->clientNum ) {
|
||||
cg.thisFrameTeleport = qtrue;
|
||||
// make sure we don't get any unwanted transition effects
|
||||
*ops = *ps;
|
||||
}
|
||||
void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops )
|
||||
{
|
||||
|
||||
// damage events (player is getting wounded)
|
||||
//if ( ps->damageEvent != ops->damageEvent && ps->damageCount ) {
|
||||
// CG_DamageFeedback( ps->damageYaw, ps->damagePitch, ps->damageCount );
|
||||
//}
|
||||
|
||||
// respawning - TODO
|
||||
//if ( ps->persistant[PERS_SPAWN_COUNT] != ops->persistant[PERS_SPAWN_COUNT] ) {
|
||||
// CG_Respawn();
|
||||
//}
|
||||
|
||||
if ( cg.mapRestart ) {
|
||||
CG_Respawn();
|
||||
cg.mapRestart = qfalse;
|
||||
}
|
||||
|
||||
// smooth the ducking viewheight change
|
||||
if ( ps->viewheight != ops->viewheight ) {
|
||||
cg.duckChange = ps->viewheight - ops->viewheight;
|
||||
cg.duckTime = cg.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+409
-397
@@ -1,38 +1,39 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_predict.c -- this file generates cg.predictedPlayerState by either
|
||||
|
||||
// DESCRIPTION:
|
||||
// this file generates cg.predicted_player_state by either
|
||||
// interpolating between snapshots from the server or locally predicting
|
||||
// ahead the client's movement.
|
||||
// It also handles local physics interaction, like fragments bouncing off walls
|
||||
// ahead the client's movement. It also handles local physics interaction,
|
||||
// like fragments bouncing off walls
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
static pmove_t cg_pmove;
|
||||
static pmove_t cg_pmove;
|
||||
|
||||
static int cg_numSolidEntities;
|
||||
static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
|
||||
static int cg_numTriggerEntities;
|
||||
static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
|
||||
static int cg_numSolidEntities;
|
||||
static centity_t* cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT];
|
||||
static int cg_numTriggerEntities;
|
||||
// static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT];
|
||||
|
||||
/*
|
||||
====================
|
||||
@@ -43,37 +44,41 @@ of the entities that are actually solid, to make for more
|
||||
efficient collision detection
|
||||
====================
|
||||
*/
|
||||
void CG_BuildSolidList( void ) {
|
||||
int i;
|
||||
centity_t *cent;
|
||||
snapshot_t *snap;
|
||||
entityState_t *ent;
|
||||
void CG_BuildSolidList(void)
|
||||
{
|
||||
int i;
|
||||
centity_t* cent;
|
||||
snapshot_t* snap;
|
||||
entityState_t* ent;
|
||||
|
||||
cg_numSolidEntities = 0;
|
||||
cg_numTriggerEntities = 0;
|
||||
cg_numSolidEntities = 0;
|
||||
cg_numTriggerEntities = 0;
|
||||
|
||||
if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
|
||||
snap = cg.nextSnap;
|
||||
} else {
|
||||
snap = cg.snap;
|
||||
}
|
||||
if (cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport) {
|
||||
snap = cg.nextSnap;
|
||||
} else {
|
||||
snap = cg.snap;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < snap->numEntities ; i++ ) {
|
||||
cent = &cg_entities[ snap->entities[ i ].number ];
|
||||
ent = ¢->currentState;
|
||||
for (i = 0; i < snap->numEntities; i++) {
|
||||
cent = &cg_entities[snap->entities[i].number];
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) {
|
||||
cg_triggerEntities[cg_numTriggerEntities] = cent;
|
||||
cg_numTriggerEntities++;
|
||||
continue;
|
||||
}
|
||||
if (ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER ||
|
||||
ent->eType == ET_TELEPORT_TRIGGER) {
|
||||
/*
|
||||
cg_triggerEntities[cg_numTriggerEntities] = cent;
|
||||
cg_numTriggerEntities++;
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( cent->nextState.solid ) {
|
||||
cg_solidEntities[cg_numSolidEntities] = cent;
|
||||
cg_numSolidEntities++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (cent->nextState.solid) {
|
||||
cg_solidEntities[cg_numSolidEntities] = cent;
|
||||
cg_numSolidEntities++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -82,61 +87,78 @@ CG_ClipMoveToEntities
|
||||
|
||||
====================
|
||||
*/
|
||||
static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
|
||||
int skipNumber, int mask, trace_t *tr ) {
|
||||
int i, x, zd, zu;
|
||||
trace_t trace;
|
||||
entityState_t *ent;
|
||||
clipHandle_t cmodel;
|
||||
vec3_t bmins, bmaxs;
|
||||
vec3_t origin, angles;
|
||||
centity_t *cent;
|
||||
void CG_ClipMoveToEntities(const vec3_t start, const vec3_t mins,
|
||||
const vec3_t maxs, const vec3_t end,
|
||||
int skipNumber, int mask, trace_t* tr,
|
||||
qboolean cylinder)
|
||||
|
||||
for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
|
||||
cent = cg_solidEntities[ i ];
|
||||
ent = ¢->currentState;
|
||||
{
|
||||
int i;
|
||||
trace_t trace;
|
||||
entityState_t* ent;
|
||||
clipHandle_t cmodel;
|
||||
vec3_t bmins, bmaxs;
|
||||
vec3_t origin, angles;
|
||||
centity_t* cent;
|
||||
|
||||
if ( ent->number == skipNumber ) {
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < cg_numSolidEntities; i++) {
|
||||
cent = cg_solidEntities[i];
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->solid == SOLID_BMODEL ) {
|
||||
// special value for bmodel
|
||||
cmodel = cgi.CM_InlineModel( ent->modelindex );
|
||||
VectorCopy( cent->lerpAngles, angles );
|
||||
//BG_EvaluateTrajectory( ¢->currentState.pos, cg.physicsTime, origin );
|
||||
// su44: BG_EvaluateTrajectory isnt used in MoHAA
|
||||
VectorCopy(cent->lerpOrigin,origin);
|
||||
} else {
|
||||
// encoded bbox
|
||||
x = (ent->solid & 255);
|
||||
zd = ((ent->solid>>8) & 255);
|
||||
zu = ((ent->solid>>16) & 255) - 32;
|
||||
if (ent->number == skipNumber) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bmins[0] = bmins[1] = -x;
|
||||
bmaxs[0] = bmaxs[1] = x;
|
||||
bmins[2] = -zd;
|
||||
bmaxs[2] = zu;
|
||||
if (ent->solid == SOLID_BMODEL) {
|
||||
// special value for bmodel
|
||||
cmodel = cgi.CM_InlineModel(ent->modelindex);
|
||||
if (!cmodel) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
IntegerToBoundingBox(ent->solid, bmins, bmaxs);
|
||||
cmodel = cgi.CM_TempBoxModel(
|
||||
bmins, bmaxs,
|
||||
CONTENTS_BBOX);
|
||||
}
|
||||
|
||||
cmodel = cgi.CM_TempBoxModel( bmins, bmaxs, qfalse );
|
||||
VectorCopy( vec3_origin, angles );
|
||||
VectorCopy( cent->lerpOrigin, origin );
|
||||
}
|
||||
VectorCopy(cent->lerpOrigin, origin);
|
||||
if (ent->eFlags & EF_LINKANGLES) {
|
||||
VectorCopy(cent->lerpAngles, angles);
|
||||
}
|
||||
else {
|
||||
VectorClear(angles);
|
||||
}
|
||||
|
||||
cgi.CM_TransformedBoxTrace(&trace, start, end, mins, maxs, cmodel, mask,
|
||||
origin, angles, cylinder);
|
||||
|
||||
cgi.CM_TransformedBoxTrace ( &trace, start, end,
|
||||
mins, maxs, cmodel, mask, origin, angles, qfalse );
|
||||
if (trace.allsolid || trace.fraction < tr->fraction) {
|
||||
trace.entityNum = ent->number;
|
||||
*tr = trace;
|
||||
} else if (trace.startsolid) {
|
||||
tr->startsolid = qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trace.allsolid || trace.fraction < tr->fraction) {
|
||||
trace.entityNum = ent->number;
|
||||
*tr = trace;
|
||||
} else if (trace.startsolid) {
|
||||
tr->startsolid = qtrue;
|
||||
}
|
||||
if ( tr->allsolid ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
void CG_ShowTrace(trace_t* trace, int passent, const char* reason)
|
||||
|
||||
{
|
||||
char text[1024];
|
||||
|
||||
assert(reason);
|
||||
assert(trace);
|
||||
|
||||
sprintf(text, "%0.2f : Pass (%d) Frac %f Hit (%d): '%s'\n",
|
||||
(float)cg.time / 1000.0f, passent, trace->fraction,
|
||||
trace->entityNum, reason ? reason : "");
|
||||
|
||||
if (cg_traceinfo->integer == 3) {
|
||||
cgi.DebugPrintf(text);
|
||||
} else {
|
||||
cgi.DPrintf(text);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -144,9 +166,34 @@ static void CG_ClipMoveToEntities ( const vec3_t start, const vec3_t mins, const
|
||||
CG_Trace
|
||||
================
|
||||
*/
|
||||
void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
|
||||
int skipNumber, int mask ) {
|
||||
CG_PlayerTrace( result, start, mins, maxs, end, skipNumber, mask, qfalse, qfalse );
|
||||
void CG_Trace(trace_t* result, const vec3_t start, const vec3_t mins,
|
||||
const vec3_t maxs, const vec3_t end, int skipNumber, int mask,
|
||||
qboolean cylinder, qboolean cliptoentities,
|
||||
const char* description)
|
||||
|
||||
{
|
||||
trace_t t;
|
||||
|
||||
cgi.CM_BoxTrace(&t, start, end, mins, maxs, 0, mask, cylinder);
|
||||
t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
|
||||
|
||||
// If starting in a solid make sure the world is set as the entitynum
|
||||
|
||||
if (t.startsolid) {
|
||||
t.entityNum = ENTITYNUM_WORLD;
|
||||
}
|
||||
|
||||
if (cliptoentities) {
|
||||
// check all other solid models
|
||||
CG_ClipMoveToEntities(start, mins, maxs, end, skipNumber, mask, &t,
|
||||
cylinder);
|
||||
}
|
||||
|
||||
*result = t;
|
||||
|
||||
if (cg_traceinfo->integer) {
|
||||
CG_ShowTrace(result, skipNumber, description);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -154,16 +201,13 @@ void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, const vec
|
||||
CG_PlayerTrace
|
||||
================
|
||||
*/
|
||||
void CG_PlayerTrace( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end,
|
||||
int skipNumber, int mask, int capsule, qboolean traceDeep ) {
|
||||
trace_t t;
|
||||
void CG_PlayerTrace(trace_t* result, const vec3_t start, const vec3_t mins,
|
||||
const vec3_t maxs, const vec3_t end, int skipNumber,
|
||||
int mask, qboolean cylinder, qboolean tracedeep)
|
||||
|
||||
cgi.CM_BoxTrace( &t, start, end, mins, maxs, 0, mask, traceDeep );
|
||||
t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE;
|
||||
// check all other solid models
|
||||
CG_ClipMoveToEntities( start, mins, maxs, end, skipNumber, mask, &t );
|
||||
|
||||
*result = t;
|
||||
{
|
||||
CG_Trace(result, start, mins, maxs, end, skipNumber, mask, cylinder, qtrue,
|
||||
"PlayerTrace");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,165 +215,157 @@ void CG_PlayerTrace( trace_t *result, const vec3_t start, const vec3_t mins, con
|
||||
CG_PointContents
|
||||
================
|
||||
*/
|
||||
int CG_PointContents( const vec3_t point, int passEntityNum ) {
|
||||
int i;
|
||||
entityState_t *ent;
|
||||
centity_t *cent;
|
||||
clipHandle_t cmodel;
|
||||
int contents;
|
||||
int CG_PointContents(const vec3_t point, int passEntityNum)
|
||||
{
|
||||
int i;
|
||||
entityState_t* ent;
|
||||
centity_t* cent;
|
||||
clipHandle_t cmodel;
|
||||
int contents;
|
||||
|
||||
contents = cgi.CM_PointContents (point, 0);
|
||||
contents = cgi.CM_PointContents(point, 0);
|
||||
|
||||
for ( i = 0 ; i < cg_numSolidEntities ; i++ ) {
|
||||
cent = cg_solidEntities[ i ];
|
||||
for (i = 0; i < cg_numSolidEntities; i++) {
|
||||
cent = cg_solidEntities[i];
|
||||
|
||||
ent = ¢->currentState;
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->number == passEntityNum ) {
|
||||
continue;
|
||||
}
|
||||
if (ent->number == passEntityNum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ent->solid != SOLID_BMODEL) { // special value for bmodel
|
||||
continue;
|
||||
}
|
||||
if (ent->solid != SOLID_BMODEL) { // special value for bmodel
|
||||
continue;
|
||||
}
|
||||
|
||||
cmodel = cgi.CM_InlineModel( ent->modelindex );
|
||||
if ( !cmodel ) {
|
||||
continue;
|
||||
}
|
||||
cmodel = cgi.CM_InlineModel(ent->modelindex);
|
||||
if (!cmodel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
contents |= cgi.CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles );
|
||||
}
|
||||
contents |= cgi.CM_TransformedPointContents(point, cmodel, ent->origin,
|
||||
ent->angles);
|
||||
}
|
||||
|
||||
return contents;
|
||||
return contents;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
CG_InterpolatePlayerStateCamera
|
||||
|
||||
Generates cg.predicted_player_state by interpolating between
|
||||
cg.snap->player_state and cg.nextFrame->player_state
|
||||
========================
|
||||
*/
|
||||
static void CG_InterpolatePlayerStateCamera(void)
|
||||
{
|
||||
float f;
|
||||
int i;
|
||||
snapshot_t *prev, *next;
|
||||
|
||||
prev = cg.snap;
|
||||
next = cg.nextSnap;
|
||||
|
||||
//
|
||||
// copy in the current ones if nothing else
|
||||
//
|
||||
VectorCopy(cg.predicted_player_state.camera_angles, cg.camera_angles);
|
||||
VectorCopy(cg.predicted_player_state.camera_origin, cg.camera_origin);
|
||||
cg.camera_fov = cg.predicted_player_state.fov;
|
||||
|
||||
// if the next frame is a teleport, we can't lerp to it
|
||||
if (cg.nextFrameCameraCut) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!next || next->serverTime <= prev->serverTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
f = (float)(cg.time - prev->serverTime) /
|
||||
(next->serverTime - prev->serverTime);
|
||||
|
||||
// interpolate fov
|
||||
cg.camera_fov = prev->ps.fov + f * (next->ps.fov - prev->ps.fov);
|
||||
|
||||
if (!(cg.snap->ps.pm_flags & PMF_CAMERA_VIEW)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
cg.camera_origin[i] =
|
||||
prev->ps.camera_origin[i] +
|
||||
f * (next->ps.camera_origin[i] - prev->ps.camera_origin[i]);
|
||||
cg.camera_angles[i] =
|
||||
LerpAngle(prev->ps.camera_angles[i], next->ps.camera_angles[i], f);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
CG_InterpolatePlayerState
|
||||
|
||||
Generates cg.predictedPlayerState by interpolating between
|
||||
Generates cg.predicted_player_state by interpolating between
|
||||
cg.snap->player_state and cg.nextFrame->player_state
|
||||
========================
|
||||
*/
|
||||
static void CG_InterpolatePlayerState( qboolean grabAngles ) {
|
||||
float f;
|
||||
int i;
|
||||
playerState_t *out;
|
||||
snapshot_t *prev, *next;
|
||||
static void CG_InterpolatePlayerState(qboolean grabAngles)
|
||||
{
|
||||
float f;
|
||||
int i;
|
||||
playerState_t* out;
|
||||
snapshot_t *prev, *next;
|
||||
|
||||
out = &cg.predictedPlayerState;
|
||||
prev = cg.snap;
|
||||
next = cg.nextSnap;
|
||||
out = &cg.predicted_player_state;
|
||||
prev = cg.snap;
|
||||
next = cg.nextSnap;
|
||||
|
||||
*out = cg.snap->ps;
|
||||
*out = cg.snap->ps;
|
||||
|
||||
// if we are still allowing local input, short circuit the view angles
|
||||
if ( grabAngles ) {
|
||||
usercmd_t cmd;
|
||||
int cmdNum;
|
||||
// interpolate the camera if necessary
|
||||
CG_InterpolatePlayerStateCamera();
|
||||
|
||||
cmdNum = cgi.GetCurrentCmdNumber();
|
||||
cgi.GetUserCmd( cmdNum, &cmd );
|
||||
// if we are still allowing local input, short circuit the view angles
|
||||
if (grabAngles) {
|
||||
usercmd_t cmd;
|
||||
int cmdNum;
|
||||
|
||||
PM_UpdateViewAngles( out, &cmd );
|
||||
}
|
||||
cmdNum = cgi.GetCurrentCmdNumber();
|
||||
cgi.GetUserCmd(cmdNum, &cmd);
|
||||
|
||||
// if the next frame is a teleport, we can't lerp to it
|
||||
if ( cg.nextFrameTeleport ) {
|
||||
return;
|
||||
}
|
||||
PM_UpdateViewAngles(out, &cmd);
|
||||
}
|
||||
|
||||
if ( !next || next->serverTime <= prev->serverTime ) {
|
||||
return;
|
||||
}
|
||||
// if the next frame is a teleport, we can't lerp to it
|
||||
if (cg.nextFrameTeleport) {
|
||||
return;
|
||||
}
|
||||
|
||||
f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime );
|
||||
if (!next || next->serverTime <= prev->serverTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
i = next->ps.bobCycle;
|
||||
if ( i < prev->ps.bobCycle ) {
|
||||
i += 256; // handle wraparound
|
||||
}
|
||||
out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle );
|
||||
|
||||
out->fLeanAngle = prev->ps.fLeanAngle +
|
||||
f * (next->ps.fLeanAngle - prev->ps.fLeanAngle );
|
||||
|
||||
for ( i = 0 ; i < 3 ; i++ ) {
|
||||
out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] );
|
||||
if ( !grabAngles ) {
|
||||
out->viewangles[i] = LerpAngle(
|
||||
prev->ps.viewangles[i], next->ps.viewangles[i], f );
|
||||
}
|
||||
out->velocity[i] = prev->ps.velocity[i] +
|
||||
f * (next->ps.velocity[i] - prev->ps.velocity[i] );
|
||||
}
|
||||
f = cg.frameInterpolation;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
out->origin[i] =
|
||||
prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i]);
|
||||
if (!grabAngles) {
|
||||
out->viewangles[i] =
|
||||
LerpAngle(prev->ps.viewangles[i], next->ps.viewangles[i], f);
|
||||
}
|
||||
out->velocity[i] = prev->ps.velocity[i] +
|
||||
f * (next->ps.velocity[i] - prev->ps.velocity[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
CG_TouchTriggerPrediction
|
||||
|
||||
Predict push triggers and items
|
||||
=========================
|
||||
*/
|
||||
static void CG_TouchTriggerPrediction( void ) {
|
||||
int i;
|
||||
trace_t trace;
|
||||
entityState_t *ent;
|
||||
clipHandle_t cmodel;
|
||||
centity_t *cent;
|
||||
qboolean spectator;
|
||||
|
||||
// dead clients don't activate triggers
|
||||
if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
spectator = ( cg.predictedPlayerState.pm_type == PM_NOCLIP );
|
||||
|
||||
if ( cg.predictedPlayerState.pm_type != PM_NORMAL && !spectator ) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < cg_numTriggerEntities ; i++ ) {
|
||||
cent = cg_triggerEntities[ i ];
|
||||
ent = ¢->currentState;
|
||||
|
||||
if ( ent->solid != SOLID_BMODEL ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cmodel = cgi.CM_InlineModel( ent->modelindex );
|
||||
if ( !cmodel ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cgi.CM_BoxTrace( &trace, cg.predictedPlayerState.origin, cg.predictedPlayerState.origin,
|
||||
cg_pmove.mins, cg_pmove.maxs, cmodel, -1, qfalse );
|
||||
|
||||
if ( !trace.startsolid ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->eType == ET_TELEPORT_TRIGGER ) {
|
||||
cg.hyperspace = qtrue;
|
||||
} else if ( ent->eType == ET_PUSH_TRIGGER ) {
|
||||
//BG_TouchJumpPad( &cg.predictedPlayerState, ent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_PredictPlayerState
|
||||
|
||||
Generates cg.predictedPlayerState for the current cg.time
|
||||
cg.predictedPlayerState is guaranteed to be valid after exiting.
|
||||
Generates cg.predicted_player_state for the current cg.time
|
||||
cg.predicted_player_state is guaranteed to be valid after exiting.
|
||||
|
||||
For demo playback, this will be an interpolation between two valid
|
||||
playerState_t.
|
||||
@@ -350,207 +386,183 @@ We detect prediction errors and allow them to be decayed off over several frames
|
||||
to ease the jerk.
|
||||
=================
|
||||
*/
|
||||
void CG_PredictPlayerState( void ) {
|
||||
int cmdNum, current;
|
||||
playerState_t oldPlayerState;
|
||||
qboolean moved;
|
||||
usercmd_t oldestCmd;
|
||||
usercmd_t latestCmd;
|
||||
//FIXME: stub
|
||||
cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
|
||||
void CG_PredictPlayerState(void)
|
||||
{
|
||||
int cmdNum, current;
|
||||
playerState_t oldPlayerState;
|
||||
qboolean moved;
|
||||
usercmd_t latestCmd;
|
||||
|
||||
// if this is the first frame we must guarantee
|
||||
// predictedPlayerState is valid even if there is some
|
||||
// other error condition
|
||||
if ( !cg.validPPS ) {
|
||||
cg.validPPS = qtrue;
|
||||
cg.predictedPlayerState = cg.snap->ps;
|
||||
}
|
||||
cg.hyperspace = qfalse; // will be set if touching a trigger_teleport
|
||||
|
||||
// if this is the first frame we must guarantee
|
||||
// predicted_player_state is valid even if there is some
|
||||
// other error condition
|
||||
if (!cg.validPPS) {
|
||||
cg.validPPS = qtrue;
|
||||
cg.predicted_player_state = cg.snap->ps;
|
||||
}
|
||||
|
||||
// demo playback just copies the moves
|
||||
if ( cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_NO_PREDICTION ) || (cg.snap->ps.pm_flags & PMF_FROZEN) ) {
|
||||
CG_InterpolatePlayerState( qfalse );
|
||||
return;
|
||||
}
|
||||
// demo playback just copies the moves
|
||||
if (cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_NO_PREDICTION) ||
|
||||
(cg.snap->ps.pm_flags & PMF_FROZEN)) {
|
||||
CG_InterpolatePlayerState(qfalse);
|
||||
return;
|
||||
}
|
||||
|
||||
// non-predicting local movement will grab the latest angles
|
||||
if ( cg_nopredict->integer || cg_synchronousClients->integer || cg.snap->ps.pm_type & PM_NOCLIP) {
|
||||
CG_InterpolatePlayerState( qtrue );
|
||||
return;
|
||||
}
|
||||
// non-predicting local movement will grab the latest angles
|
||||
// FIXME
|
||||
// Noclip is jittery for some reason, so I'm disabling prediction while
|
||||
// noclipping
|
||||
if (cg_nopredict->integer || cg_synchronousClients->integer ||
|
||||
(cg.snap->ps.pm_type == PM_NOCLIP)) {
|
||||
CG_InterpolatePlayerState(qtrue);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 1
|
||||
// su44: temporary disabling playerstate prediction
|
||||
CG_InterpolatePlayerState( qtrue );
|
||||
return;
|
||||
#endif
|
||||
// prepare for pmove
|
||||
cg_pmove.ps = &cg.predicted_player_state;
|
||||
cg_pmove.trace = CG_PlayerTrace;
|
||||
cg_pmove.pointcontents = CG_PointContents;
|
||||
|
||||
// prepare for pmove
|
||||
cg_pmove.ps = &cg.predictedPlayerState;
|
||||
cg_pmove.trace = CG_PlayerTrace;
|
||||
cg_pmove.pointcontents = CG_PointContents;
|
||||
if ( cg_pmove.ps->pm_type == PM_DEAD ) {
|
||||
cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
|
||||
}
|
||||
else {
|
||||
cg_pmove.tracemask = MASK_PLAYERSOLID;
|
||||
}
|
||||
if ( cg.snap->ps.stats[STAT_TEAM] == TEAM_SPECTATOR ) {
|
||||
cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies
|
||||
}
|
||||
cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0;
|
||||
if (cg_pmove.ps->pm_type == PM_DEAD) {
|
||||
cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
|
||||
} else {
|
||||
cg_pmove.tracemask = MASK_PLAYERSOLID;
|
||||
}
|
||||
|
||||
// save the state before the pmove so we can detect transitions
|
||||
oldPlayerState = cg.predictedPlayerState;
|
||||
cg_pmove.noFootsteps = (cgs.dmflags & DF_NO_FOOTSTEPS) > 0;
|
||||
|
||||
current = cgi.GetCurrentCmdNumber();
|
||||
// save the state before the pmove so we can detect transitions
|
||||
oldPlayerState = cg.predicted_player_state;
|
||||
|
||||
// if we don't have the commands right after the snapshot, we
|
||||
// can't accurately predict a current position, so just freeze at
|
||||
// the last good position we had
|
||||
cmdNum = current - CMD_BACKUP + 1;
|
||||
cgi.GetUserCmd( cmdNum, &oldestCmd );
|
||||
if ( oldestCmd.serverTime > cg.snap->ps.commandTime
|
||||
&& oldestCmd.serverTime < cg.time ) { // special check for map_restart
|
||||
if ( cg_showmiss->integer ) {
|
||||
CG_Printf ("exceeded PACKET_BACKUP on commands\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
current = cgi.GetCurrentCmdNumber();
|
||||
|
||||
// get the latest command so we can know which commands are from previous map_restarts
|
||||
cgi.GetUserCmd( current, &latestCmd );
|
||||
// get the latest command so we can know which commands are from previous
|
||||
// map_restarts
|
||||
cgi.GetUserCmd(current, &latestCmd);
|
||||
|
||||
// get the most recent information we have, even if
|
||||
// the server time is beyond our current cg.time,
|
||||
// because predicted player positions are going to
|
||||
// be ahead of everything else anyway
|
||||
if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) {
|
||||
cg.predictedPlayerState = cg.nextSnap->ps;
|
||||
cg.physicsTime = cg.nextSnap->serverTime;
|
||||
} else {
|
||||
cg.predictedPlayerState = cg.snap->ps;
|
||||
cg.physicsTime = cg.snap->serverTime;
|
||||
}
|
||||
// get the most recent information we have, even if
|
||||
// the server time is beyond our current cg.time,
|
||||
// because predicted player positions are going to
|
||||
// be ahead of everything else anyway
|
||||
if (cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport) {
|
||||
cg.predicted_player_state = cg.nextSnap->ps;
|
||||
cg.physicsTime = cg.nextSnap->serverTime;
|
||||
} else {
|
||||
cg.predicted_player_state = cg.snap->ps;
|
||||
cg.physicsTime = cg.snap->serverTime;
|
||||
}
|
||||
|
||||
if ( pmove_msec->integer < 8 ) {
|
||||
cgi.Cvar_Set("pmove_msec", "8");
|
||||
}
|
||||
else if (pmove_msec->integer > 33) {
|
||||
cgi.Cvar_Set("pmove_msec", "33");
|
||||
}
|
||||
if (pmove_msec->integer >= 8)
|
||||
{
|
||||
if (pmove_msec->integer > 33)
|
||||
cgi.Cvar_Set("pmove_msec", "33");
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.Cvar_Set("pmove_msec", "8");
|
||||
}
|
||||
|
||||
cg_pmove.pmove_fixed = pmove_fixed->integer;// | cg_pmove_fixed->integer;
|
||||
cg_pmove.pmove_msec = pmove_msec->integer;
|
||||
cg_pmove.pmove_fixed = pmove_fixed->integer;
|
||||
cg_pmove.pmove_msec = pmove_msec->integer;
|
||||
|
||||
// run cmds
|
||||
moved = qfalse;
|
||||
for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) {
|
||||
// get the command
|
||||
cgi.GetUserCmd( cmdNum, &cg_pmove.cmd );
|
||||
// run cmds
|
||||
moved = qfalse;
|
||||
for (cmdNum = current - CMD_BACKUP + 1; cmdNum <= current; cmdNum++) {
|
||||
// get the command
|
||||
cgi.GetUserCmd(cmdNum, &cg_pmove.cmd);
|
||||
|
||||
if ( cg_pmove.pmove_fixed ) {
|
||||
PM_UpdateViewAngles( cg_pmove.ps, &cg_pmove.cmd );
|
||||
}
|
||||
if (cg_pmove.pmove_fixed) {
|
||||
PM_UpdateViewAngles(cg_pmove.ps, &cg_pmove.cmd);
|
||||
}
|
||||
|
||||
// don't do anything if the time is before the snapshot player time
|
||||
if ( cg_pmove.cmd.serverTime <= cg.predictedPlayerState.commandTime ) {
|
||||
continue;
|
||||
}
|
||||
// don't do anything if the time is before the snapshot player time
|
||||
if (cg_pmove.cmd.serverTime <= cg.predicted_player_state.commandTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't do anything if the command was from a previous map_restart
|
||||
if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) {
|
||||
continue;
|
||||
}
|
||||
// don't do anything if the command was from a previous map_restart
|
||||
if (cg_pmove.cmd.serverTime > latestCmd.serverTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for a prediction error from last frame
|
||||
// on a lan, this will often be the exact value
|
||||
// from the snapshot, but on a wan we will have
|
||||
// to predict several commands to get to the point
|
||||
// we want to compare
|
||||
if ( cg.predictedPlayerState.commandTime == oldPlayerState.commandTime ) {
|
||||
vec3_t delta;
|
||||
float len;
|
||||
// check for a prediction error from last frame
|
||||
// on a lan, this will often be the exact value
|
||||
// from the snapshot, but on a wan we will have
|
||||
// to predict several commands to get to the point
|
||||
// we want to compare
|
||||
if (cg.predicted_player_state.commandTime ==
|
||||
oldPlayerState.commandTime) {
|
||||
|
||||
if ( cg.thisFrameTeleport ) {
|
||||
// a teleport will not cause an error decay
|
||||
VectorClear( cg.predictedError );
|
||||
if ( cg_showmiss->integer ) {
|
||||
CG_Printf( "PredictionTeleport\n" );
|
||||
}
|
||||
cg.thisFrameTeleport = qfalse;
|
||||
} else {
|
||||
vec3_t adjusted;
|
||||
CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
|
||||
cg.predictedPlayerState.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted );
|
||||
if (cg.thisFrameTeleport) {
|
||||
// a teleport will not cause an error decay
|
||||
VectorClear(cg.predictedError);
|
||||
cg.thisFrameTeleport = qfalse;
|
||||
if (cg_showmiss->integer) {
|
||||
cgi.Printf("PredictionTeleport\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( cg_showmiss->integer ) {
|
||||
if (!VectorCompare( oldPlayerState.origin, adjusted )) {
|
||||
CG_Printf("prediction error\n");
|
||||
}
|
||||
}
|
||||
VectorSubtract( oldPlayerState.origin, adjusted, delta );
|
||||
len = VectorLength( delta );
|
||||
if ( len > 0.1 ) {
|
||||
if ( cg_showmiss->integer ) {
|
||||
CG_Printf("Prediction miss: %f\n", len);
|
||||
}
|
||||
if ( cg_errorDecay->integer ) {
|
||||
int t;
|
||||
float f;
|
||||
// if our feet are falling, don't try to move
|
||||
if (cg_pmove.ps->feetfalling && (cg_pmove.waterlevel < 2)) {
|
||||
cg_pmove.cmd.forwardmove = 0;
|
||||
cg_pmove.cmd.rightmove = 0;
|
||||
}
|
||||
|
||||
t = cg.time - cg.predictedErrorTime;
|
||||
f = ( cg_errorDecay->value - t ) / cg_errorDecay->value;
|
||||
if ( f < 0 ) {
|
||||
f = 0;
|
||||
}
|
||||
if ( f > 0 && cg_showmiss->integer ) {
|
||||
CG_Printf("Double prediction decay: %f\n", f);
|
||||
}
|
||||
VectorScale( cg.predictedError, f, cg.predictedError );
|
||||
} else {
|
||||
VectorClear( cg.predictedError );
|
||||
}
|
||||
VectorAdd( delta, cg.predictedError, cg.predictedError );
|
||||
cg.predictedErrorTime = cg.oldTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cg_pmove.pmove_fixed) {
|
||||
cg_pmove.cmd.serverTime = pmove_msec->integer
|
||||
* ((cg_pmove.cmd.serverTime + pmove_msec->integer - 1)
|
||||
/ pmove_msec->integer);
|
||||
}
|
||||
|
||||
if ( cg_pmove.pmove_fixed ) {
|
||||
cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec->integer-1) / pmove_msec->integer) * pmove_msec->integer;
|
||||
}
|
||||
Pmove(&cg_pmove);
|
||||
|
||||
Pmove (&cg_pmove);
|
||||
moved = qtrue;
|
||||
|
||||
moved = qtrue;
|
||||
// add push trigger movement effects
|
||||
// CG_TouchTriggerPrediction();
|
||||
}
|
||||
|
||||
// add push trigger movement effects
|
||||
CG_TouchTriggerPrediction();
|
||||
if (cg_showmiss->integer > 1) {
|
||||
cgi.Printf("[%i : %i] ", cg_pmove.cmd.serverTime, cg.time);
|
||||
}
|
||||
|
||||
// check for predictable events that changed from previous predictions
|
||||
//CG_CheckChangedPredictableEvents(&cg.predictedPlayerState);
|
||||
}
|
||||
// interpolate the camera if necessary
|
||||
CG_InterpolatePlayerStateCamera();
|
||||
|
||||
if ( cg_showmiss->integer > 1 ) {
|
||||
CG_Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time );
|
||||
}
|
||||
// Interpolate the player position
|
||||
if (cg.predicted_player_state.groundEntityNum != ENTITYNUM_WORLD) {
|
||||
centity_t* cent;
|
||||
vec3_t offset;
|
||||
|
||||
if ( !moved ) {
|
||||
if ( cg_showmiss->integer ) {
|
||||
CG_Printf( "not moved\n" );
|
||||
}
|
||||
return;
|
||||
}
|
||||
cent = &cg_entities[cg.predicted_player_state.groundEntityNum];
|
||||
|
||||
// adjust for the movement of the groundentity
|
||||
CG_AdjustPositionForMover( cg.predictedPlayerState.origin,
|
||||
cg.predictedPlayerState.groundEntityNum,
|
||||
cg.physicsTime, cg.time, cg.predictedPlayerState.origin );
|
||||
if (cent->interpolate) {
|
||||
float f;
|
||||
|
||||
// fire events and other transition triggered things
|
||||
CG_TransitionPlayerState( &cg.predictedPlayerState, &oldPlayerState );
|
||||
f = cg.frameInterpolation - 1.0;
|
||||
|
||||
offset[0] = (cent->nextState.origin[0] - cg_entities[cg.predicted_player_state.groundEntityNum].currentState.origin[0]) * f;
|
||||
offset[1] = (cent->nextState.origin[1] - cg_entities[cg.predicted_player_state.groundEntityNum].currentState.origin[1]) * f;
|
||||
offset[2] = (cent->nextState.origin[2] - cg_entities[cg.predicted_player_state.groundEntityNum].currentState.origin[2]) * f;
|
||||
|
||||
cg.predicted_player_state.origin[0] += offset[0];
|
||||
cg.predicted_player_state.origin[1] += offset[1];
|
||||
cg.predicted_player_state.origin[2] += offset[2];
|
||||
}
|
||||
}
|
||||
|
||||
// adjust for the movement of the groundentity
|
||||
|
||||
if (!moved) {
|
||||
if (cg_showmiss->integer) {
|
||||
cgi.Printf("not moved\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// fire events and other transition triggered things
|
||||
CG_TransitionPlayerState(&cg.predicted_player_state, &oldPlayerState);
|
||||
}
|
||||
|
||||
|
||||
+356
-519
@@ -1,41 +1,45 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
|
||||
// DESCRIPTION:
|
||||
// client game public interfaces
|
||||
|
||||
#ifndef __CG_PUBLIC_H__
|
||||
#define __CG_PUBLIC_H__
|
||||
|
||||
#include <tiki.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#define CMD_BACKUP 128
|
||||
#define CMD_MASK (CMD_BACKUP - 1)
|
||||
#define MAGIC_UNUSED_NUMBER 7777
|
||||
#define CMD_BACKUP 128
|
||||
#define CMD_MASK (CMD_BACKUP - 1)
|
||||
// allow a lot of command backups for very fast systems
|
||||
// multiple commands may be combined into a single packet, so this
|
||||
// needs to be larger than PACKET_BACKUP
|
||||
|
||||
|
||||
#define MAX_ENTITIES_IN_SNAPSHOT 1024
|
||||
#define MAX_SOUNDS_IN_SNAPSHOT 64
|
||||
#define MAX_HUDDRAW_ELEMENTS 256
|
||||
#define MAX_ENTITIES_IN_SNAPSHOT 1024
|
||||
|
||||
// snapshots are a view of the server at a given time
|
||||
|
||||
@@ -43,83 +47,36 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
// but they may not be sent if a client's rate level is exceeded, or
|
||||
// they may be dropped by the network.
|
||||
typedef struct {
|
||||
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
|
||||
int ping;
|
||||
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
|
||||
int ping;
|
||||
|
||||
int serverTime; // server time the message is valid for (in msec)
|
||||
int serverTime; // server time the message is valid for (in msec)
|
||||
|
||||
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
|
||||
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
|
||||
|
||||
playerState_t ps; // complete information about the current player at this time
|
||||
playerState_t ps; // complete information about the current player at this time
|
||||
|
||||
int numEntities; // all of the entities that need to be presented
|
||||
entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
|
||||
int numEntities; // all of the entities that need to be presented
|
||||
entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
|
||||
|
||||
int numServerCommands; // text based server commands to execute when this
|
||||
int serverCommandSequence; // snapshot becomes current
|
||||
int numServerCommands; // text based server commands to execute when this
|
||||
int serverCommandSequence; // snapshot becomes current
|
||||
|
||||
int number_of_sounds;
|
||||
server_sound_t sounds[MAX_SOUNDS_IN_SNAPSHOT];
|
||||
int number_of_sounds;
|
||||
server_sound_t sounds[ MAX_SERVER_SOUNDS ];
|
||||
} snapshot_t;
|
||||
|
||||
typedef struct stopwatch_s {
|
||||
int iStartTime;
|
||||
int iEndTime;
|
||||
} stopwatch_t;
|
||||
|
||||
typedef struct hdelement_s {
|
||||
qhandle_t hShader;
|
||||
char shaderName[ 64 ];
|
||||
int iX;
|
||||
int iY;
|
||||
int iWidth;
|
||||
int iHeight;
|
||||
float vColor[ 4 ];
|
||||
int iHorizontalAlign;
|
||||
int iVerticalAlign;
|
||||
qboolean bVirtualScreen;
|
||||
char string[ 2048 ];
|
||||
char fontName[ 64 ];
|
||||
fontheader_t *pFont;
|
||||
} hdelement_t;
|
||||
|
||||
/*
|
||||
==================================================================
|
||||
|
||||
clientAnim_t structure, wiped each new gamestate
|
||||
reserved for viewmodelanim
|
||||
|
||||
==================================================================
|
||||
*/
|
||||
typedef struct clientAnim_s
|
||||
typedef struct stopWatch_s
|
||||
{
|
||||
frameInfo_t vmFrameInfo[ MAX_FRAMEINFOS ];
|
||||
int lastVMAnim;
|
||||
int lastVMAnimChanged;
|
||||
int iStartTime;
|
||||
int iEndTime;
|
||||
|
||||
int currentVMAnimSlot;
|
||||
int currentVMDuration;
|
||||
|
||||
qboolean crossBlending;
|
||||
|
||||
int lastEquippedWeaponStat;
|
||||
char lastActiveItem[ 80 ];
|
||||
int lastAnimPrefixIndex;
|
||||
|
||||
vec3_t currentVMPosOffset;
|
||||
|
||||
refEntity_t ref;
|
||||
dtiki_t *tiki;
|
||||
|
||||
} clientAnim_t;
|
||||
|
||||
enum {
|
||||
CGAME_EVENT_NONE,
|
||||
CGAME_EVENT_TEAMMENU,
|
||||
CGAME_EVENT_SCOREBOARD,
|
||||
CGAME_EVENT_EDITHUD
|
||||
};
|
||||
} stopWatch_t;
|
||||
|
||||
typedef struct AliasList_s AliasList_t;
|
||||
typedef struct AliasListNode_s AliasListNode_t;
|
||||
typedef struct dtiki_s dtiki_t;
|
||||
typedef struct tiki_cmd_s tiki_cmd_t;
|
||||
|
||||
/*
|
||||
==================================================================
|
||||
@@ -129,416 +86,7 @@ functions imported from the main executable
|
||||
==================================================================
|
||||
*/
|
||||
|
||||
#define CGAME_IMPORT_API_VERSION 4
|
||||
|
||||
#if 0
|
||||
typedef struct clientGameImport_s {
|
||||
|
||||
// print message on the local console
|
||||
void( *Printf )( const char *fmt, ... );
|
||||
void( *DPrintf )( const char *fmt, ... );
|
||||
|
||||
// abort the game
|
||||
void( *Error )( int level, const char *fmt, ... );
|
||||
|
||||
// milliseconds should only be used for performance tuning, never
|
||||
// for anything game related. Get time from the CG_DrawActiveFrame parameter
|
||||
int( *Milliseconds )( void );
|
||||
|
||||
void *( *Malloc )( int size );
|
||||
void( *Free )( void *ptr );
|
||||
|
||||
// console variable interaction
|
||||
cvar_t *( *Cvar_Get )( const char *varName, const char *varValue, int varFlags );
|
||||
void( *Cvar_Register )( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags );
|
||||
void( *Cvar_Update )( vmCvar_t *vmCvar );
|
||||
void( *Cvar_Set )( const char *var_name, const char *value );
|
||||
void( *Cvar_VariableStringBuffer )( const char *var_name, char *buffer, int bufsize );
|
||||
|
||||
// ServerCommand and ConsoleCommand parameter access
|
||||
int( *Argc )( void );
|
||||
char *( *Argv )( int n );
|
||||
char *( *Args )( void );
|
||||
|
||||
// filesystem access
|
||||
// returns length of file
|
||||
int( *FS_FOpenFile )( const char *qpath, fileHandle_t *f, fsMode_t mode );
|
||||
int ( *FS_Read )( void *buffer, int len, fileHandle_t f );
|
||||
int ( *FS_Write )( const void *buffer, int len, fileHandle_t f );
|
||||
void ( *FS_FCloseFile )( fileHandle_t f );
|
||||
int ( *FS_GetFileList )( const char *path, const char *extension, char *listbuf, int bufsize );
|
||||
int ( *FS_Seek )( fileHandle_t f, long offset, fsOrigin_t origin ); // fsOrigin_t
|
||||
int ( *FS_ReadFile )( const char *name, void **buffer, qboolean quiet );
|
||||
void ( *FS_FreeFile )( void *buffer );
|
||||
int ( *FS_WriteFile )( const char *qpath, const void *buffer, int size );
|
||||
int ( *FS_FOpenFileWrite )( const char *name );
|
||||
void ( *FS_Flush )( fileHandle_t f );
|
||||
|
||||
// add commands to the local console as if they were typed in
|
||||
// for map changing, etc. The command is not executed immediately,
|
||||
// but will be executed in order the next time console commands
|
||||
// are processed
|
||||
void( *SendConsoleCommand )( const char *text );
|
||||
|
||||
// register a command name so the console can perform command completion.
|
||||
// FIXME: replace this with a normal console command "defineCommand"?
|
||||
void( *AddCommand )( const char *cmdName, xcommand_t function );
|
||||
|
||||
// send a string to the server over the network
|
||||
void( *SendClientCommand )( const char *s );
|
||||
|
||||
// force a screen update, only used during gamestate load
|
||||
void( *UpdateScreen )( void );
|
||||
|
||||
// model collision
|
||||
void( *CM_LoadMap )( const char *mapname );
|
||||
int( *CM_NumInlineModels )( void );
|
||||
clipHandle_t( *CM_InlineModel )( int index ); // 0 = world, 1+ = bmodels
|
||||
clipHandle_t( *CM_TempBoxModel )( const vec3_t mins, const vec3_t maxs, qboolean capsule );
|
||||
int( *CM_PointContents )( const vec3_t p, clipHandle_t model );
|
||||
int( *CM_TransformedPointContents )( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles );
|
||||
void( *CM_BoxTrace )( trace_t *results, const vec3_t start, const vec3_t end,
|
||||
const vec3_t mins, const vec3_t maxs,
|
||||
clipHandle_t model, int brushmask, qboolean capsule );
|
||||
void( *CM_TransformedBoxTrace )( trace_t *results, const vec3_t start, const vec3_t end,
|
||||
const vec3_t mins, const vec3_t maxs,
|
||||
clipHandle_t model, int brushmask,
|
||||
const vec3_t origin, const vec3_t angles, qboolean capsule );
|
||||
|
||||
// Returns the projection of a polygon onto the solid brushes in the world
|
||||
int( *CM_MarkFragments )( int numPoints, const vec3_t *points,
|
||||
const vec3_t projection,
|
||||
int maxPoints, vec3_t pointBuffer,
|
||||
int maxFragments, markFragment_t *fragmentBuffer );
|
||||
|
||||
// normal sounds will have their volume dynamically changed as their entity
|
||||
// moves and the listener moves
|
||||
void( *S_StartSound )( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx );
|
||||
void( *S_StopLoopingSound )( int entnum );
|
||||
|
||||
// a local sound is always played full volume
|
||||
void( *S_StartLocalSound )( sfxHandle_t sfx, int channelNum );
|
||||
void( *S_ClearLoopingSounds )( qboolean killall );
|
||||
void( *S_AddLoopingSound )( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
||||
void( *S_AddRealLoopingSound )( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
||||
void( *S_UpdateEntityPosition )( int entityNum, const vec3_t origin );
|
||||
|
||||
// respatialize recalculates the volumes of sound as they should be heard by the
|
||||
// given entityNum and position
|
||||
void( *S_Respatialize )( int entityNum, const vec3_t origin, vec3_t axis[ 3 ], int inwater );
|
||||
sfxHandle_t( *S_RegisterSound )( const char *sample, qboolean compressed ); // returns buzz if not found
|
||||
void( *S_StartBackgroundTrack )( const char *intro, const char *loop ); // empty name stops music
|
||||
void( *S_StopBackgroundTrack )( void );
|
||||
|
||||
|
||||
void( *R_LoadWorldMap )( const char *mapname );
|
||||
|
||||
// all media should be registered during level startup to prevent
|
||||
// hitches during gameplay
|
||||
qhandle_t( *R_RegisterModel )( const char *name ); // returns rgb axis if not found
|
||||
qhandle_t( *R_RegisterSkin )( const char *name ); // returns all white if not found
|
||||
qhandle_t( *R_RegisterShader )( const char *name ); // returns all white if not found
|
||||
qhandle_t( *R_RegisterShaderNoMip )( const char *name ); // returns all white if not found
|
||||
|
||||
// a scene is built up by calls to R_ClearScene and the various R_Add functions.
|
||||
// Nothing is drawn until R_RenderScene is called.
|
||||
void( *R_ClearScene )( void );
|
||||
void( *R_AddRefEntityToScene )( const refEntity_t *re );
|
||||
|
||||
// polys are intended for simple wall marks, not really for doing
|
||||
// significant construction
|
||||
void( *R_AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts );
|
||||
void( *R_AddPolysToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys );
|
||||
void( *R_AddLightToScene )( const vec3_t org, float intensity, float r, float g, float b );
|
||||
int( *R_LightForPoint )( vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir );
|
||||
void( *R_RenderScene )( const refdef_t *fd );
|
||||
void( *R_SetColor )( const float *rgba ); // NULL = 1,1,1,1
|
||||
void( *R_DrawStretchPic )( float x, float y, float w, float h,
|
||||
float s1, float t1, float s2, float t2, qhandle_t hShader );
|
||||
void( *R_ModelBounds )( clipHandle_t model, vec3_t mins, vec3_t maxs );
|
||||
int( *R_LerpTag )( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame,
|
||||
float frac, const char *tagName );
|
||||
void( *R_RemapShader )( const char *oldShader, const char *newShader, const char *timeOffset );
|
||||
|
||||
// The glconfig_t will not change during the life of a cgame.
|
||||
// If it needs to change, the entire cgame will be restarted, because
|
||||
// all the qhandle_t are then invalid.
|
||||
void( *GetGlconfig )( glconfig_t *glconfig );
|
||||
|
||||
// the gamestate should be grabbed at startup, and whenever a
|
||||
// configstring changes
|
||||
void( *GetGameState )( gameState_t *gamestate );
|
||||
|
||||
// cgame will poll each frame to see if a newer snapshot has arrived
|
||||
// that it is interested in. The time is returned seperately so that
|
||||
// snapshot latency can be calculated.
|
||||
void( *GetCurrentSnapshotNumber )( int *snapshotNumber, int *serverTime );
|
||||
|
||||
// a snapshot get can fail if the snapshot (or the entties it holds) is so
|
||||
// old that it has fallen out of the client system queue
|
||||
qboolean( *GetSnapshot )( int snapshotNumber, snapshot_t *snapshot );
|
||||
|
||||
// retrieve a text command from the server stream
|
||||
// the current snapshot will hold the number of the most recent command
|
||||
// qfalse can be returned if the client system handled the command
|
||||
// argc )() / argv )() can be used to examine the parameters of the command
|
||||
qboolean( *GetServerCommand )( int serverCommandNumber );
|
||||
|
||||
// returns the most recent command number that can be passed to GetUserCmd
|
||||
// this will always be at least one higher than the number in the current
|
||||
// snapshot, and it may be quite a few higher if it is a fast computer on
|
||||
// a lagged connection
|
||||
int( *GetCurrentCmdNumber )( void );
|
||||
|
||||
qboolean( *GetUserCmd )( int cmdNumber, usercmd_t *ucmd );
|
||||
|
||||
// used for the weapon select and zoom
|
||||
void( *SetUserCmdValue )( int stateValue, float sensitivityScale );
|
||||
|
||||
int( *MemoryRemaining )( void );
|
||||
void( *R_RegisterFont )( const char *fontName, int pointSize, fontInfo_t *font );
|
||||
qboolean( *Key_IsDown )( int keynum );
|
||||
int( *Key_GetCatcher )( void );
|
||||
void( *Key_SetCatcher )( int catcher );
|
||||
int( *Key_GetKey )( const char *binding );
|
||||
|
||||
// ley0k: animation system
|
||||
const char *( *Anim_NameForNum )( tiki_t *tiki, int animNum );
|
||||
int( *Anim_NumForName )( tiki_t *tiki, const char *name );
|
||||
int( *Anim_Random )( tiki_t *tiki, const char *name );
|
||||
int( *Anim_NumFrames )( tiki_t *tiki, int animNum );
|
||||
float( *Anim_Time )( tiki_t *tiki, int animNum );
|
||||
float( *Anim_Frametime )( tiki_t *tiki, int animNum );
|
||||
int ( *Anim_Delta )( tiki_t *tiki, int animNum, vec3_t delta );
|
||||
int ( *Anim_Flags )( tiki_t *tiki, int animNum );
|
||||
float ( *Anim_CrossblendTime )( tiki_t *tiki, int animNum );
|
||||
qboolean ( *Anim_HasCommands )( tiki_t *tiki, int animNum );
|
||||
qboolean ( *Frame_Commands )( tiki_t *tiki, int animNum, int frameNum, tiki_cmd_t *tikiCmds );
|
||||
qboolean( *Frame_CommandsTime )( tiki_t *pmdl, int animNum, float start, float end, tiki_cmd_t *tikiCmd );
|
||||
|
||||
// ley0k: TIKI tags
|
||||
int ( *Tag_NumForName )( tiki_t *tiki, const char * name );
|
||||
const char *( *Tag_NameForNum )( tiki_t *tiki, int num );
|
||||
|
||||
// IneQuation, wombat
|
||||
int ( *R_Text_Width )( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes );
|
||||
int ( *R_Text_Height )( fontInfo_t *font, const char *text, int limit, qboolean useColourCodes );
|
||||
void ( *R_Text_Paint )( fontInfo_t *font, float x, float y, float scale, float alpha, const char *text, float adjust, int limit, qboolean useColourCodes, qboolean is640 );
|
||||
void ( *R_Text_PaintChar )( fontInfo_t *font, float x, float y, float scale, int c, qboolean is640 );
|
||||
// su44: MoHAA TIKI model system API
|
||||
tiki_t* ( *TIKI_RegisterModel )( const char *fname );
|
||||
bone_t* ( *TIKI_GetBones )( int numBones );
|
||||
void ( *TIKI_SetChannels )( struct tiki_s *tiki, int animIndex, float animTime, float animWeight, bone_t *bones );
|
||||
void ( *TIKI_AppendFrameBoundsAndRadius )( struct tiki_s *tiki, int animIndex, float animTime, float *outRadius, vec3_t outBounds[ 2 ] );
|
||||
void ( *TIKI_Animate )( struct tiki_s *tiki, bone_t *bones );
|
||||
int ( *TIKI_GetBoneNameIndex )( const char *boneName );
|
||||
int ( *TIKI_GetAnimIndex )( tiki_t *tiki, const char *animName ); // returns -1 if not found
|
||||
int ( *TIKI_GetBoneIndex )( tiki_t *tiki, const char *boneName ); // returns -1 if not found
|
||||
void ( *SetEyeInfo )( vec3_t origin, vec3_t angles );
|
||||
// su44: these are here only for cg_parsemsg.c
|
||||
int ( *MSG_ReadBits )( int bits );
|
||||
int ( *MSG_ReadByte )();
|
||||
int ( *MSG_ReadShort )();
|
||||
float ( *MSG_ReadCoord )();
|
||||
void ( *MSG_ReadDir )( vec3_t dir );
|
||||
char *( *MSG_ReadString )();
|
||||
// su44: I need these for cg_beam.c
|
||||
int ( *R_GetShaderWidth )( qhandle_t shader );
|
||||
int ( *R_GetShaderHeight )( qhandle_t shader );
|
||||
|
||||
int ( *CIN_PlayCinematic )( const char *arg0, int xpos, int ypos, int width, int height, int bits );
|
||||
e_status ( *CIN_StopCinematic )( int handle );
|
||||
e_status ( *CIN_RunCinematic )( int handle );
|
||||
void ( *CIN_DrawCinematic )( int handle );
|
||||
void ( *CIN_SetExtents )( int handle, int x, int y, int w, int h );
|
||||
|
||||
qboolean ( *loadCamera )( const char *name );
|
||||
void ( *startCamera )( int time );
|
||||
qboolean ( *getCameraInfo )( int time, vec3_t *origin, vec3_t *angles );
|
||||
|
||||
qboolean ( *GetEntityToken )( char *buffer, int bufferSize );
|
||||
|
||||
clientAnim_t *anim;
|
||||
} clientGameImport_t;
|
||||
#endif
|
||||
|
||||
typedef struct clientGameImport_s {
|
||||
|
||||
int apiVersion;
|
||||
|
||||
void ( *Printf )( const char *fmt, ... );
|
||||
void ( *DPrintf )( const char *fmt, ... );
|
||||
void ( *DebugPrintf )( const char *fmt, ... );
|
||||
void * ( *Malloc )( size_t size );
|
||||
void ( *Free )( void *ptr );
|
||||
void ( *Error )( int level, const char *fmt, ... );
|
||||
int ( *Milliseconds )( );
|
||||
const char * ( *LV_ConvertString )( const char *string );
|
||||
cvar_t * ( *Cvar_Get )( const char *varName, const char *varValue, int varFlags );
|
||||
void ( *Cvar_Set )( const char *varName, const char *varValue );
|
||||
int ( *Argc )( );
|
||||
char * ( *Argv )( int arg );
|
||||
char * ( *Args )( );
|
||||
void ( *AddCommand )( const char *cmdName );
|
||||
void ( *Cmd_Stuff )( const char *text );
|
||||
void ( *Cmd_Execute )( int exec_when, const char *text );
|
||||
void ( *Cmd_TokenizeString )( const char *textIn );
|
||||
int ( *FS_ReadFile )( const char *qpath, void **buffer, qboolean quiet );
|
||||
void ( *FS_FreeFile )( void *buffer );
|
||||
int ( *FS_WriteFile )( const char *qpath, const void *buffer, int size );
|
||||
void ( *FS_WriteTextFile )( const char *qpath, const void *buffer, int size );
|
||||
void ( *SendConsoleCommand )( const char *text );
|
||||
int ( *MSG_ReadBits )( int bits );
|
||||
int ( *MSG_ReadChar )( );
|
||||
int ( *MSG_ReadByte )( );
|
||||
int ( *MSG_ReadSVC )( );
|
||||
int ( *MSG_ReadShort )( );
|
||||
int ( *MSG_ReadLong )( );
|
||||
float ( *MSG_ReadFloat )( );
|
||||
char * ( *MSG_ReadString )( );
|
||||
char * ( *MSG_ReadStringLine )( );
|
||||
float ( *MSG_ReadAngle8 )( );
|
||||
float ( *MSG_ReadAngle16 )( );
|
||||
void ( *MSG_ReadData )( void *data, int len );
|
||||
float ( *MSG_ReadCoord )( );
|
||||
void ( *MSG_ReadDir )( vec3_t dir );
|
||||
void ( *SendClientCommand )( const char *text );
|
||||
void ( *CM_LoadMap )( const char *name );
|
||||
clipHandle_t ( *CM_InlineModel )( int index );
|
||||
int ( *CM_NumInlineModels )( );
|
||||
int ( *CM_PointContents )( const vec3_t point, clipHandle_t model );
|
||||
int ( *CM_TransformedPointContents )( const vec3_t point, clipHandle_t model, const vec3_t origin, const vec3_t angles );
|
||||
void ( *CM_BoxTrace )( trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int model, int brushMask, int cylinder );
|
||||
void ( *CM_TransformedBoxTrace )( trace_t *results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int model, int brushMask, const vec3_t origin, const vec3_t angles, int cylinder );
|
||||
clipHandle_t ( *CM_TempBoxModel )( const vec3_t mins, const vec3_t maxs, int contents );
|
||||
void ( *CM_PrintBSPFileSizes )( );
|
||||
qboolean ( *CM_LeafInPVS )( int leaf1, int leaf2 );
|
||||
int ( *CM_PointLeafnum )( const vec3_t p );
|
||||
int ( *R_MarkFragments )( int numPoints, const vec3_t *points, const vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
|
||||
int ( *R_MarkFragmentsForInlineModel )( clipHandle_t bmodel, vec3_t vAngles, vec3_t vOrigin, int numPoints, vec3_t *points, vec3_t projection, int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
|
||||
void ( *R_GetInlineModelBounds )( int index, vec3_t mins, vec3_t maxs );
|
||||
void ( *R_GetLightingForDecal )( vec3_t light, vec3_t facing, vec3_t origin );
|
||||
void ( *R_GetLightingForSmoke )( vec3_t light, vec3_t origin );
|
||||
int ( *R_GatherLightSources )( vec3_t pos, vec3_t *lightPos, vec3_t *lightIntensity, int maxLights );
|
||||
void ( *S_StartSound )( const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed );
|
||||
void ( *S_StartLocalSound )( const char *sound_name );
|
||||
void ( *S_StopSound )( int entNum, int channel );
|
||||
void ( *S_ClearLoopingSounds )( );
|
||||
void ( *S_AddLoopingSound )( const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags );
|
||||
void ( *S_Respatialize )( int entityNum, const vec3_t head, vec3_t axis[3] );
|
||||
void ( *S_BeginRegistration )( );
|
||||
sfxHandle_t ( *S_RegisterSound )( const char *name, qboolean streamed );
|
||||
void ( *S_EndRegistration )( );
|
||||
void ( *S_UpdateEntity )( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean useListener );
|
||||
void ( *S_SetReverb )( int reverbType, float reverbLevel );
|
||||
void ( *S_SetGlobalAmbientVolumeLevel )( float volume );
|
||||
float ( *S_GetSoundTime )( sfxHandle_t handle );
|
||||
int ( *S_ChannelNameToNum )( const char *name );
|
||||
const char * ( *S_ChannelNumToName )( int channel );
|
||||
int ( *S_IsSoundPlaying )( int channelNumber, const char *name );
|
||||
void ( *MUSIC_NewSoundtrack )( const char *name );
|
||||
void( *MUSIC_UpdateMood )( int current, int fallback );
|
||||
void ( *MUSIC_UpdateVolume )( float volume, float fadeTime );
|
||||
float * ( *get_camera_offset )( qboolean *lookActive, qboolean *resetView );
|
||||
void ( *R_ClearScene )( );
|
||||
void ( *R_RenderScene )( const refdef_t *fd );
|
||||
void ( *R_LoadWorldMap )( const char *name );
|
||||
void ( *R_PrintBSPFileSizes )( );
|
||||
int ( *MapVersion )( );
|
||||
int ( *R_MapVersion )( );
|
||||
qhandle_t ( *R_RegisterModel )( const char *name );
|
||||
qhandle_t ( *R_SpawnEffectModel )( const char *name, vec3_t pos, vec3_t axis[3] );
|
||||
qhandle_t ( *R_RegisterServerModel )( const char *name );
|
||||
void ( *R_UnregisterServerModel )( qhandle_t hModel );
|
||||
qhandle_t ( *R_RegisterSkin )( const char *name );
|
||||
qhandle_t ( *R_RegisterShader )( const char *name );
|
||||
qhandle_t ( *R_RegisterShaderNoMip )( const char *name );
|
||||
void ( *R_AddRefEntityToScene )( const refEntity_t *ent, int parentEntityNumber );
|
||||
void ( *R_AddRefSpriteToScene )( const refEntity_t *ent );
|
||||
void ( *R_AddLightToScene )( const vec3_t org, float intensity, float r, float g, float b, int type );
|
||||
qboolean ( *R_AddPolyToScene )( qhandle_t hShader, int numVerts, const polyVert_t *verts, int renderFx );
|
||||
void ( *R_AddTerrainMarkToScene )( int terrainIndex, qhandle_t hShader, int numVerts, polyVert_t *verts, int renderFx );
|
||||
void ( *R_SetColor )( const vec4_t rgba );
|
||||
void ( *R_DrawStretchPic )( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader );
|
||||
fontheader_t * ( *R_LoadFont )( const char *name );
|
||||
void( *R_DrawString )( fontheader_t *font, const char *text, float x, float y, int maxLen, qboolean virtualScreen );
|
||||
refEntity_t * ( *R_GetRenderEntity )( int entityNumber );
|
||||
void ( *R_ModelBounds )( clipHandle_t model, vec3_t mins, vec3_t maxs );
|
||||
float ( *R_ModelRadius )( qhandle_t handle );
|
||||
float ( *R_Noise )( float x, float y, float z, float t );
|
||||
void ( *R_DebugLine )( vec3_t start, vec3_t end, float r, float g, float b, float alpha );
|
||||
baseshader_t * ( *GetShader )( int shaderNum );
|
||||
void ( *R_SwipeBegin )( float thistime, float life, qhandle_t shader );
|
||||
void ( *R_SwipePoint )( vec3_t point1, vec3_t point2, float time );
|
||||
void ( *R_SwipeEnd )( );
|
||||
int ( *R_GetShaderWidth )( qhandle_t hShader );
|
||||
int ( *R_GetShaderHeight )( qhandle_t hShader );
|
||||
void ( *R_DrawBox )( float x, float y, float w, float h );
|
||||
void ( *GetGameState )( gameState_t *gameState );
|
||||
int ( *GetSnapshot )( int snapshotNumber, snapshot_t *snapshot );
|
||||
int ( *GetServerStartTime )( );
|
||||
void ( *SetTime )( int time );
|
||||
void ( *GetCurrentSnapshotNumber )( int *snapshotNumber, int *serverTime );
|
||||
void ( *GetGlconfig )( glconfig_t *glConfig );
|
||||
qboolean ( *GetParseEntityState )( int parseEntityNumber, entityState_t *state );
|
||||
int ( *GetCurrentCmdNumber )( );
|
||||
qboolean ( *GetUserCmd )( int cmdNumber, usercmd_t *userCmd );
|
||||
qboolean ( *GetServerCommand )( int serverCommandNumber, qboolean differentServer );
|
||||
qboolean ( *Alias_Add )( const char *alias, const char *name, const char *parameters );
|
||||
qboolean( *Alias_ListAdd )( AliasList_t *list, const char *alias, const char *name, const char *parameters );
|
||||
const char * ( *Alias_FindRandom )( const char *alias, AliasListNode_t **ret );
|
||||
const char * ( *Alias_ListFindRandom )( AliasList_t *list, const char *alias, AliasListNode_t **ret );
|
||||
void ( *Alias_Dump )( );
|
||||
void ( *Alias_Clear )( );
|
||||
AliasList_t * ( *AliasList_New )( const char *name );
|
||||
void( *Alias_ListFindRandomRange )( AliasList_t *list, const char *alias, int *minIndex, int *maxIndex, float *totalWeight );
|
||||
AliasList_t * ( *Alias_GetGlobalList )( );
|
||||
void ( *UI_ShowMenu )( const char *name, qboolean bForce );
|
||||
void ( *UI_HideMenu )( const char *name, qboolean bForce );
|
||||
int ( *UI_FontStringWidth )( fontheader_t *font, const char *string, int maxLen );
|
||||
int ( *Key_StringToKeynum )( const char *str );
|
||||
const char * ( *Key_KeynumToBindString )( int keyNum );
|
||||
void ( *Key_GetKeysForCommand )( const char *command, int *key1, int *key2 );
|
||||
dtiki_t * ( *R_Model_GetHandle )( qhandle_t handle );
|
||||
int ( *TIKI_NumAnims )( dtiki_t *pmdl );
|
||||
void ( *TIKI_CalculateBounds )( dtiki_t *pmdl, float scale, vec3_t mins, vec3_t maxs );
|
||||
const char * ( *TIKI_Name )( dtiki_t *tiki );
|
||||
void * ( *TIKI_GetSkeletor )( dtiki_t *tiki, int entNum );
|
||||
void ( *TIKI_SetEyeTargetPos )( dtiki_t *tiki, int entNum, vec3_t pos );
|
||||
const char * ( *Anim_NameForNum )( dtiki_t *tiki, int animNum );
|
||||
int ( *Anim_NumForName )( dtiki_t *tiki, const char *name );
|
||||
int ( *Anim_Random )( dtiki_t *tiki, const char *name );
|
||||
int ( *Anim_NumFrames )( dtiki_t *tiki, int animNum );
|
||||
float ( *Anim_Time )( dtiki_t *tiki, int animNum );
|
||||
float ( *Anim_Frametime )( dtiki_t *tiki, int animNum );
|
||||
void ( *Anim_Delta )( dtiki_t *tiki, int animNum, vec3_t delta );
|
||||
int ( *Anim_Flags )( dtiki_t *tiki, int animNum );
|
||||
int ( *Anim_FlagsSkel )( dtiki_t *tiki, int animNum );
|
||||
float ( *Anim_CrossblendTime )( dtiki_t *tiki, int animNum );
|
||||
qboolean ( *Anim_HasCommands )( dtiki_t *tiki, int animNum );
|
||||
qboolean ( *Frame_Commands )( dtiki_t *tiki, int animNum, int frameNum, tiki_cmd_t *tikiCmds );
|
||||
qboolean ( *Frame_CommandsTime )( dtiki_t *pmdl, int animNum, float start, float end, tiki_cmd_t *tikiCmd );
|
||||
int ( *Surface_NameToNum )( dtiki_t *pmdl, const char *name );
|
||||
int ( *Tag_NumForName )( dtiki_t *pmdl, const char *name );
|
||||
const char * ( *Tag_NameForNum )( dtiki_t *pmdl, int animNum );
|
||||
void ( *ForceUpdatePose )( refEntity_t *model );
|
||||
orientation_t ( *TIKI_Orientation )( refEntity_t *model, int tagNum );
|
||||
qboolean ( *TIKI_IsOnGround )( refEntity_t *model, int tagNum, float threshold );
|
||||
void ( *UI_ShowScoreBoard )( const char *menuName );
|
||||
void ( *UI_HideScoreBoard )( );
|
||||
void ( *UI_SetScoreBoardItem )( int itemNumber, const char *data1, const char *data2, const char *data3, const char *data4, const char *data5, const char *data6, const char *data7, const char *data8, vec3_t textColor, vec3_t backColor, qboolean isHeader );
|
||||
void ( *UI_DeleteScoreBoardItems )( int maxIndex );
|
||||
void ( *UI_ToggleDMMessageConsole )( int consoleMode );
|
||||
dtiki_t * ( *TIKI_FindTiki )( const char *path );
|
||||
void ( *LoadResource )( const char *name );
|
||||
void ( *FS_CanonicalFilename )( char *name );
|
||||
|
||||
cvar_t *fsDebug;
|
||||
hdelement_t *hudDrawElements;
|
||||
clientAnim_t *anim;
|
||||
stopwatch_t *stopWatch;
|
||||
void *pUnknownVar;
|
||||
} clientGameImport_t;
|
||||
#define CGAME_IMPORT_API_VERSION 3
|
||||
|
||||
/*
|
||||
==================================================================
|
||||
@@ -548,40 +96,329 @@ functions exported to the main executable
|
||||
==================================================================
|
||||
*/
|
||||
|
||||
typedef struct clientGameExport_s {
|
||||
void ( *CG_Init )( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence, int clientNum );
|
||||
void ( *CG_Shutdown )( void );
|
||||
void ( *CG_DrawActiveFrame )( int serverTime, int frametime, stereoFrame_t stereoView, qboolean demoPlayback );
|
||||
qboolean ( *CG_ConsoleCommand )( void );
|
||||
void ( *CG_GetRendererConfig )( void );
|
||||
void ( *CG_Draw2D )( void );
|
||||
void ( *CG_EyePosition )( vec3_t *eyePos );
|
||||
void ( *CG_EyeOffset )( vec3_t *eyeOffset );
|
||||
void ( *CG_EyeAngles )( vec3_t *eyeAngles );
|
||||
float ( *CG_SensitivityScale )( );
|
||||
void ( *CG_ParseCGMessage )( );
|
||||
void ( *CG_RefreshHudDrawElements )( );
|
||||
void ( *CG_HudDrawShader )( int info );
|
||||
void ( *CG_HudDrawFont )( int info );
|
||||
int ( *CG_GetParent )( int entNum );
|
||||
float ( *CG_GetObjectiveAlpha )( );
|
||||
int ( *CG_PermanentMark )( vec3_t origin, vec3_t dir, float orientation, float sScale, float tScale, float red, float green, float blue, float alpha, qboolean doLighting, float sCenter, float tCenter, markFragment_t *markFragments, void *polyVerts );
|
||||
int ( *CG_PermanentTreadMarkDecal )( treadMark_t *treadMark, qboolean startSegment, qboolean doLighting, markFragment_t *markFragments, void *polyVerts );
|
||||
int ( *CG_PermanentUpdateTreadMark )( treadMark_t *treadMark, float alpha, float minSegment, float maxSegment, float maxOffset, float texScale );
|
||||
void ( *CG_ProcessInitCommands )( dtiki_t *tiki, refEntity_t *ent );
|
||||
void ( *CG_EndTiki )( dtiki_t *tiki );
|
||||
char *( *CG_GetColumnName )( int columnNum, int *columnWidth );
|
||||
void ( *CG_GetScoreBoardColor )( float *red, float *green, float *blue, float *alpha );
|
||||
void ( *CG_GetScoreBoardFontColor )( float *red, float *green, float *blue, float *alpha );
|
||||
int ( *CG_GetScoreBoardDrawHeader )( );
|
||||
void ( *CG_GetScoreBoardPosition )( float *x, float *y, float *width, float *height );
|
||||
int ( *CG_WeaponCommandButtonBits )( );
|
||||
int ( *CG_CheckCaptureKey )( int key, qboolean down, unsigned int time );
|
||||
typedef struct
|
||||
{
|
||||
int apiversion;
|
||||
|
||||
//============== general services ==================
|
||||
|
||||
qboolean ( *CG_Command_ProcessFile )( char *name, qboolean quiet, dtiki_t *curTiki );
|
||||
// print message on the local console
|
||||
void (*Printf)( const char *fmt, ...);
|
||||
void (*DPrintf)( const char *fmt, ...);
|
||||
void (*DebugPrintf)( const char *fmt, ...);
|
||||
|
||||
// managed memory allocation
|
||||
void *(*Malloc)( int size );
|
||||
void (*Free)( void *block );
|
||||
|
||||
// abort the game
|
||||
void (*Error)( int errorLevel, const char *fmt, ...);
|
||||
|
||||
// milliseconds should only be used for profiling, never
|
||||
// for anything game related. Get time from CG_ReadyToBuildScene.
|
||||
int (*Milliseconds)( void );
|
||||
|
||||
// localization
|
||||
const char* (*LV_ConvertString)(const char* string);
|
||||
|
||||
// console variable interaction
|
||||
cvar_t * (*Cvar_Get)( const char *var_name, const char *value, int flags );
|
||||
void (*Cvar_Set)( const char *var_name, const char *value );
|
||||
|
||||
// ClientCommand and ConsoleCommand parameter access
|
||||
int (*Argc)( void );
|
||||
char * (*Argv)( int n );
|
||||
char * (*Args)( void ); // concatenation of all argv >= 1
|
||||
void (*AddCommand)( const char *cmd );
|
||||
void (*Cmd_Stuff)(const char* text);
|
||||
void (*Cmd_Execute)(cbufExec_t execWhen, const char* text);
|
||||
void (*Cmd_TokenizeString)(const char* textIn);
|
||||
|
||||
// a -1 return means the file does not exist
|
||||
// NULL can be passed for buf to just determine existance
|
||||
int (*FS_ReadFile)( const char *name, void **buf, qboolean quiet );
|
||||
void (*FS_FreeFile)( void *buf );
|
||||
int (*FS_WriteFile)( const char *qpath, const void *buffer, int size );
|
||||
void (*FS_WriteTextFile)( const char *qpath, const void *buffer, int size );
|
||||
// add commands to the local console as if they were typed in
|
||||
// for map changing, etc. The command is not executed immediately,
|
||||
// but will be executed in order the next time console commands
|
||||
// are processed
|
||||
void (*SendConsoleCommand)( const char *text );
|
||||
|
||||
// =========== client specific functions ===============
|
||||
|
||||
// send a string to the server over the network
|
||||
int (*MSG_ReadBits)(int bits);
|
||||
int (*MSG_ReadChar)();
|
||||
int (*MSG_ReadByte)();
|
||||
int (*MSG_ReadSVC)();
|
||||
int (*MSG_ReadShort)();
|
||||
int (*MSG_ReadLong)();
|
||||
float (*MSG_ReadFloat)();
|
||||
char* (*MSG_ReadString)();
|
||||
char* (*MSG_ReadStringLine)();
|
||||
float (*MSG_ReadAngle8)();
|
||||
float (*MSG_ReadAngle16)();
|
||||
void (*MSG_ReadData)(void* data, int len);
|
||||
float (*MSG_ReadCoord)();
|
||||
void (*MSG_ReadDir)(vec3_t dir);
|
||||
void (*SendClientCommand)( const char *s );
|
||||
|
||||
// CM functions
|
||||
void (*CM_LoadMap)( const char *name );
|
||||
clipHandle_t (*CM_InlineModel)( int index ); // 0 = world, 1+ = bmodels
|
||||
int (*CM_NumInlineModels)( void );
|
||||
int (*CM_PointContents)( const vec3_t p, int headnode );
|
||||
int (*CM_TransformedPointContents)(const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles);
|
||||
void (*CM_BoxTrace)( trace_t *results, const vec3_t start, const vec3_t end,
|
||||
const vec3_t mins, const vec3_t maxs,
|
||||
int headnode, int brushmask, qboolean cylinder );
|
||||
void (*CM_TransformedBoxTrace)( trace_t *results, const vec3_t start, const vec3_t end,
|
||||
const vec3_t mins, const vec3_t maxs,
|
||||
int headnode, int brushmask,
|
||||
const vec3_t origin, const vec3_t angles,
|
||||
qboolean cylinder
|
||||
);
|
||||
clipHandle_t (*CM_TempBoxModel)( const vec3_t mins, const vec3_t maxs, int contents );
|
||||
void (*CM_PrintBSPFileSizes)();
|
||||
qboolean (*CM_LeafInPVS)(int leaf1, int leaf2);
|
||||
int (*CM_PointLeafnum)(const vec3_t p);
|
||||
int (*R_MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection,
|
||||
int maxPoints, vec3_t pointBuffer,
|
||||
int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
|
||||
int (*R_MarkFragmentsForInlineModel)(clipHandle_t bmodel, const vec3_t vAngles, const vec3_t vOrigin,
|
||||
int numPoints, const vec3_t *points, const vec3_t projection,
|
||||
int maxPoints, vec3_t pointBuffer,
|
||||
int maxFragments, markFragment_t *fragmentBuffer, float fRadiusSquared );
|
||||
|
||||
void (*R_GetInlineModelBounds)(int index, vec3_t mins, vec3_t maxs);
|
||||
void (*R_GetLightingForDecal)(vec3_t light, vec3_t facing, vec3_t origin);
|
||||
void (*R_GetLightingForSmoke)(vec3_t light, vec3_t origin);
|
||||
int (*R_GatherLightSources)(const vec3_t pos, vec3_t* lightPos, vec3_t* lightIntensity, int maxLights);
|
||||
|
||||
// =========== sound function calls ===============
|
||||
|
||||
void (*S_StartSound)(const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed);
|
||||
void (*S_StartLocalSound)(const char* soundName, qboolean forceLoad);
|
||||
void (*S_StopSound)( int entnum, int channel );
|
||||
void (*S_ClearLoopingSounds)(void);
|
||||
void (*S_AddLoopingSound)(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags);
|
||||
void (*S_Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3] );
|
||||
void (*S_BeginRegistration)( void );
|
||||
sfxHandle_t (*S_RegisterSound)( const char *sample, int streamed );
|
||||
void (*S_EndRegistration)( void );
|
||||
void (*S_UpdateEntity)( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener );
|
||||
void (*S_SetReverb)( int reverb_type, float reverb_level );
|
||||
void (*S_SetGlobalAmbientVolumeLevel)( float volume );
|
||||
float (*S_GetSoundTime)(sfxHandle_t handle);
|
||||
int (*S_ChannelNameToNum)(const char* name);
|
||||
const char* (*S_ChannelNumToName)(int channel);
|
||||
int (*S_IsSoundPlaying)(int channelNumber, const char* name);
|
||||
|
||||
// =========== music function calls ===============
|
||||
|
||||
void (*MUSIC_NewSoundtrack)( const char *name );
|
||||
void (*MUSIC_UpdateMood)( int current_mood, int fallback_mood );
|
||||
void (*MUSIC_UpdateVolume)( float volume, float fade_time );
|
||||
|
||||
// =========== camera function calls ===============
|
||||
|
||||
float * (*get_camera_offset)( qboolean *lookactive, qboolean *resetview );
|
||||
|
||||
// =========== renderer function calls ================
|
||||
void (*R_ClearScene)( void );
|
||||
void (*R_RenderScene)( const refdef_t *fd );
|
||||
void (*R_LoadWorldMap)(const char* mapname);
|
||||
void (*R_PrintBSPFileSizes)();
|
||||
int (*MapVersion)();
|
||||
int (*R_MapVersion)();
|
||||
qhandle_t (*R_RegisterModel)( const char *name );
|
||||
qhandle_t (*R_SpawnEffectModel)(const char* name, vec3_t pos, vec3_t axis[3]);
|
||||
qhandle_t (*R_RegisterServerModel)(const char* name);
|
||||
void (*R_UnregisterServerModel)(qhandle_t hModel);
|
||||
qhandle_t (*R_RegisterSkin)( const char *name );
|
||||
qhandle_t (*R_RegisterShader)( const char *name );
|
||||
qhandle_t (*R_RegisterShaderNoMip)( const char *name );
|
||||
void (*R_AddRefEntityToScene)(const refEntity_t *ent, int parentEntityNumber );
|
||||
void (*R_AddRefSpriteToScene)(const refEntity_t *ent );
|
||||
void (*R_AddLightToScene)(const vec3_t origin, float intensity, float r, float g, float b, int type );
|
||||
qboolean (*R_AddPolyToScene)(qhandle_t hShader, int numVerts, const polyVert_t* verts, int renderfx);
|
||||
void (*R_AddTerrainMarkToScene)(int terrainIndex, qhandle_t hShader, int numVerts, const polyVert_t* verts, int renderFx);
|
||||
void (*R_SetColor)( const vec4_t rgba ); // NULL = 1,1,1,1
|
||||
void (*R_DrawStretchPic) ( float x, float y, float w, float h,
|
||||
float s1, float t1, float s2, float t2,
|
||||
qhandle_t hShader ); // 0 = white
|
||||
fontheader_t* (*R_LoadFont)(const char* name);
|
||||
void (*R_DrawString)(fontheader_t* font, const char* text, float x, float y, int maxLen, qboolean virtualScreen);
|
||||
refEntity_t * (*R_GetRenderEntity)( int entityNumber );
|
||||
void (*R_ModelBounds)( clipHandle_t model, vec3_t mins, vec3_t maxs );
|
||||
float (*R_ModelRadius)( clipHandle_t model );
|
||||
float (*R_Noise)( float x, float y, float z, float t );
|
||||
void (*R_DebugLine)(const vec3_t start, const vec3_t end, float r, float g, float b, float alpha);
|
||||
baseshader_t* (*GetShader)(int shaderNum);
|
||||
// =========== Swipes =============
|
||||
void (*R_SwipeBegin) ( float thistime, float life, qhandle_t shader );
|
||||
void (*R_SwipePoint) ( vec3_t p1, vec3_t p2, float time );
|
||||
void (*R_SwipeEnd) ( void );
|
||||
int (*R_GetShaderWidth)( qhandle_t shader );
|
||||
int (*R_GetShaderHeight)( qhandle_t shader );
|
||||
void (*R_DrawBox)( float x, float y, float w, float h );
|
||||
|
||||
// =========== data shared with the client =============
|
||||
void (*GetGameState)( gameState_t *gamestate );
|
||||
int (*GetSnapshot)( int snapshotNumber, snapshot_t *snapshot );
|
||||
int (*GetServerStartTime)();
|
||||
void (*SetTime)(int time);
|
||||
void (*GetCurrentSnapshotNumber)( int *snapshotNumber, int *serverTime );
|
||||
void (*GetGlconfig)( glconfig_t *glconfig );
|
||||
|
||||
// will return false if the number is so old that it doesn't exist in the buffer anymore
|
||||
qboolean (*GetParseEntityState)( int parseEntityNumber, entityState_t *state );
|
||||
int (*GetCurrentCmdNumber)( void ); // returns the most recent command number
|
||||
// which is the local predicted command for
|
||||
// the following frame
|
||||
qboolean (*GetUserCmd)( int cmdNumber, usercmd_t *ucmd );
|
||||
qboolean (*GetServerCommand)(int serverCommandNumber, qboolean differentServer);
|
||||
|
||||
// ALIAS STUFF
|
||||
qboolean (*Alias_Add)( const char * alias, const char * name, const char *parameters );
|
||||
qboolean (*Alias_ListAdd)(AliasList_t* list, const char* alias, const char* name, const char* parameters);
|
||||
const char* (*Alias_FindRandom)(const char* alias, AliasListNode_t **ret);
|
||||
const char* (*Alias_ListFindRandom)(AliasList_t* list, const char* alias, AliasListNode_t** ret);
|
||||
void (*Alias_Dump)( void );
|
||||
void (*Alias_Clear)( void );
|
||||
AliasList_t* (*AliasList_New)(const char* name);
|
||||
void (*Alias_ListFindRandomRange)(AliasList_t* list, const char* alias, int* minIndex, int* maxIndex, float* totalWeight);
|
||||
AliasList_t* (*Alias_GetGlobalList)();
|
||||
|
||||
// ==================== UI STUFF ==========================
|
||||
void (*UI_ShowMenu)(const char* name, qboolean bForce);
|
||||
void (*UI_HideMenu)(const char* name, qboolean bForce);
|
||||
int (*UI_FontStringWidth)(fontheader_t* font, const char* string, int maxLen);
|
||||
|
||||
int (*Key_StringToKeynum)(const char* str);
|
||||
const char* (*Key_KeynumToBindString)(int keyNum);
|
||||
void (*Key_GetKeysForCommand)(const char* command, int* key1, int* key2);
|
||||
|
||||
// ==================== TIKI STUFF ==========================
|
||||
// TIKI SPECIFIC STUFF
|
||||
dtiki_t* (*R_Model_GetHandle)(qhandle_t handle);
|
||||
int (*TIKI_NumAnims)(dtiki_t* pmdl);
|
||||
void (*TIKI_CalculateBounds)(dtiki_t* pmdl, float scale, vec3_t mins, vec3_t maxs);
|
||||
const char* (*TIKI_Name)(dtiki_t* tiki);
|
||||
void* (*TIKI_GetSkeletor)(dtiki_t* tiki, int entNum);
|
||||
void (*TIKI_SetEyeTargetPos)(dtiki_t* tiki, int entNum, vec3_t pos);
|
||||
|
||||
// ANIM SPECIFIC STUFF
|
||||
const char * (*Anim_NameForNum) (dtiki_t* tiki, int animnum );
|
||||
int (*Anim_NumForName) (dtiki_t* tiki, const char * name );
|
||||
int (*Anim_Random) (dtiki_t* tiki, const char * name );
|
||||
int (*Anim_NumFrames) (dtiki_t* tiki, int animnum );
|
||||
float (*Anim_Time) (dtiki_t* tiki, int animnum);
|
||||
float (*Anim_Frametime) (dtiki_t* tiki, int animnum);
|
||||
void (*Anim_Delta) (dtiki_t* tiki, int animnum, vec3_t delta );
|
||||
int (*Anim_Flags) (dtiki_t* tiki, int animnum);
|
||||
int (*Anim_FlagsSkel) (dtiki_t* tiki, int animnum);
|
||||
float (*Anim_CrossblendTime) (dtiki_t* tiki, int animnum );
|
||||
qboolean (*Anim_HasCommands) (dtiki_t* tiki, int animnum );
|
||||
|
||||
// FRAME SPECIFIC STUFF
|
||||
qboolean (*Frame_Commands) (dtiki_t* tiki, int animnum, int framenum, tiki_cmd_t * tiki_cmd );
|
||||
qboolean (*Frame_CommandsTime) (dtiki_t* tiki, int animnum, float start, float end, tiki_cmd_t * tiki_cmd );
|
||||
|
||||
// SURFACE SPECIFIC STUFF
|
||||
int (*Surface_NameToNum) (dtiki_t* tiki, const char * name );
|
||||
//const char * (*Surface_NumToName) (dtiki_t* tiki, int num );
|
||||
//int (*Surface_Flags) (dtiki_t* tiki, int num );
|
||||
//int (*Surface_NumSkins) (dtiki_t* tiki, int num );
|
||||
|
||||
// TAG SPECIFIC STUFF
|
||||
int (*Tag_NumForName) (dtiki_t* tiki, const char * name );
|
||||
const char * (*Tag_NameForNum) (dtiki_t* tiki, int num );
|
||||
void (*ForceUpdatePose)(refEntity_t* model);
|
||||
orientation_t (*TIKI_Orientation)(refEntity_t* model, int tagNum);
|
||||
qboolean (*TIKI_IsOnGround)(refEntity_t* model, int tagNum, float threshold);
|
||||
|
||||
// MISCELLANEOUS SPECIFIC STUFF
|
||||
void (*UI_ShowScoreBoard)(const char* menuName);
|
||||
void (*UI_HideScoreBoard)();
|
||||
void (*UI_SetScoreBoardItem)(int itemNumber, const char* data1,
|
||||
const char* data2, const char* data3,
|
||||
const char* data4, const char* data5,
|
||||
const char* data6, const char* data7,
|
||||
const char* data8, const vec4_t textColor,
|
||||
const vec4_t backColor, qboolean isHeader);
|
||||
void (*UI_DeleteScoreBoardItems)(int maxIndex);
|
||||
void (*UI_ToggleDMMessageConsole)(int consoleMode);
|
||||
dtiki_t* (*TIKI_FindTiki)(const char* path);
|
||||
void (*LoadResource)(const char* name);
|
||||
void (*FS_CanonicalFilename)(char* name);
|
||||
|
||||
cvar_t* fsDebug;
|
||||
hdelement_t* HudDrawElements;
|
||||
clientAnim_t* anim;
|
||||
stopWatch_t* stopWatch;
|
||||
|
||||
} clientGameImport_t;
|
||||
|
||||
|
||||
/*
|
||||
==================================================================
|
||||
|
||||
functions exported to the main executable
|
||||
|
||||
==================================================================
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
void (*CG_Init)( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence, int clientNum );
|
||||
void (*CG_Shutdown)( void );
|
||||
void (*CG_DrawActiveFrame)( int serverTime, int frameTime, stereoFrame_t stereoView, qboolean demoPlayback );
|
||||
qboolean (*CG_ConsoleCommand)( void );
|
||||
void (*CG_GetRendererConfig)( void );
|
||||
void (*CG_Draw2D)( void );
|
||||
void (*CG_EyePosition)(vec3_t* eyePos);
|
||||
void (*CG_EyeOffset)(vec3_t* eyeOffset);
|
||||
void (*CG_EyeAngles)(vec3_t* eyeAngles);
|
||||
float (*CG_SensitivityScale)();
|
||||
void (*CG_ParseCGMessage)();
|
||||
void (*CG_RefreshHudDrawElements)();
|
||||
void (*CG_HudDrawShader)(int info);
|
||||
void (*CG_HudDrawFont)(int info);
|
||||
int (*CG_GetParent)(int entNum);
|
||||
float (*CG_GetObjectiveAlpha)();
|
||||
int (*CG_PermanentMark)(const vec3_t origin, const vec3_t dir, float orientation, float sScale, float tScale, float red, float green, float blue, float alpha, qboolean doLighting, float sCenter, float tCenter, markFragment_t* markFragments, void* polyVerts);
|
||||
int (*CG_PermanentTreadMarkDecal)(treadMark_t* treadMark, qboolean startSegment, qboolean doLighting, markFragment_t* markFragments, void* polyVerts);
|
||||
int (*CG_PermanentUpdateTreadMark)(treadMark_t* treadMark, float alpha, float minSegment, float maxSegment, float maxOffset, float texScale);
|
||||
void (*CG_ProcessInitCommands)(dtiki_t* tiki, refEntity_t* ent);
|
||||
void (*CG_EndTiki)(dtiki_t* tiki);
|
||||
const char* (*CG_GetColumnName)(int columnNum, int* columnWidth);
|
||||
void (*CG_GetScoreBoardColor)(float* red, float* green, float* blue, float* alpha);
|
||||
void (*CG_GetScoreBoardFontColor)(float* red, float* green, float* blue, float* alpha);
|
||||
int (*CG_GetScoreBoardDrawHeader)();
|
||||
void (*CG_GetScoreBoardPosition)(float* x, float* y, float* width, float* height);
|
||||
int (*CG_WeaponCommandButtonBits)();
|
||||
int (*CG_CheckCaptureKey)(int key, qboolean down, unsigned int time);
|
||||
|
||||
// FIXME
|
||||
//prof_cgame_t* profStruct;
|
||||
|
||||
qboolean (*CG_Command_ProcessFile)(const char* name, qboolean quiet, dtiki_t* curTiki);
|
||||
|
||||
} clientGameExport_t;
|
||||
|
||||
//----------------------------------------------
|
||||
#ifdef CGAME_DLL
|
||||
#ifdef WIN32
|
||||
__declspec(dllexport)
|
||||
#else
|
||||
__attribute__((visibility("default")))
|
||||
#endif
|
||||
#endif
|
||||
clientGameExport_t* GetCGameAPI(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __CG_PUBLIC_H__
|
||||
@@ -1,175 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 su44
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// cg_rain.c - MoHAA rain/snow effects
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
void CG_InitRainEffect() {
|
||||
cg.rain.density = 0;
|
||||
cg.rain.speed = 2048.0;
|
||||
cg.rain.length = 90.0;
|
||||
cg.rain.min_dist = 512.0;
|
||||
cg.rain.width = 1.f;
|
||||
cg.rain.speed_vary = 512;
|
||||
cg.rain.slant = 50;
|
||||
memset(cg.rain.shader,0,sizeof(cg.rain.shader));
|
||||
strcpy(cg.rain.shader[0],"textures/hud/allies"); // only for debuging
|
||||
cg.rain.numshaders = 0;
|
||||
}
|
||||
|
||||
void CG_RainCSUpdated(int num, const char *str) {
|
||||
if( num == CS_RAIN_DENSITY ) {
|
||||
cg.rain.density = atof(str);
|
||||
} else if( num == CS_RAIN_SPEED ) {
|
||||
cg.rain.speed = atof(str);
|
||||
} else if( num == CS_RAIN_SPEEDVARY ) {
|
||||
cg.rain.speed_vary = atof(str);
|
||||
} else if( num == CS_RAIN_SLANT ) {
|
||||
cg.rain.slant = atof(str);
|
||||
} else if( num == CS_RAIN_LENGTH ) {
|
||||
cg.rain.length = atof(str);
|
||||
} else if( num == CS_RAIN_MINDIST ) {
|
||||
cg.rain.min_dist = atof(str);
|
||||
} else if( num == CS_RAIN_WIDTH ) {
|
||||
cg.rain.width = atof(str);
|
||||
} else if( num == CS_RAIN_SHADER ) {
|
||||
if(cg.rain.numshaders) {
|
||||
int i;
|
||||
for(i = 0; i < cg.rain.numshaders; i++) {
|
||||
sprintf(cg.rain.shader[i],"%s%i",str,i);
|
||||
}
|
||||
}
|
||||
} else if( num == CS_RAIN_NUMSHADERS ) {
|
||||
cg.rain.numshaders = atoi(str);
|
||||
} else {
|
||||
CG_Error("CG_RainCSUpdated: unknown cs index\n");
|
||||
}
|
||||
}
|
||||
|
||||
void CG_Rain(centity_t *cent) {
|
||||
char *shadername;
|
||||
vec3_t vEnd;
|
||||
vec3_t vStart;
|
||||
//vec4_t fcolor;
|
||||
byte fcolor[4]; // su44: in MoHAA that's a float[4]
|
||||
vec3_t maxs;
|
||||
vec3_t mins;
|
||||
float f;
|
||||
vec3_t tMins,tMaxs;
|
||||
vec3_t size;
|
||||
int i;
|
||||
int density;
|
||||
int r;
|
||||
|
||||
fcolor[0] = 1.f;
|
||||
fcolor[1] = 1.f;
|
||||
fcolor[2] = 1.f;
|
||||
fcolor[3] = 1.f;
|
||||
//if ( !cg_rain.integer )
|
||||
// return;
|
||||
cgi.R_ModelBounds(cgs.gameModels[cent->currentState.modelindex],mins,maxs);
|
||||
|
||||
tMins[0] = mins[0] + cent->lerpOrigin[0];
|
||||
f = cg.snap->ps.origin[0] - cg.rain.min_dist;
|
||||
if ( f > tMins[0] )
|
||||
tMins[0] = f;
|
||||
|
||||
tMins[1] = mins[1] + cent->lerpOrigin[1];
|
||||
f = cg.snap->ps.origin[1] - cg.rain.min_dist;
|
||||
if ( f > tMins[1] )
|
||||
tMins[1] = f;
|
||||
tMins[2] = mins[2] + cent->lerpOrigin[2];
|
||||
|
||||
tMaxs[0] = maxs[0] + cent->lerpOrigin[0];
|
||||
f = cg.snap->ps.origin[0] + cg.rain.min_dist;
|
||||
if ( f > tMaxs[0] )
|
||||
tMaxs[0] = f;
|
||||
|
||||
tMaxs[1] = maxs[1] + cent->lerpOrigin[1];
|
||||
f = cg.snap->ps.origin[1] + cg.rain.min_dist;
|
||||
if( f > tMaxs[1] )
|
||||
tMaxs[1] = f;
|
||||
|
||||
tMaxs[2] = maxs[2] + cent->lerpOrigin[2];
|
||||
if ( tMins[0] >= tMaxs[0] )
|
||||
return;
|
||||
|
||||
if (tMins[1] >= tMaxs[1] )
|
||||
return;
|
||||
|
||||
|
||||
size[0] = tMaxs[0] - tMins[0];
|
||||
size[1] = tMaxs[1] - tMins[1];
|
||||
size[2] = tMaxs[2] - tMins[2];
|
||||
density = (signed int)(cg.rain.density / 200.0 * sqrt(size[1] * size[0]));
|
||||
if ( density > 4096 )
|
||||
density = 4096;
|
||||
r = rand();
|
||||
if ( cg.rain.numshaders ) {
|
||||
shadername = &cg.rain.shader[r % cg.rain.numshaders][0];
|
||||
} else {
|
||||
shadername = &cg.rain.shader[0][0];
|
||||
}
|
||||
for(i = 0; i < density; i++) {
|
||||
int iLife;
|
||||
|
||||
iLife = (signed int)(size[2] / ((long double)(r % cg.rain.speed_vary) + cg.rain.speed) * 1000.0);
|
||||
f = (long double)(r % (signed int)(size[0] + 1.0));
|
||||
r = ((214013 * r + 2531011) >> 16) & 0x7FFF;
|
||||
vStart[2] = tMaxs[2];
|
||||
vStart[0] = f + tMins[0];
|
||||
vStart[1] = (long double)(r % (signed int)(size[1] + 1.0)) + tMins[1];
|
||||
//if( )
|
||||
{
|
||||
f = r % cg.rain.slant;
|
||||
r = ((214013 * r + 2531011) >> 16) & 0x7FFF;
|
||||
vEnd[0] = f + vStart[0] + /*vss_wind_x->value*/8;
|
||||
vEnd[1] = (r % cg.rain.slant) + vStart[1] + /*vss_wind_y->value*/4;
|
||||
vEnd[2] = tMins[2];
|
||||
CG_CreateBeam(
|
||||
vStart, // start
|
||||
vec3_origin,// dir
|
||||
0, // owner
|
||||
1, // model
|
||||
1.0, // alpha
|
||||
cg.rain.width, // scale
|
||||
16384, // flags
|
||||
0, // length <- isnt smth wrong there?
|
||||
iLife, // life
|
||||
1, // create
|
||||
vEnd, // endpointvec
|
||||
0, // min_offset
|
||||
0, // max_offset
|
||||
0, // overlap
|
||||
1, // numSubdivisions
|
||||
0, // delay
|
||||
shadername, // beamshadername
|
||||
fcolor, // modulate (byte[4] here, float[4] in MoHAA)
|
||||
0, // numspherebeams
|
||||
0.0, // sphereradius
|
||||
cg.rain.length, // toggledelay
|
||||
1.0, // endalpha
|
||||
0, // renderfx
|
||||
"raineffect"); // name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,723 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// Scoreboard
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
void CG_GetScoreBoardColor(float* fR, float* fG, float* fB, float* fA)
|
||||
{
|
||||
*fR = 0.0f;
|
||||
*fG = 0.0f;
|
||||
*fB = 0.0f;
|
||||
*fA = 0.7f;
|
||||
}
|
||||
|
||||
void CG_GetScoreBoardFontColor(float* fR, float* fG, float* fB, float* fA)
|
||||
{
|
||||
*fR = 1.0f;
|
||||
*fG = 1.0f;
|
||||
*fB = 1.0f;
|
||||
*fA = 1.0f;
|
||||
}
|
||||
|
||||
void CG_GetScoreBoardPosition(float* fX, float* fY, float* fW, float* fH)
|
||||
{
|
||||
*fX = 32.0;
|
||||
*fY = 56.0;
|
||||
*fW = 384.0;
|
||||
*fH = 392.0;
|
||||
}
|
||||
|
||||
int CG_GetScoreBoardDrawHeader()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CG_PrepScoreBoardInfo()
|
||||
{
|
||||
switch (cgs.gametype) {
|
||||
case GT_TEAM_ROUNDS:
|
||||
strcpy(cg.scoresMenuName, "DM_Round_Scoreboard");
|
||||
break;
|
||||
case GT_OBJECTIVE:
|
||||
strcpy(cg.scoresMenuName, "Obj_Scoreboard");
|
||||
break;
|
||||
case GT_TOW:
|
||||
strcpy(cg.scoresMenuName, "Tow_Scoreboard");
|
||||
break;
|
||||
case GT_LIBERATION:
|
||||
strcpy(cg.scoresMenuName, "Lib_Scoreboard");
|
||||
break;
|
||||
default:
|
||||
strcpy(cg.scoresMenuName, "DM_Scoreboard");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_GAME_PROTOCOL >= 15
|
||||
|
||||
const char* CG_GetColumnName(int iColumnNum, int* iColumnWidth)
|
||||
{
|
||||
int iReturnWidth;
|
||||
const char* pszReturnString;
|
||||
|
||||
switch (iColumnNum) {
|
||||
case 0:
|
||||
iReturnWidth = 24;
|
||||
pszReturnString = "#";
|
||||
break;
|
||||
case 1:
|
||||
iReturnWidth = 128;
|
||||
pszReturnString = "Name";
|
||||
break;
|
||||
case 2:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Kills";
|
||||
break;
|
||||
case 3:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Deaths";
|
||||
if (cgs.gametype > GT_TEAM) {
|
||||
pszReturnString = "Total";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Time";
|
||||
break;
|
||||
case 5:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Ping";
|
||||
break;
|
||||
default:
|
||||
iReturnWidth = 0;
|
||||
pszReturnString = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (iColumnWidth) {
|
||||
*iColumnWidth = iReturnWidth;
|
||||
}
|
||||
|
||||
return pszReturnString;
|
||||
}
|
||||
|
||||
void CG_ParseScores()
|
||||
{
|
||||
int i;
|
||||
int iEntryCount;
|
||||
int iClientTeam, iClientNum;
|
||||
int iDatumCount;
|
||||
int iMatchTeam;
|
||||
int iCurrentEntry;
|
||||
qboolean bIsDead, bIsHeader;
|
||||
char szString2[MAX_STRING_TOKENS];
|
||||
char szString3[MAX_STRING_TOKENS];
|
||||
char szString4[MAX_STRING_TOKENS];
|
||||
char szString5[MAX_STRING_TOKENS];
|
||||
char szString6[MAX_STRING_TOKENS];
|
||||
char szString7[MAX_STRING_TOKENS];
|
||||
float vSameTeamTextColor[4];
|
||||
float vSameTeamBackColor[4];
|
||||
float vOtherTeamTextColor[4];
|
||||
float vOtherTeamBackColor[4];
|
||||
float vNoTeamTextColor[4];
|
||||
float vNoTeamBackColor[4];
|
||||
float vThisClientTextColor[4];
|
||||
float vThisClientBackColor[4];
|
||||
float vDeadTextColorDead[4];
|
||||
float* pItemTextColor;
|
||||
float* pItemBackColor;
|
||||
|
||||
iMatchTeam = -1;
|
||||
vSameTeamTextColor[0] = 1.0f;
|
||||
vSameTeamTextColor[1] = 1.0f;
|
||||
vSameTeamTextColor[2] = 1.0f;
|
||||
vSameTeamTextColor[3] = 1.0f;
|
||||
vSameTeamBackColor[0] = 0.1f;
|
||||
vSameTeamBackColor[1] = 0.5f;
|
||||
vSameTeamBackColor[2] = 0.1f;
|
||||
vSameTeamBackColor[3] = 0.4f;
|
||||
vOtherTeamTextColor[0] = 1.0f;
|
||||
vOtherTeamTextColor[1] = 1.0f;
|
||||
vOtherTeamTextColor[2] = 1.0f;
|
||||
vOtherTeamTextColor[3] = 1.0f;
|
||||
vOtherTeamBackColor[0] = 0.5f;
|
||||
vOtherTeamBackColor[1] = 0.1f;
|
||||
vOtherTeamBackColor[2] = 0.1f;
|
||||
vOtherTeamBackColor[3] = 0.4f;
|
||||
vNoTeamTextColor[0] = 1.0f;
|
||||
vNoTeamTextColor[1] = 1.0f;
|
||||
vNoTeamTextColor[2] = 1.0f;
|
||||
vNoTeamTextColor[3] = 1.0f;
|
||||
vNoTeamBackColor[0] = 0.1f;
|
||||
vNoTeamBackColor[1] = 0.1f;
|
||||
vNoTeamBackColor[2] = 0.1f;
|
||||
vNoTeamBackColor[3] = 0.4f;
|
||||
vDeadTextColorDead[0] = 1.0f;
|
||||
vDeadTextColorDead[1] = 0.1f;
|
||||
vDeadTextColorDead[2] = 0.1f;
|
||||
vDeadTextColorDead[3] = 1.0f;
|
||||
|
||||
vThisClientTextColor[0] = 0.0f;
|
||||
vThisClientTextColor[1] = 0.0f;
|
||||
vThisClientTextColor[2] = 0.0f;
|
||||
vThisClientTextColor[3] = 1.0f;
|
||||
|
||||
if (cgs.gametype > GT_FFA)
|
||||
{
|
||||
vThisClientBackColor[0] = 0.5f;
|
||||
vThisClientBackColor[1] = 0.75f;
|
||||
vThisClientBackColor[2] = 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
vThisClientBackColor[0] = 0.75f;
|
||||
vThisClientBackColor[1] = 0.75f;
|
||||
vThisClientBackColor[2] = 0.75f;
|
||||
}
|
||||
|
||||
vThisClientBackColor[3] = 0.8f;
|
||||
|
||||
iCurrentEntry = 1;
|
||||
if (cgs.gametype > GT_FFA)
|
||||
{
|
||||
iDatumCount = 6;
|
||||
iMatchTeam = cg.snap->ps.stats[STAT_TEAM];
|
||||
if (iMatchTeam != TEAM_ALLIES && iMatchTeam != TEAM_AXIS)
|
||||
{
|
||||
iMatchTeam = TEAM_ALLIES;
|
||||
vThisClientTextColor[0] = 0.0f;
|
||||
vThisClientTextColor[1] = 0.0f;
|
||||
vThisClientTextColor[2] = 0.0f;
|
||||
vThisClientBackColor[0] = 0.75f;
|
||||
vThisClientBackColor[1] = 0.75f;
|
||||
vThisClientBackColor[2] = 0.75f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// free-for-all
|
||||
iDatumCount = 5;
|
||||
}
|
||||
|
||||
iEntryCount = atoi(cgi.Argv(iCurrentEntry++));
|
||||
if (iEntryCount > MAX_CLIENTS) {
|
||||
iEntryCount = MAX_CLIENTS;
|
||||
}
|
||||
|
||||
if (cgs.gametype == GT_TOW)
|
||||
{
|
||||
cgi.Cvar_Set("tow_allied_obj1", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_allied_obj2", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_allied_obj3", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_allied_obj4", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_allied_obj5", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_axis_obj1", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_axis_obj2", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_axis_obj3", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_axis_obj4", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("tow_axis_obj5", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
}
|
||||
|
||||
if (cgs.gametype == GT_LIBERATION)
|
||||
{
|
||||
cgi.Cvar_Set("scoreboard_toggle1", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
cgi.Cvar_Set("scoreboard_toggle2", va("%i", cgi.Argv(iCurrentEntry++)));
|
||||
}
|
||||
|
||||
for (i = 0; i < iEntryCount; ++i)
|
||||
{
|
||||
bIsHeader = qfalse;
|
||||
if (cgs.gametype > GT_FFA)
|
||||
{
|
||||
iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i));
|
||||
iClientTeam = atoi(cgi.Argv(1 + iCurrentEntry + iDatumCount * i));
|
||||
if (iClientTeam >= 0) {
|
||||
bIsDead = qfalse;
|
||||
}
|
||||
else {
|
||||
bIsDead = qtrue;
|
||||
iClientTeam = -iClientTeam;
|
||||
}
|
||||
|
||||
if (iClientNum == -1)
|
||||
{
|
||||
szString2[0] = 0;
|
||||
bIsHeader = qtrue;
|
||||
|
||||
switch (iClientTeam)
|
||||
{
|
||||
case 1:
|
||||
strcpy(szString3, cgi.LV_ConvertString("Spectators"));
|
||||
break;
|
||||
case 2:
|
||||
strcpy(szString3, cgi.LV_ConvertString("Free-For-Allers"));
|
||||
break;
|
||||
case 3:
|
||||
sprintf(
|
||||
szString3,
|
||||
"%s - %d %s",
|
||||
cgi.LV_ConvertString("Allies"),
|
||||
atoi(cgi.Argv(2 + iCurrentEntry + iDatumCount * i)),
|
||||
cgi.LV_ConvertString("Players")
|
||||
);
|
||||
iCurrentEntry++;
|
||||
break;
|
||||
case 4:
|
||||
sprintf(
|
||||
szString3,
|
||||
"%s - %d %s",
|
||||
cgi.LV_ConvertString("Axis"),
|
||||
atoi(cgi.Argv(2 + iCurrentEntry + iDatumCount * i)),
|
||||
cgi.LV_ConvertString("Players")
|
||||
);
|
||||
iCurrentEntry++;
|
||||
break;
|
||||
default:
|
||||
strcpy(szString3, cgi.LV_ConvertString("No Team"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (iClientNum == -2)
|
||||
{
|
||||
// spectating
|
||||
szString2[0] = 0;
|
||||
szString3[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(szString2, va("%i", iClientNum));
|
||||
strcpy(szString3, cg.clientinfo[iClientNum].name);
|
||||
}
|
||||
|
||||
strcpy(szString4, cgi.Argv(2 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString5, cgi.Argv(3 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString6, cgi.Argv(4 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString7, cgi.Argv(5 + iCurrentEntry + iDatumCount * i));
|
||||
|
||||
if (cgs.gametype >= GT_TEAM_ROUNDS && iClientNum == -1 && iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS)
|
||||
{
|
||||
strcat(szString4, va(" %s", cgi.LV_ConvertString("Wins")));
|
||||
szString5[0] = 0;
|
||||
}
|
||||
|
||||
if (iClientNum == cg.snap->ps.clientNum)
|
||||
{
|
||||
pItemTextColor = vThisClientTextColor;
|
||||
pItemBackColor = vThisClientBackColor;
|
||||
}
|
||||
else if (iClientNum == -2)
|
||||
{
|
||||
pItemTextColor = vNoTeamTextColor;
|
||||
pItemBackColor = vNoTeamBackColor;
|
||||
}
|
||||
else if (iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS)
|
||||
{
|
||||
if (iClientTeam == iMatchTeam)
|
||||
{
|
||||
pItemTextColor = vSameTeamTextColor;
|
||||
pItemBackColor = vSameTeamBackColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItemTextColor = vOtherTeamTextColor;
|
||||
pItemBackColor = vOtherTeamBackColor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pItemTextColor = vNoTeamTextColor;
|
||||
pItemBackColor = vNoTeamBackColor;
|
||||
}
|
||||
|
||||
if (bIsDead) {
|
||||
pItemTextColor = vDeadTextColorDead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iClientNum = atoi(cgi.Argv(iDatumCount * i));
|
||||
if (iClientNum >= 0)
|
||||
{
|
||||
strcpy(szString2, va("%i", iClientNum));
|
||||
strcpy(szString3, cg.clientinfo[iClientNum].name);
|
||||
strcpy(szString4, cgi.Argv(1 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString5, cgi.Argv(2 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString6, cgi.Argv(3 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString7, cgi.Argv(4 + iCurrentEntry + iDatumCount * i));
|
||||
}
|
||||
else
|
||||
{
|
||||
szString2[0] = 0;
|
||||
if (iClientNum == -3)
|
||||
{
|
||||
strcpy(szString2, cgi.LV_ConvertString("Players"));
|
||||
bIsHeader = qtrue;
|
||||
}
|
||||
else if (iClientNum == -2)
|
||||
{
|
||||
strcpy(szString2, cgi.LV_ConvertString("Spectators"));
|
||||
bIsHeader = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown
|
||||
szString3[0] = 0;
|
||||
}
|
||||
szString4[0] = 0;
|
||||
szString5[0] = 0;
|
||||
szString6[0] = 0;
|
||||
szString7[0] = 0;
|
||||
}
|
||||
|
||||
if (iClientNum == cg.snap->ps.clientNum)
|
||||
{
|
||||
pItemTextColor = vThisClientTextColor;
|
||||
pItemBackColor = vThisClientBackColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItemTextColor = vNoTeamTextColor;
|
||||
pItemBackColor = vNoTeamBackColor;
|
||||
}
|
||||
}
|
||||
|
||||
cgi.UI_SetScoreBoardItem(
|
||||
i,
|
||||
szString2,
|
||||
szString3,
|
||||
szString4,
|
||||
szString5,
|
||||
szString6,
|
||||
szString7,
|
||||
NULL,
|
||||
NULL,
|
||||
pItemTextColor,
|
||||
pItemBackColor,
|
||||
bIsHeader
|
||||
);
|
||||
}
|
||||
|
||||
cgi.UI_DeleteScoreBoardItems(iEntryCount);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char* CG_GetColumnName(int iColumnNum, int* iColumnWidth)
|
||||
{
|
||||
int iReturnWidth;
|
||||
const char* pszReturnString;
|
||||
|
||||
switch (iColumnNum) {
|
||||
case 0:
|
||||
iReturnWidth = 128;
|
||||
pszReturnString = "Name";
|
||||
break;
|
||||
case 1:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Kills";
|
||||
break;
|
||||
case 2:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Deaths";
|
||||
if (cgs.gametype > GT_TEAM) {
|
||||
pszReturnString = "Total";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Time";
|
||||
break;
|
||||
case 4:
|
||||
iReturnWidth = 64;
|
||||
pszReturnString = "Ping";
|
||||
break;
|
||||
default:
|
||||
iReturnWidth = 0;
|
||||
pszReturnString = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (iColumnWidth) {
|
||||
*iColumnWidth = iReturnWidth;
|
||||
}
|
||||
|
||||
return pszReturnString;
|
||||
}
|
||||
|
||||
void CG_ParseScores()
|
||||
{
|
||||
int i;
|
||||
int iEntryCount;
|
||||
int iClientTeam, iClientNum;
|
||||
int iDatumCount;
|
||||
int iMatchTeam;
|
||||
int iCurrentEntry;
|
||||
qboolean bIsDead, bIsHeader;
|
||||
char szString2[MAX_STRING_TOKENS];
|
||||
char szString3[MAX_STRING_TOKENS];
|
||||
char szString4[MAX_STRING_TOKENS];
|
||||
char szString5[MAX_STRING_TOKENS];
|
||||
char szString6[MAX_STRING_TOKENS];
|
||||
float vSameTeamTextColor[4];
|
||||
float vSameTeamBackColor[4];
|
||||
float vOtherTeamTextColor[4];
|
||||
float vOtherTeamBackColor[4];
|
||||
float vNoTeamTextColor[4];
|
||||
float vNoTeamBackColor[4];
|
||||
float vThisClientTextColor[4];
|
||||
float vThisClientBackColor[4];
|
||||
float vDeadTextColorDead[4];
|
||||
float* pItemTextColor;
|
||||
float* pItemBackColor;
|
||||
|
||||
iMatchTeam = -1;
|
||||
vSameTeamTextColor[0] = 1.0f;
|
||||
vSameTeamTextColor[1] = 1.0f;
|
||||
vSameTeamTextColor[2] = 1.0f;
|
||||
vSameTeamTextColor[3] = 1.0f;
|
||||
vSameTeamBackColor[0] = 0.1f;
|
||||
vSameTeamBackColor[1] = 0.5f;
|
||||
vSameTeamBackColor[2] = 0.1f;
|
||||
vSameTeamBackColor[3] = 0.4f;
|
||||
vOtherTeamTextColor[0] = 1.0f;
|
||||
vOtherTeamTextColor[1] = 1.0f;
|
||||
vOtherTeamTextColor[2] = 1.0f;
|
||||
vOtherTeamTextColor[3] = 1.0f;
|
||||
vOtherTeamBackColor[0] = 0.5f;
|
||||
vOtherTeamBackColor[1] = 0.1f;
|
||||
vOtherTeamBackColor[2] = 0.1f;
|
||||
vOtherTeamBackColor[3] = 0.4f;
|
||||
vNoTeamTextColor[0] = 1.0f;
|
||||
vNoTeamTextColor[1] = 1.0f;
|
||||
vNoTeamTextColor[2] = 1.0f;
|
||||
vNoTeamTextColor[3] = 1.0f;
|
||||
vNoTeamBackColor[0] = 0.1f;
|
||||
vNoTeamBackColor[1] = 0.1f;
|
||||
vNoTeamBackColor[2] = 0.1f;
|
||||
vNoTeamBackColor[3] = 0.4f;
|
||||
vDeadTextColorDead[0] = 1.0f;
|
||||
vDeadTextColorDead[1] = 0.1f;
|
||||
vDeadTextColorDead[2] = 0.1f;
|
||||
vDeadTextColorDead[3] = 1.0f;
|
||||
|
||||
vThisClientTextColor[0] = 0.0f;
|
||||
vThisClientTextColor[1] = 0.0f;
|
||||
vThisClientTextColor[2] = 0.0f;
|
||||
vThisClientTextColor[3] = 1.0f;
|
||||
|
||||
if (cgs.gametype > GT_FFA)
|
||||
{
|
||||
vThisClientBackColor[0] = 0.5f;
|
||||
vThisClientBackColor[1] = 0.75f;
|
||||
vThisClientBackColor[2] = 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
vThisClientBackColor[0] = 0.75f;
|
||||
vThisClientBackColor[1] = 0.75f;
|
||||
vThisClientBackColor[2] = 0.75f;
|
||||
}
|
||||
|
||||
vThisClientBackColor[3] = 0.8f;
|
||||
|
||||
iCurrentEntry = 1;
|
||||
if (cgs.gametype > GT_FFA)
|
||||
{
|
||||
iDatumCount = 6;
|
||||
iMatchTeam = cg.snap->ps.stats[STAT_TEAM];
|
||||
if (iMatchTeam != TEAM_ALLIES && iMatchTeam != TEAM_AXIS)
|
||||
{
|
||||
iMatchTeam = TEAM_ALLIES;
|
||||
vThisClientTextColor[0] = 0.0f;
|
||||
vThisClientTextColor[1] = 0.0f;
|
||||
vThisClientTextColor[2] = 0.0f;
|
||||
vThisClientBackColor[0] = 0.75f;
|
||||
vThisClientBackColor[1] = 0.75f;
|
||||
vThisClientBackColor[2] = 0.75f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// free-for-all
|
||||
iDatumCount = 5;
|
||||
}
|
||||
|
||||
iEntryCount = atoi(cgi.Argv(iCurrentEntry++));
|
||||
if (iEntryCount > MAX_CLIENTS) {
|
||||
iEntryCount = MAX_CLIENTS;
|
||||
}
|
||||
|
||||
for (i = 0; i < iEntryCount; ++i)
|
||||
{
|
||||
bIsHeader = qfalse;
|
||||
if (cgs.gametype > GT_FFA)
|
||||
{
|
||||
iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i));
|
||||
iClientTeam = atoi(cgi.Argv(1 + iCurrentEntry + iDatumCount * i));
|
||||
if (iClientTeam >= 0) {
|
||||
bIsDead = qfalse;
|
||||
}
|
||||
else {
|
||||
bIsDead = qtrue;
|
||||
iClientTeam = -iClientTeam;
|
||||
}
|
||||
|
||||
if (iClientNum == -1)
|
||||
{
|
||||
bIsHeader = qtrue;
|
||||
|
||||
switch (iClientTeam)
|
||||
{
|
||||
case 1:
|
||||
strcpy(szString2, cgi.LV_ConvertString("Spectators"));
|
||||
break;
|
||||
case 2:
|
||||
strcpy(szString2, cgi.LV_ConvertString("Free-For-Allers"));
|
||||
break;
|
||||
case 3:
|
||||
strcpy(szString2, cgi.LV_ConvertString("Allies"));
|
||||
break;
|
||||
case 4:
|
||||
strcpy(szString2, cgi.LV_ConvertString("Axis"));
|
||||
break;
|
||||
default:
|
||||
strcpy(szString2, cgi.LV_ConvertString("No Team"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (iClientNum == -2)
|
||||
{
|
||||
// spectating
|
||||
szString2[0] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(szString2, cg.clientinfo[iClientNum].name);
|
||||
}
|
||||
|
||||
strcpy(szString3, cgi.Argv(2 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString4, cgi.Argv(3 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString5, cgi.Argv(4 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString6, cgi.Argv(5 + iCurrentEntry + iDatumCount * i));
|
||||
|
||||
if (iClientNum == cg.snap->ps.clientNum)
|
||||
{
|
||||
pItemTextColor = vThisClientTextColor;
|
||||
pItemBackColor = vThisClientBackColor;
|
||||
}
|
||||
else if (iClientNum == -2)
|
||||
{
|
||||
pItemTextColor = vNoTeamTextColor;
|
||||
pItemBackColor = vNoTeamBackColor;
|
||||
}
|
||||
else if (iClientTeam == TEAM_ALLIES || iClientTeam == TEAM_AXIS)
|
||||
{
|
||||
if (iClientTeam == iMatchTeam)
|
||||
{
|
||||
pItemTextColor = vSameTeamTextColor;
|
||||
pItemBackColor = vSameTeamBackColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItemTextColor = vOtherTeamTextColor;
|
||||
pItemBackColor = vOtherTeamBackColor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pItemTextColor = vNoTeamTextColor;
|
||||
pItemBackColor = vNoTeamBackColor;
|
||||
}
|
||||
|
||||
if (bIsDead) {
|
||||
pItemTextColor = vDeadTextColorDead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iClientNum = atoi(cgi.Argv(iCurrentEntry + iDatumCount * i));
|
||||
if (iClientNum >= 0)
|
||||
{
|
||||
strcpy(szString2, cg.clientinfo[iClientNum].name);
|
||||
strcpy(szString3, cgi.Argv(1 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString4, cgi.Argv(2 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString5, cgi.Argv(3 + iCurrentEntry + iDatumCount * i));
|
||||
strcpy(szString6, cgi.Argv(4 + iCurrentEntry + iDatumCount * i));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iClientNum == -3)
|
||||
{
|
||||
strcpy(szString2, cgi.LV_ConvertString("Players"));
|
||||
bIsHeader = qtrue;
|
||||
}
|
||||
else if (iClientNum == -2)
|
||||
{
|
||||
strcpy(szString2, cgi.LV_ConvertString("Spectators"));
|
||||
bIsHeader = qtrue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown
|
||||
szString2[0] = 0;
|
||||
}
|
||||
szString3[0] = 0;
|
||||
szString4[0] = 0;
|
||||
szString5[0] = 0;
|
||||
szString6[0] = 0;
|
||||
}
|
||||
|
||||
if (iClientNum == cg.snap->ps.clientNum)
|
||||
{
|
||||
pItemTextColor = vThisClientTextColor;
|
||||
pItemBackColor = vThisClientBackColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
pItemTextColor = vNoTeamTextColor;
|
||||
pItemBackColor = vNoTeamBackColor;
|
||||
}
|
||||
}
|
||||
|
||||
cgi.UI_SetScoreBoardItem(
|
||||
i,
|
||||
szString2,
|
||||
szString3,
|
||||
szString4,
|
||||
szString5,
|
||||
szString6,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
pItemTextColor,
|
||||
pItemBackColor,
|
||||
bIsHeader
|
||||
);
|
||||
}
|
||||
|
||||
cgi.UI_DeleteScoreBoardItems(iEntryCount);
|
||||
}
|
||||
#endif
|
||||
+228
-449
@@ -1,31 +1,82 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_servercmds.c -- reliably sequenced text commands sent by the server
|
||||
// these are processed at snapshot transition time, so there will definately
|
||||
// be a valid snapshot this frame
|
||||
|
||||
// DESCRIPTION:
|
||||
// cg_servercmds.c -- text commands sent by the server
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
static const char* IsWeaponAllowed(int dmFlags, int flags) {
|
||||
return (dmFlags & flags) ? "0" : "1";
|
||||
}
|
||||
|
||||
static qboolean QueryLandminesAllowed2(const char* mapname, int dmflags) {
|
||||
if (dmflags & DF_WEAPON_NO_LANDMINE) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if (dmflags & DF_WEAPON_LANDMINE_ALWAYS) {
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
if (!Q_stricmpn(mapname, "obj/obj_", 8u))
|
||||
return qfalse;
|
||||
if (!Q_stricmpn(mapname, "dm/mohdm", 8u))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Bahnhof_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "obj/MP_Ardennes_TOW"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Bazaar_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "obj/MP_Berlin_TOW"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Brest_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "obj/MP_Druckkammern_TOW"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Gewitter_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "obj/MP_Flughafen_TOW"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Holland_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Malta_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Stadt_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Unterseite_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Verschneit_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "lib/mp_ship_lib"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "DM/MP_Verschneit_DM"))
|
||||
return qfalse;
|
||||
if (!Q_stricmp(mapname, "lib/mp_ship_lib"))
|
||||
return qfalse;
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_ParseServerinfo
|
||||
@@ -34,60 +85,83 @@ This is called explicitly when the gamestate is first received,
|
||||
and whenever the server updates any serverinfo flagged cvars
|
||||
================
|
||||
*/
|
||||
void CG_ParseServerinfo( void ) {
|
||||
const char *info;
|
||||
char *mapname;
|
||||
void CG_ParseServerinfo(void)
|
||||
{
|
||||
const char* info;
|
||||
const char* mapname;
|
||||
char map[MAX_QPATH];
|
||||
char* spawnpos;
|
||||
const char* version;
|
||||
|
||||
info = CG_ConfigString( CS_SERVERINFO );
|
||||
cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) );
|
||||
cgi.Cvar_Set("g_gametype", va("%i", cgs.gametype));
|
||||
cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) );
|
||||
cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) );
|
||||
cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) );
|
||||
cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) );
|
||||
cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) );
|
||||
cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) );
|
||||
mapname = Info_ValueForKey( info, "mapname" );
|
||||
Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname );
|
||||
cgi.Cvar_Set( "cg_scoreboardpic", Info_ValueForKey( info,"g_scoreboardpic" ) );
|
||||
}
|
||||
info = CG_ConfigString(CS_SERVERINFO);
|
||||
cgs.gametype = atoi(Info_ValueForKey(info, "g_gametype"));
|
||||
cgs.dmflags = atoi(Info_ValueForKey(info, "dmflags"));
|
||||
cgs.teamflags = atoi(Info_ValueForKey(info, "teamflags"));
|
||||
cgs.fraglimit = atoi(Info_ValueForKey(info, "fraglimit"));
|
||||
cgs.timelimit = atoi(Info_ValueForKey(info, "timelimit"));
|
||||
cgs.maxclients = atoi(Info_ValueForKey(info, "sv_maxclients"));
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_ParseWarmup
|
||||
==================
|
||||
*/
|
||||
static void CG_ParseWarmup( void ) {
|
||||
const char *info;
|
||||
int warmup;
|
||||
version = Info_ValueForKey(info, "version");
|
||||
if (strstr(version, "Spearhead")) {
|
||||
cgi.Cvar_Set("g_servertype", "1");
|
||||
} else {
|
||||
cgi.Cvar_Set("g_servertype", "2");
|
||||
}
|
||||
|
||||
info = CG_ConfigString( CS_WARMUP );
|
||||
cgi.Cvar_Set("cg_gametype", Info_ValueForKey(info, "g_gametype"));
|
||||
cgi.Cvar_Set("cg_fraglimit", Info_ValueForKey(info, "fraglimit"));
|
||||
cgi.Cvar_Set("cg_timelimit", Info_ValueForKey(info, "timelimit"));
|
||||
cgi.Cvar_Set("cg_maxclients", Info_ValueForKey(info, "sv_gametype"));
|
||||
cgi.Cvar_Set("cg_obj_alliedtext1", Info_ValueForKey(info, "g_obj_alliedtext1"));
|
||||
cgi.Cvar_Set("cg_obj_alliedtext2", Info_ValueForKey(info, "g_obj_alliedtext2"));
|
||||
cgi.Cvar_Set("cg_obj_alliedtext3", Info_ValueForKey(info, "g_obj_alliedtext3"));
|
||||
cgi.Cvar_Set("cg_obj_axistext1", Info_ValueForKey(info, "cg_obj_axistext1"));
|
||||
cgi.Cvar_Set("cg_obj_axistext2", Info_ValueForKey(info, "cg_obj_axistext2"));
|
||||
cgi.Cvar_Set("cg_obj_axistext3", Info_ValueForKey(info, "cg_obj_axistext3"));
|
||||
cgi.Cvar_Set("cg_scoreboardpic", Info_ValueForKey(info, "g_scoreboardpic"));
|
||||
cgi.Cvar_Set("cg_scoreboardpicover", Info_ValueForKey(info, "g_scoreboardpicover"));
|
||||
cgs.mapChecksum = atoi(Info_ValueForKey(info, "sv_mapChecksum"));
|
||||
|
||||
warmup = atoi( info );
|
||||
cg.warmupCount = -1;
|
||||
mapname = Info_ValueForKey(info, "mapname");
|
||||
|
||||
if ( warmup == 0 && cg.warmup ) {
|
||||
cgi.Cvar_Set("cg_weapon_rifle", IsWeaponAllowed(cgs.dmflags, DF_WEAPON_NO_RIFLE));
|
||||
cgi.Cvar_Set("cg_weapon_sniper", IsWeaponAllowed(cgs.dmflags, DF_WEAPON_NO_SNIPER));
|
||||
cgi.Cvar_Set("cg_weapon_mg", IsWeaponAllowed(cgs.dmflags, DF_WEAPON_NO_MG));
|
||||
cgi.Cvar_Set("cg_weapon_smg", IsWeaponAllowed(cgs.dmflags, DF_WEAPON_NO_SMG));
|
||||
cgi.Cvar_Set("cg_weapon_rocket", IsWeaponAllowed(cgs.dmflags, DF_WEAPON_NO_ROCKET));
|
||||
cgi.Cvar_Set("cg_weapon_shotgun", IsWeaponAllowed(cgs.dmflags, DF_WEAPON_NO_SHOTGUN));
|
||||
cgi.Cvar_Set("cg_weapon_landmine", QueryLandminesAllowed2(mapname, cgs.dmflags) ? "1" : "0");
|
||||
|
||||
} else if ( warmup > 0 && cg.warmup <= 0 ) {
|
||||
spawnpos = strchr(mapname, '$');
|
||||
if (spawnpos) {
|
||||
Q_strncpyz(map, mapname, spawnpos - mapname + 1);
|
||||
} else {
|
||||
strcpy(map, mapname);
|
||||
}
|
||||
|
||||
{
|
||||
// cgi.S_StartLocalSound( cgs.media.countPrepareSound, CHAN_ANNOUNCER );
|
||||
}
|
||||
}
|
||||
Com_sprintf(cgs.mapname, sizeof(cgs.mapname), "maps/%s.bsp", map);
|
||||
|
||||
cg.warmup = warmup;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CG_SetConfigValues
|
||||
|
||||
Called on load to set the initial values from configure strings
|
||||
================
|
||||
*/
|
||||
void CG_SetConfigValues( void ) {
|
||||
cgs.levelStartTime = atoi( CG_ConfigString( CS_LEVEL_START_TIME ) );
|
||||
cg.warmup = atoi( CG_ConfigString( CS_WARMUP ) );
|
||||
// hide/show huds
|
||||
if (cgs.gametype)
|
||||
{
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_timelimit\n");
|
||||
if (cgs.fraglimit)
|
||||
{
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_fraglimit\n");
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_score\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_addhud hud_score\n");
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fraglimit\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_timelimit\n");
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_fraglimit\n");
|
||||
cgi.Cmd_Execute(EXEC_NOW, "ui_removehud hud_score\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -96,296 +170,74 @@ CG_ConfigStringModified
|
||||
|
||||
================
|
||||
*/
|
||||
static void CG_ConfigStringModified( void ) {
|
||||
const char *str;
|
||||
int num;
|
||||
char buffer[MAX_QPATH];
|
||||
static void CG_ConfigStringModified(void)
|
||||
{
|
||||
int num;
|
||||
|
||||
num = atoi( CG_Argv( 1 ) );
|
||||
num = atoi(cgi.Argv(1));
|
||||
|
||||
// get the gamestate from the client system, which will have the
|
||||
// new configstring already integrated
|
||||
cgi.GetGameState( &cgs.gameState );
|
||||
// get the gamestate from the client system, which will have the
|
||||
// new configstring already integrated
|
||||
cgi.GetGameState(&cgs.gameState);
|
||||
|
||||
// look up the individual string that was modified
|
||||
str = CG_ConfigString( num );
|
||||
|
||||
// do something with it if necessary
|
||||
if ( num == CS_MUSIC ) {
|
||||
CG_StartMusic();
|
||||
} else if ( num == CS_SERVERINFO ) {
|
||||
CG_ParseServerinfo();
|
||||
} else if ( num == CS_WARMUP ) {
|
||||
CG_ParseWarmup();
|
||||
} else if( num >= CS_RAIN_DENSITY && num <= CS_RAIN_NUMSHADERS) {
|
||||
CG_RainCSUpdated(num,str);
|
||||
} else if ( num == CS_FOGINFO ) {
|
||||
sscanf(str, "%d %f %f %f %f", &cg.farplane_cull, &cg.farplane_distance,
|
||||
&cg.farplane_color[0], &cg.farplane_color[1], &cg.farplane_color[2]);
|
||||
} else if ( num == CS_LEVEL_START_TIME ) {
|
||||
cgs.levelStartTime = atoi( str );
|
||||
} else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) {
|
||||
cgs.gameModels[ num-CS_MODELS ] = cgi.R_RegisterModel( str );
|
||||
if(str[0] && str[0] != '*') {
|
||||
cgs.gameTIKIs[num-CS_MODELS] = cgi.TIKI_RegisterModel( str );
|
||||
if(cgs.gameTIKIs[num-CS_MODELS] == 0) {
|
||||
CG_Printf("CG_ConfigStringModified: failed to load tiki file %s (%i)\n",str,num-CS_MODELS);
|
||||
}
|
||||
}
|
||||
} else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) {
|
||||
if ( str[0] != '*' ) { // player specific sounds don't register here
|
||||
Q_strncpyz( buffer, str, sizeof(buffer) );
|
||||
if (buffer[strlen( buffer )-1] == '0' || buffer[strlen( buffer )-1] == '1')
|
||||
buffer[strlen( buffer )-1] = 0;
|
||||
cgs.gameSounds[ num-CS_SOUNDS] = cgi.S_RegisterSound( buffer, qfalse );
|
||||
}
|
||||
} else if ( num >= CS_PLAYERS && num < CS_PLAYERS+MAX_CLIENTS ) {
|
||||
CG_NewClientInfo( num - CS_PLAYERS );
|
||||
} else if( num >= CS_WEAPONS && num < CS_TEAMS ) {
|
||||
CG_RegisterItemName(num - CS_WEAPONS, str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=======================
|
||||
CG_AddToTeamChat
|
||||
|
||||
=======================
|
||||
*/
|
||||
static void CG_AddToTeamChat( const char *str ) {
|
||||
int len;
|
||||
char *p, *ls;
|
||||
int lastcolor;
|
||||
int chatHeight;
|
||||
|
||||
if (cg_teamChatHeight->integer < TEAMCHAT_HEIGHT) {
|
||||
chatHeight = cg_teamChatHeight->integer;
|
||||
} else {
|
||||
chatHeight = TEAMCHAT_HEIGHT;
|
||||
}
|
||||
|
||||
if (chatHeight <= 0 || cg_teamChatTime->integer <= 0) {
|
||||
// team chat disabled, dump into normal chat
|
||||
cgs.teamChatPos = cgs.teamLastChatPos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
|
||||
p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
|
||||
*p = 0;
|
||||
|
||||
lastcolor = '7';
|
||||
|
||||
ls = NULL;
|
||||
while (*str) {
|
||||
if (len > TEAMCHAT_WIDTH - 1) {
|
||||
if (ls) {
|
||||
str -= (p - ls);
|
||||
str++;
|
||||
p -= (p - ls);
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
|
||||
|
||||
cgs.teamChatPos++;
|
||||
p = cgs.teamChatMsgs[cgs.teamChatPos % chatHeight];
|
||||
*p = 0;
|
||||
*p++ = Q_COLOR_ESCAPE;
|
||||
*p++ = lastcolor;
|
||||
len = 0;
|
||||
ls = NULL;
|
||||
}
|
||||
|
||||
if ( Q_IsColorString( str ) ) {
|
||||
*p++ = *str++;
|
||||
lastcolor = *str;
|
||||
*p++ = *str++;
|
||||
continue;
|
||||
}
|
||||
if (*str == ' ') {
|
||||
ls = p;
|
||||
}
|
||||
*p++ = *str++;
|
||||
len++;
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
cgs.teamChatMsgTimes[cgs.teamChatPos % chatHeight] = cg.time;
|
||||
cgs.teamChatPos++;
|
||||
|
||||
if (cgs.teamChatPos - cgs.teamLastChatPos > chatHeight)
|
||||
cgs.teamLastChatPos = cgs.teamChatPos - chatHeight;
|
||||
CG_ProcessConfigString(num);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_MapRestart
|
||||
================
|
||||
CG_ParseStats
|
||||
|
||||
The server has issued a map_restart, so the next snapshot
|
||||
is completely new and should not be interpolated to.
|
||||
|
||||
A tournement restart will clear everything, but doesn't
|
||||
require a reload of all the media
|
||||
===============
|
||||
================
|
||||
*/
|
||||
static void CG_MapRestart( void ) {
|
||||
if ( cg_showmiss->integer ) {
|
||||
CG_Printf( "CG_MapRestart\n" );
|
||||
}
|
||||
|
||||
CG_InitLocalEntities();
|
||||
CG_InitMarkPolys();
|
||||
CG_ClearParticles ();
|
||||
|
||||
// make sure the "3 frags left" warnings play again
|
||||
cg.fraglimitWarnings = 0;
|
||||
|
||||
cg.timelimitWarnings = 0;
|
||||
|
||||
cg.mapRestart = qtrue;
|
||||
|
||||
CG_StartMusic();
|
||||
|
||||
cgi.S_ClearLoopingSounds(qtrue);
|
||||
|
||||
// we really should clear more parts of cg here and stop sounds
|
||||
|
||||
// play the "fight" sound if this is a restart without warmup
|
||||
if ( cg.warmup == 0 /* && cgs.gametype == GT_TOURNAMENT */) {
|
||||
// cgi.S_StartLocalSound( cgs.media.countFightSound, CHAN_ANNOUNCER );
|
||||
CG_CenterPrint( "FIGHT!", 120, GIANTCHAR_WIDTH*2 );
|
||||
}
|
||||
|
||||
cgi.Cvar_Set("cg_thirdPerson", "0");
|
||||
static void CG_ParseStats()
|
||||
{
|
||||
cgi.Cvar_Set("ui_NumObjectives", cgi.Argv(1));
|
||||
cgi.Cvar_Set("ui_NumComplete", cgi.Argv(2));
|
||||
cgi.Cvar_Set("ui_NumShotsFired", cgi.Argv(3));
|
||||
cgi.Cvar_Set("ui_NumHits", cgi.Argv(4));
|
||||
cgi.Cvar_Set("ui_Accuracy", cgi.Argv(5));
|
||||
cgi.Cvar_Set("ui_PreferredWeapon", cgi.Argv(6));
|
||||
cgi.Cvar_Set("ui_NumHitsTaken", cgi.Argv(7));
|
||||
cgi.Cvar_Set("ui_NumObjectsDestroyed", cgi.Argv(8));
|
||||
cgi.Cvar_Set("ui_NumEnemysKilled", cgi.Argv(9));
|
||||
cgi.Cvar_Set("ui_HeadShots", cgi.Argv(10));
|
||||
cgi.Cvar_Set("ui_TorsoShots", cgi.Argv(11));
|
||||
cgi.Cvar_Set("ui_LeftLegShots", cgi.Argv(12));
|
||||
cgi.Cvar_Set("ui_RightLegShots", cgi.Argv(13));
|
||||
cgi.Cvar_Set("ui_GroinShots", cgi.Argv(14));
|
||||
cgi.Cvar_Set("ui_LeftArmShots", cgi.Argv(15));
|
||||
cgi.Cvar_Set("ui_RightArmShots", cgi.Argv(16));
|
||||
cgi.Cvar_Set("ui_GunneryEvaluation", cgi.Argv(17));
|
||||
cgi.Cvar_Set("ui_gotmedal", cgi.Argv(18));
|
||||
cgi.Cvar_Set("ui_success", cgi.Argv(19));
|
||||
cgi.Cvar_Set("ui_failed", cgi.Argv(20));
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_RemoveChatEscapeChar
|
||||
=================
|
||||
================
|
||||
CG_Stopwatch_f
|
||||
|
||||
================
|
||||
*/
|
||||
static void CG_RemoveChatEscapeChar( char *text ) {
|
||||
int i, l;
|
||||
static void CG_Stopwatch_f()
|
||||
{
|
||||
if (cgi.Argc() < 3) {
|
||||
Com_Error(1, "stopwatch didn't have 2 parameters");
|
||||
}
|
||||
|
||||
l = 0;
|
||||
for ( i = 0; text[i]; i++ ) {
|
||||
if (text[i] == '\x19')
|
||||
continue;
|
||||
text[l++] = text[i];
|
||||
}
|
||||
text[l] = '\0';
|
||||
}
|
||||
|
||||
// Wombat: Lists of blocked and allowed stufftext commands
|
||||
const char *stufftextBlock[] = {
|
||||
"quit"
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
int args;
|
||||
} stufftextCommand_t;
|
||||
|
||||
stufftextCommand_t stufftextSafe[] = {
|
||||
{ "pushmenu_teamselect", 0 },
|
||||
{ "pushmenu_weaponselect", 0 },
|
||||
{ "wait", 1 },
|
||||
{ "locationprint", 3 }, // locationprint <x> <y> <text ... >
|
||||
{ "add", 2 }, // add <variable> <amount>
|
||||
// su44: these are used on "-(V)ethod-Clan" server ( 8.9.16.34:12203 )
|
||||
// for some kind of anticheat
|
||||
{ "set", 2 }, // set <variable> <value>
|
||||
{ "setu", 2 }, // setu <variable> <value>
|
||||
};
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_StufftextCommand
|
||||
|
||||
Wombat: MOHAA servers may send certain server commands
|
||||
that contain console commands supposed to be executed
|
||||
on the client's console.
|
||||
I don't like the idea that a remote machine can execute
|
||||
*anything*, so i think i will implement a filter to pass only
|
||||
sane commands...
|
||||
=================
|
||||
*/
|
||||
void CG_StufftextCommand( const char *cmd ) {
|
||||
int i;
|
||||
char *ptr;
|
||||
const char *ptr2;
|
||||
|
||||
ptr = ( char * )cmd;
|
||||
ptr2 = COM_Parse(&ptr);
|
||||
for ( i = 0 ; i < sizeof( stufftextBlock ) / sizeof( stufftextBlock[0] ) ; i++ ) {
|
||||
if ( !Q_stricmp( ptr2, stufftextBlock[i] ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// wombat: some servers use ST commands for anti-cheat measures
|
||||
// we don't use the whitelist right now...
|
||||
Com_Printf( "^3Executing stufftext command: \"%s\"\n", cmd );
|
||||
cgi.SendConsoleCommand( cmd );
|
||||
return;
|
||||
|
||||
for ( i = 0 ; i < sizeof( stufftextSafe ) / sizeof( stufftextSafe[0] ) ; i++ ) {
|
||||
if ( !Q_stricmp( ptr2, stufftextSafe[i].cmd ) ) {
|
||||
cgi.SendConsoleCommand( cmd );
|
||||
return;
|
||||
}
|
||||
}
|
||||
Com_Printf( "Unlisted stufftext command: \"%s\"\n", cmd );
|
||||
cgi.stopWatch->iStartTime = 1000 * atoi(cgi.Argv(1));
|
||||
cgi.stopWatch->iEndTime = cgi.stopWatch->iStartTime + 1000 * atoi(cgi.Argv(2));
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CG_AddGameMessage
|
||||
================
|
||||
CG_ServerLag_f
|
||||
|
||||
To be printed below the compass
|
||||
=================
|
||||
================
|
||||
*/
|
||||
void CG_AddGameMessage( const char *cmd, serverMessageType_t smt ) {
|
||||
ubersound_t *click;
|
||||
|
||||
click = CG_GetUbersound( "click" );
|
||||
switch ( smt ) {
|
||||
case SMT_YELLOW:
|
||||
case SMT_WHITE:
|
||||
if ( cg.gameMessageTime == 0 )
|
||||
cg.gameMessageTime = cg.time;
|
||||
cg.gameMessageTypes[cg.gameMessagePtr2] = smt;
|
||||
Q_strncpyz( cg.gameMessages[cg.gameMessagePtr2], cmd, sizeof(cg.gameMessages[cg.gameMessagePtr2]) );
|
||||
CG_Printf( "Game Message: %s", cmd );
|
||||
cgi.S_StartLocalSound( click->sfxHandle, click->channel );
|
||||
cg.gameMessagePtr2 = (cg.gameMessagePtr2+1) % MAX_GAMEMESSAGES;
|
||||
if ( cg.gameMessagePtr2 == cg.gameMessagePtr1 ) {
|
||||
cg.gameMessagePtr1 = (cg.gameMessagePtr1+1) % MAX_GAMEMESSAGES;
|
||||
cg.gameMessageTime = cg.time;
|
||||
}
|
||||
break;
|
||||
case SMT_CHAT:
|
||||
CG_Printf( "Chat: %s", cmd );
|
||||
cgi.S_StartLocalSound( click->sfxHandle, click->channel );
|
||||
case SMT_DEATH:
|
||||
if ( cg.chatDeathMessageTime == 0 )
|
||||
cg.chatDeathMessageTime = cg.time;
|
||||
cg.chatDeathMessageTypes[cg.chatDeathMessagePtr2] = smt;
|
||||
Q_strncpyz( cg.chatDeathMessages[cg.chatDeathMessagePtr2], cmd, sizeof(cg.chatDeathMessages[cg.chatDeathMessagePtr2]) );
|
||||
if ( smt == SMT_DEATH )
|
||||
CG_Printf( "Death: %s", cmd );
|
||||
cg.chatDeathMessagePtr2 = (cg.chatDeathMessagePtr2+1) % MAX_CHATDEATHMESSAGES;
|
||||
if (cg.chatDeathMessagePtr2 == cg.chatDeathMessagePtr1 ) {
|
||||
cg.chatDeathMessagePtr1 = (cg.chatDeathMessagePtr1+1) % MAX_CHATDEATHMESSAGES;
|
||||
cg.chatDeathMessageTime = cg.time;
|
||||
}
|
||||
break;
|
||||
case SMT_UNKNOWN:
|
||||
CG_Printf( "Unknown Message: %s", cmd );
|
||||
break;
|
||||
}
|
||||
static void CG_ServerLag_f()
|
||||
{
|
||||
cgs.serverLagTime = cg.time;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -396,133 +248,59 @@ The string has been tokenized and can be retrieved with
|
||||
Cmd_Argc() / Cmd_Argv()
|
||||
=================
|
||||
*/
|
||||
static void CG_ServerCommand( void ) {
|
||||
const char *cmd;
|
||||
char stufftextBuffer[512];
|
||||
const char *ptr;
|
||||
char letter;
|
||||
int i;
|
||||
int lastpos;
|
||||
static void CG_ServerCommand(void)
|
||||
{
|
||||
const char* cmd;
|
||||
|
||||
cmd = CG_Argv(0);
|
||||
cmd = cgi.Argv(0);
|
||||
|
||||
if ( !cmd[0] ) {
|
||||
// server claimed the command
|
||||
return;
|
||||
}
|
||||
if (!cmd[0]) {
|
||||
// server claimed the command
|
||||
return;
|
||||
}
|
||||
|
||||
// wombat: stufftext is something specific to MOHAA
|
||||
if ( !strcmp( cmd, "stufftext" ) ) {
|
||||
if (!strcmp(cmd, "cs")) {
|
||||
CG_ConfigStringModified();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = CG_Argv(1);
|
||||
for ( i=0,lastpos=0; i<sizeof(stufftextBuffer);i++ ) {
|
||||
letter = *(ptr + i);
|
||||
if ( i == sizeof(stufftextBuffer) && letter != 0 ) {
|
||||
Com_Printf( "WARNING: Max. stufftext command length (%i) exceeded.\n", sizeof(stufftextBuffer) );
|
||||
return;
|
||||
}
|
||||
if ( letter == ';' ) {
|
||||
letter = 0;
|
||||
stufftextBuffer[i] =letter;
|
||||
CG_StufftextCommand( &stufftextBuffer[lastpos] );
|
||||
lastpos = i+1;
|
||||
}
|
||||
else if ( letter == 0 ) {
|
||||
stufftextBuffer[i] =letter;
|
||||
CG_StufftextCommand( &stufftextBuffer[lastpos] );
|
||||
return;
|
||||
}
|
||||
else stufftextBuffer[i] =letter;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!strcmp(cmd, "print") || !strcmp(cmd, "hudprint")) {
|
||||
cgi.Printf("%s", cgi.Argv(1));
|
||||
if (!strcmp(cmd, "hudprint")) {
|
||||
CG_HudPrint_f();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(cmd, "stufftext")) {
|
||||
cgi.Cmd_Stuff(cgi.Argv(1));
|
||||
cgi.Cmd_Stuff("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "cp" ) ) {
|
||||
CG_CenterPrint( CG_Argv(1), SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH );
|
||||
return;
|
||||
}
|
||||
if (!strcmp(cmd, "scores")) {
|
||||
CG_ParseScores();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "cs" ) ) {
|
||||
CG_ConfigStringModified();
|
||||
return;
|
||||
}
|
||||
if (!strcmp(cmd, "stats")) {
|
||||
CG_ParseStats();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "print" ) ) {
|
||||
// TODO: print to screen, too
|
||||
const char *ptr;
|
||||
serverMessageType_t smt;
|
||||
if (!strcmp(cmd, "stopwatch")) {
|
||||
CG_Stopwatch_f();
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = CG_Argv(1);
|
||||
smt = (serverMessageType_t)*ptr;
|
||||
if (!strcmp(cmd, "svlag")) {
|
||||
CG_ServerLag_f();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( smt < SMT_MAX )
|
||||
CG_AddGameMessage( ptr + 1, smt );
|
||||
else
|
||||
CG_Printf( "%s", ptr );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// su44: chats are handled differently in MoH
|
||||
// if ( !strcmp( cmd, "chat" ) ) {
|
||||
// if ( !cg_teamChatsOnly->integer ) {
|
||||
//// cgi.S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
|
||||
// Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
|
||||
// CG_RemoveChatEscapeChar( text );
|
||||
// CG_Printf( "%s\n", text );
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if ( !strcmp( cmd, "tchat" ) ) {
|
||||
//// cgi.S_StartLocalSound( cgs.media.talkSound, CHAN_LOCAL_SOUND );
|
||||
// Q_strncpyz( text, CG_Argv(1), MAX_SAY_TEXT );
|
||||
// CG_RemoveChatEscapeChar( text );
|
||||
// CG_AddToTeamChat( text );
|
||||
// CG_Printf( "%s\n", text );
|
||||
// return;
|
||||
// }
|
||||
|
||||
if ( !strcmp( cmd, "scores" ) ) {
|
||||
//CG_ParseScores();
|
||||
Q_strncpyz( cg.aScore, cgi.Args(), sizeof( cg.aScore ) );
|
||||
return;
|
||||
}
|
||||
|
||||
//if ( !strcmp( cmd, "map_restart" ) ) {
|
||||
// CG_MapRestart();
|
||||
// return;
|
||||
//}
|
||||
|
||||
// clientLevelShot is sent before taking a special screenshot for
|
||||
// the menu system during development
|
||||
if ( !strcmp( cmd, "clientLevelShot" ) ) {
|
||||
cg.levelShot = qtrue;
|
||||
return;
|
||||
}
|
||||
|
||||
// MoHAA's stopwatch
|
||||
if ( !strcmp( cmd, "stopwatch" ) ) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "svlag" ) ) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
// su44: send just before server map change
|
||||
if ( !strcmp( cmd, "fadesound" ) ) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CG_Printf( "Unknown client game command: %s\n", cmd );
|
||||
cgi.Printf("Unknown client game command: %s\n", cmd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
====================
|
||||
CG_ExecuteNewServerCommands
|
||||
@@ -531,10 +309,11 @@ Execute all of the server commands that were received along
|
||||
with this this snapshot.
|
||||
====================
|
||||
*/
|
||||
void CG_ExecuteNewServerCommands( int latestSequence ) {
|
||||
while ( cgs.serverCommandSequence < latestSequence ) {
|
||||
if ( cgi.GetServerCommand( ++cgs.serverCommandSequence ) ) {
|
||||
CG_ServerCommand();
|
||||
}
|
||||
}
|
||||
void CG_ExecuteNewServerCommands(int latestSequence, qboolean differentServer)
|
||||
{
|
||||
while (cgs.serverCommandSequence < latestSequence) {
|
||||
if (cgi.GetServerCommand(++cgs.serverCommandSequence, differentServer)) {
|
||||
CG_ServerCommand();
|
||||
}
|
||||
}
|
||||
}
|
||||
+335
-344
@@ -1,43 +1,101 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_snapshot.c -- things that happen on snapshot transition,
|
||||
// not necessarily every single rendered frame
|
||||
|
||||
// DESCRIPTION:
|
||||
// things that happen on snapshot transition, not necessarily every
|
||||
// single frame
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "../qcommon/tiki_local.h"
|
||||
|
||||
#include "tiki.h"
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_ResetEntity
|
||||
==================
|
||||
*/
|
||||
static void CG_ResetEntity( centity_t *cent ) {
|
||||
VectorCopy (cent->currentState.origin, cent->lerpOrigin);
|
||||
VectorCopy (cent->currentState.angles, cent->lerpAngles);
|
||||
if ( cent->currentState.eType == ET_PLAYER ) {
|
||||
CG_ResetPlayerEntity( cent );
|
||||
}
|
||||
static void CG_ResetEntity(centity_t* cent)
|
||||
{
|
||||
dtiki_t* tiki;
|
||||
int i;
|
||||
|
||||
VectorCopy(cent->currentState.origin, cent->lerpOrigin);
|
||||
|
||||
VectorCopy(cent->currentState.angles, cent->lerpAngles);
|
||||
|
||||
// if we just teleported, all we care about is the position and orientation
|
||||
// information
|
||||
if (cent->teleported) {
|
||||
cent->teleported = qfalse;
|
||||
return;
|
||||
}
|
||||
|
||||
// reset local color
|
||||
cent->client_color[0] = 1;
|
||||
cent->client_color[1] = 1;
|
||||
cent->client_color[2] = 1;
|
||||
cent->client_color[3] = 1;
|
||||
|
||||
// Make sure entity starts with no loop sound
|
||||
cent->tikiLoopSound = 0;
|
||||
|
||||
// Reset client flags
|
||||
cent->clientFlags = 0;
|
||||
|
||||
// Reset splash info
|
||||
cent->splash_last_spawn_time = 0;
|
||||
cent->splash_still_count = -1;
|
||||
|
||||
tiki = cgi.R_Model_GetHandle(cgs.model_draw[cent->currentState.modelindex]);
|
||||
// reset client command
|
||||
CG_RemoveClientEntity(cent->currentState.number, tiki, cent);
|
||||
|
||||
// reset the animation for the entities
|
||||
if (tiki && tiki->a->bIsCharacter) {
|
||||
for (i = 0; i < MAX_FRAMEINFOS; i++) {
|
||||
cent->animLast[i] = cent->currentState.frameInfo[i].index;
|
||||
cent->animLastTimes[i] = cent->currentState.frameInfo[i].time;
|
||||
if (cent->currentState.frameInfo[i].weight) {
|
||||
cent->animLastWeight |= 1 << i;
|
||||
} else {
|
||||
// zero-weight shouldn't count
|
||||
cent->animLastWeight &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// clear all the last animations
|
||||
for (i = 0; i < MAX_FRAMEINFOS; i++) {
|
||||
cent->animLast[i] = -1;
|
||||
}
|
||||
|
||||
cent->animLastWeight = 0;
|
||||
}
|
||||
|
||||
cent->usageIndexLast = 0;
|
||||
cent->bFootOnGround_Left = qtrue;
|
||||
cent->bFootOnGround_Right = qtrue;
|
||||
|
||||
if (cent->currentState.eType == ET_PLAYER) {
|
||||
CG_ResetPlayerEntity(cent);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -47,148 +105,66 @@ CG_TransitionEntity
|
||||
cent->nextState is moved to cent->currentState and events are fired
|
||||
===============
|
||||
*/
|
||||
static int TIKI_FrameNumForTime(tiki_t *tiki, int animIndex, float animTime) {
|
||||
int i;
|
||||
tikiAnim_t *anim;
|
||||
if(tiki->numAnims <= animIndex) {
|
||||
Com_Printf("TIKI_FrameNumForTime: animIndex %i out of range %i\n",animIndex,tiki->numAnims);
|
||||
return 0;
|
||||
}
|
||||
anim = tiki->anims[animIndex];
|
||||
if(anim->numFrames == 1) {
|
||||
return 0;
|
||||
}
|
||||
i = 0;
|
||||
while(animTime > anim->frameTime) {
|
||||
animTime -= anim->frameTime;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
static void CG_ExecuteFrameCommands(centity_t *cent, tikiAnim_t *anim, int frameIndex) {
|
||||
int i;
|
||||
tikiCommand_t *cmd;
|
||||
cmd = anim->clientCmds;
|
||||
for(i = 0; i < anim->numClientCmds; i++,cmd++) {
|
||||
if(cmd->frame == frameIndex) {
|
||||
//CG_Printf("Frame %i command %s\n",cmd->frame,cmd->text);
|
||||
//CG_ProcessEventText(cent,cmd->text);
|
||||
CG_PostEvent(cent,cmd->text,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void CG_ExecuteFramesCommands(centity_t *cent, tikiAnim_t *anim, int start, int stop) {
|
||||
int i;
|
||||
tikiCommand_t *cmd;
|
||||
cmd = anim->clientCmds;
|
||||
for(i = 0; i < anim->numClientCmds; i++,cmd++) {
|
||||
if(cmd->frame >= start && cmd->frame <= stop) {
|
||||
//CG_Printf("Frame %i command %s\n",cmd->frame,cmd->text);
|
||||
//CG_ProcessEventText(cent,cmd->text);
|
||||
CG_PostEvent(cent,cmd->text,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void CG_TransitionEntity(centity_t* cent)
|
||||
{
|
||||
cent->currentState = cent->nextState;
|
||||
cent->currentValid = qtrue;
|
||||
|
||||
static void CG_TransitionEntity( centity_t *cent ) {
|
||||
frameInfo_t *fi0, *fi1;
|
||||
tiki_t *tiki0,*tiki1;
|
||||
tikiAnim_t *a0, *a1;
|
||||
int f0, f1;
|
||||
int i;
|
||||
|
||||
tiki0 = cgs.gameTIKIs[cent->currentState.modelindex];
|
||||
tiki1 = cgs.gameTIKIs[cent->nextState.modelindex];
|
||||
if(tiki0 || tiki1) {
|
||||
// su44: It should be placed somewhere else soon
|
||||
fi0 = cent->currentState.frameInfo;
|
||||
fi1 = cent->nextState.frameInfo;
|
||||
for(i = 0; i < 16; i++,fi0++,fi1++) {
|
||||
if(fi0->weight && tiki0 && fi0->index < tiki0->numAnims) {
|
||||
a0 = tiki0->anims[fi0->index];
|
||||
f0 = TIKI_FrameNumForTime(tiki0,fi0->index,fi0->time);
|
||||
if(fi1->weight && tiki1 && fi1->index < tiki1->numAnims) {
|
||||
if(fi0->index != fi1->index || tiki0 != tiki1) {
|
||||
a1 = tiki1->anims[fi1->index];
|
||||
CG_ExecuteFrameCommands(cent,a0,TIKI_FRAME_EXIT);
|
||||
CG_ExecuteFrameCommands(cent,a1,TIKI_FRAME_ENTRY);
|
||||
} else {
|
||||
f1 = TIKI_FrameNumForTime(tiki1,fi1->index,fi1->time);
|
||||
if(f1 > f0) {
|
||||
CG_ExecuteFramesCommands(cent,a0,f0,f1);
|
||||
} else {
|
||||
CG_ExecuteFramesCommands(cent,a0,f1,f0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// anim has stopped
|
||||
//CG_ExecuteFramesCommands(cent,anim,fi0->
|
||||
CG_ExecuteFrameCommands(cent,a0,TIKI_FRAME_EXIT);
|
||||
}
|
||||
} else if(fi1->weight && tiki1 && fi1->index < tiki1->numAnims) {
|
||||
// anim is starting
|
||||
a1 = tiki1->anims[fi1->index];
|
||||
f1 = TIKI_FrameNumForTime(tiki1,fi1->index,fi1->time);
|
||||
CG_ExecuteFrameCommands(cent,a1,TIKI_FRAME_ENTRY);
|
||||
}
|
||||
}
|
||||
}
|
||||
cent->currentState = cent->nextState;
|
||||
cent->currentValid = qtrue;
|
||||
// reset if the entity wasn't in the last frame or was teleported
|
||||
if (!cent->interpolate) {
|
||||
CG_ResetEntity(cent);
|
||||
}
|
||||
|
||||
// reset if the entity wasn't in the last frame or was teleported
|
||||
if ( !cent->interpolate ) {
|
||||
CG_ResetEntity( cent );
|
||||
}
|
||||
// clear the next state. if will be set by the next CG_SetNextSnap
|
||||
cent->interpolate = qfalse;
|
||||
// reset the teleported state
|
||||
cent->teleported = qfalse;
|
||||
|
||||
// clear the next state. if will be set by the next CG_SetNextSnap
|
||||
cent->interpolate = qfalse;
|
||||
if (cent->currentState.eType == ET_EVENTS) {
|
||||
CG_Event(cent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CG_SetInitialSnapshot
|
||||
|
||||
This will only happen on the very first snapshot, or
|
||||
on tourney restarts. All other times will use
|
||||
on tourney restarts. All other times will use
|
||||
CG_TransitionSnapshot instead.
|
||||
|
||||
FIXME: Also called by map_restart?
|
||||
==================
|
||||
*/
|
||||
void CG_SetInitialSnapshot( snapshot_t *snap ) {
|
||||
int i;
|
||||
centity_t *cent;
|
||||
entityState_t *state;
|
||||
void CG_SetInitialSnapshot(snapshot_t* snap)
|
||||
{
|
||||
int i;
|
||||
centity_t* cent;
|
||||
entityState_t* state;
|
||||
|
||||
cg.snap = snap;
|
||||
cg.snap = snap;
|
||||
|
||||
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].currentState, qfalse );
|
||||
// sort out solid entities
|
||||
CG_BuildSolidList();
|
||||
|
||||
// sort out solid entities
|
||||
CG_BuildSolidList();
|
||||
CG_ExecuteNewServerCommands(snap->serverCommandSequence, qfalse);
|
||||
|
||||
CG_ExecuteNewServerCommands( snap->serverCommandSequence );
|
||||
for (i = 0; i < cg.snap->numEntities; i++) {
|
||||
state = &cg.snap->entities[i];
|
||||
cent = &cg_entities[state->number];
|
||||
|
||||
// set our local weapon selection pointer to
|
||||
// what the server has indicated the current weapon is
|
||||
CG_Respawn();
|
||||
cent->currentState = *state;
|
||||
cent->interpolate = qfalse;
|
||||
cent->currentValid = qtrue;
|
||||
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
|
||||
state = &cg.snap->entities[ i ];
|
||||
cent = &cg_entities[ state->number ];
|
||||
CG_ResetEntity(cent);
|
||||
}
|
||||
|
||||
memcpy(¢->currentState, state, sizeof(entityState_t));
|
||||
//cent->currentState = *state;
|
||||
cent->interpolate = qfalse;
|
||||
cent->currentValid = qtrue;
|
||||
|
||||
CG_ResetEntity( cent );
|
||||
}
|
||||
cgi.MUSIC_UpdateMood(snap->ps.current_music_mood,
|
||||
snap->ps.fallback_music_mood);
|
||||
cgi.MUSIC_UpdateVolume(snap->ps.music_volume,
|
||||
snap->ps.music_volume_fade_time);
|
||||
cgi.S_SetReverb(snap->ps.reverb_type, snap->ps.reverb_level);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_TransitionSnapshot
|
||||
@@ -196,86 +172,81 @@ CG_TransitionSnapshot
|
||||
The transition point from snap to nextSnap has passed
|
||||
===================
|
||||
*/
|
||||
static void CG_TransitionSnapshot( void ) {
|
||||
centity_t *cent;
|
||||
snapshot_t *oldFrame;
|
||||
int i;
|
||||
static void CG_TransitionSnapshot(qboolean differentServer)
|
||||
{
|
||||
centity_t* cent;
|
||||
snapshot_t* oldFrame;
|
||||
int i;
|
||||
|
||||
server_sound_t *snd;
|
||||
if (differentServer) {
|
||||
CG_ServerRestarted();
|
||||
}
|
||||
|
||||
if ( !cg.snap ) {
|
||||
CG_Error( "CG_TransitionSnapshot: NULL cg.snap" );
|
||||
}
|
||||
if ( !cg.nextSnap ) {
|
||||
CG_Error( "CG_TransitionSnapshot: NULL cg.nextSnap" );
|
||||
}
|
||||
// execute any server string commands before transitioning entities
|
||||
CG_ExecuteNewServerCommands(cg.nextSnap->serverCommandSequence, differentServer);
|
||||
|
||||
// execute any server string commands before transitioning entities
|
||||
CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence );
|
||||
// clear the currentValid flag for all entities in the existing snapshot
|
||||
for (i = 0; i < cg.snap->numEntities; i++) {
|
||||
cent = &cg_entities[cg.snap->entities[i].number];
|
||||
cent->currentValid = qfalse;
|
||||
}
|
||||
|
||||
// if we had a map_restart, set everthing with initial
|
||||
if ( !cg.snap ) {
|
||||
}
|
||||
// move nextSnap to snap and do the transitions
|
||||
oldFrame = cg.snap;
|
||||
cg.snap = cg.nextSnap;
|
||||
|
||||
// clear the currentValid flag for all entities in the existing snapshot
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
|
||||
cent = &cg_entities[ cg.snap->entities[ i ].number ];
|
||||
cent->currentValid = qfalse;
|
||||
}
|
||||
// FAKK: Commented out to make our stuff work
|
||||
// cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
|
||||
|
||||
// move nextSnap to snap and do the transitions
|
||||
oldFrame = cg.snap;
|
||||
cg.snap = cg.nextSnap;
|
||||
for (i = 0; i < cg.snap->numEntities; i++) {
|
||||
cent = &cg_entities[cg.snap->entities[i].number];
|
||||
if (differentServer) {
|
||||
cent->interpolate = qfalse;
|
||||
cent->teleported = qfalse;
|
||||
}
|
||||
CG_TransitionEntity(cent);
|
||||
}
|
||||
|
||||
BG_PlayerStateToEntityState( &cg.snap->ps, &cg_entities[ cg.snap->ps.clientNum ].currentState, qfalse );
|
||||
cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse;
|
||||
for (i = 0; i < cg.snap->number_of_sounds; i++) {
|
||||
CG_ProcessSound(&cg.snap->sounds[i]);
|
||||
}
|
||||
|
||||
for ( i = 0 ; i < cg.snap->numEntities ; i++ ) {
|
||||
cent = &cg_entities[ cg.snap->entities[ i ].number ];
|
||||
CG_TransitionEntity( cent );
|
||||
cgi.MUSIC_UpdateMood(cg.snap->ps.current_music_mood, cg.snap->ps.fallback_music_mood);
|
||||
cg.nextSnap = NULL;
|
||||
|
||||
// remember time of snapshot this entity was last updated in
|
||||
cent->snapShotTime = cg.snap->serverTime;
|
||||
}
|
||||
// check for playerstate transition events
|
||||
|
||||
if (oldFrame) {
|
||||
playerState_t *ops, *ps;
|
||||
|
||||
ops = &oldFrame->ps;
|
||||
ps = &cg.snap->ps;
|
||||
|
||||
for ( i=0;i<cg.snap->number_of_sounds;i++ ) {
|
||||
snd = &cg.snap->sounds[i];
|
||||
if ( snd->sound_index == 0 ) // wombat: we get these sometimes, no clue why
|
||||
continue;
|
||||
if (snd->stop_flag) {
|
||||
cgi.S_StopLoopingSound( snd->entity_number );
|
||||
}
|
||||
else {
|
||||
cgi.S_StartSound( snd->origin, snd->entity_number, snd->channel, cgs.gameSounds[snd->sound_index] );
|
||||
}
|
||||
}
|
||||
// teleporting checks are irrespective of prediction
|
||||
if (ps->pm_flags & PMF_RESPAWNED) {
|
||||
cg.thisFrameTeleport = qtrue;
|
||||
}
|
||||
|
||||
cg.nextSnap = NULL;
|
||||
if ((ops->music_volume != ps->music_volume) ||
|
||||
(ops->music_volume_fade_time != ps->music_volume_fade_time)) {
|
||||
cgi.MUSIC_UpdateVolume(ps->music_volume,
|
||||
ps->music_volume_fade_time);
|
||||
}
|
||||
|
||||
// check for playerstate transition events
|
||||
if ( oldFrame ) {
|
||||
playerState_t *ops, *ps;
|
||||
|
||||
ops = &oldFrame->ps;
|
||||
ps = &cg.snap->ps;
|
||||
// teleporting checks are irrespective of prediction
|
||||
//if ( ( ps->eFlags ^ ops->eFlags ) & EF_TELEPORT_BIT ) {
|
||||
// cg.thisFrameTeleport = qtrue; // will be cleared by prediction code
|
||||
//}
|
||||
|
||||
// if we are not doing client side movement prediction for any
|
||||
// reason, then the client events and view changes will be issued now
|
||||
if ( cg.demoPlayback /*|| (cg.snap->ps.pm_flags & PMF_FOLLOW)*/
|
||||
|| cg_nopredict->integer || cg_synchronousClients->integer ) {
|
||||
CG_TransitionPlayerState( ps, ops );
|
||||
}
|
||||
}
|
||||
if ((ops->reverb_type != ps->reverb_type) ||
|
||||
(ops->reverb_level != ps->reverb_level)) {
|
||||
cgi.S_SetReverb(ps->reverb_type, ps->reverb_level);
|
||||
}
|
||||
|
||||
// if we are not doing client side movement prediction for any
|
||||
// reason, then the client events and view changes will be issued now
|
||||
if (cg.demoPlayback || (cg.snap->ps.pm_flags & PMF_NO_PREDICTION) ||
|
||||
cg_nopredict->integer || cg_synchronousClients->integer) {
|
||||
CG_TransitionPlayerState(ps, ops);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_SetNextSnap
|
||||
@@ -283,58 +254,71 @@ CG_SetNextSnap
|
||||
A new snapshot has just been read in from the client system.
|
||||
===================
|
||||
*/
|
||||
static void CG_SetNextSnap( snapshot_t *snap ) {
|
||||
int num;
|
||||
entityState_t *es;
|
||||
centity_t *cent;
|
||||
static void CG_SetNextSnap(snapshot_t* snap)
|
||||
{
|
||||
int num;
|
||||
entityState_t* es;
|
||||
centity_t* cent;
|
||||
|
||||
cg.nextSnap = snap;
|
||||
cg.nextSnap = snap;
|
||||
|
||||
BG_PlayerStateToEntityState( &snap->ps, &cg_entities[ snap->ps.clientNum ].nextState, qfalse );
|
||||
cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue;
|
||||
cg_entities[cg.snap->ps.clientNum].interpolate = qtrue;
|
||||
|
||||
// check for extrapolation errors
|
||||
for ( num = 0 ; num < snap->numEntities ; num++ ) {
|
||||
es = &snap->entities[num];
|
||||
cent = &cg_entities[ es->number ];
|
||||
// check for extrapolation errors
|
||||
for (num = 0; num < snap->numEntities; num++) {
|
||||
es = &snap->entities[num];
|
||||
cent = &cg_entities[es->number];
|
||||
|
||||
memcpy(¢->nextState, es, sizeof(entityState_t));
|
||||
//cent->nextState = *es;
|
||||
cent->nextState = *es;
|
||||
|
||||
// if this frame is a teleport, or the entity wasn't in the
|
||||
// previous frame, don't interpolate
|
||||
if ( !cent->currentValid || ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) ) {
|
||||
cent->interpolate = qfalse;
|
||||
} else {
|
||||
cent->interpolate = qtrue;
|
||||
}
|
||||
}
|
||||
// if this frame is a teleport, or the entity wasn't in the
|
||||
// previous frame, don't interpolate
|
||||
if (!cent->currentValid ||
|
||||
((cent->currentState.eFlags ^ es->eFlags) & EF_TELEPORT_BIT) ||
|
||||
(cent->currentState.parent != es->parent) ||
|
||||
(cent->currentState.modelindex != es->modelindex)) {
|
||||
cent->interpolate = qfalse;
|
||||
// if this isn't the first frame and we have valid data, set the
|
||||
// teleport flag
|
||||
if (cent->currentValid) {
|
||||
cent->teleported = qtrue;
|
||||
}
|
||||
} else {
|
||||
cent->interpolate = qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
// if the next frame is a teleport for the playerstate, we
|
||||
// can't interpolate during demos
|
||||
//if ( cg.snap && ( ( snap->ps.eFlags ^ cg.snap->ps.eFlags ) & EF_TELEPORT_BIT ) ) {
|
||||
// cg.nextFrameTeleport = qtrue;
|
||||
//} else
|
||||
|
||||
{
|
||||
cg.nextFrameTeleport = qfalse;
|
||||
}
|
||||
// if the next frame is a teleport for the playerstate, we
|
||||
// can't interpolate during demos
|
||||
if (cg.snap && (snap->ps.pm_flags & PMF_RESPAWNED)) {
|
||||
cg.nextFrameTeleport = qtrue;
|
||||
} else {
|
||||
cg.nextFrameTeleport = qfalse;
|
||||
}
|
||||
|
||||
// if changing follow mode, don't interpolate
|
||||
if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) {
|
||||
cg.nextFrameTeleport = qtrue;
|
||||
}
|
||||
// if changing follow mode, don't interpolate
|
||||
if (cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum) {
|
||||
cg.nextFrameTeleport = qtrue;
|
||||
}
|
||||
|
||||
// if changing server restarts, don't interpolate
|
||||
if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) {
|
||||
cg.nextFrameTeleport = qtrue;
|
||||
}
|
||||
// if the camera cut bit changed, than the next frame is a camera cut
|
||||
if ((cg.nextSnap->ps.camera_flags & CF_CAMERA_CUT_BIT) !=
|
||||
(cg.snap->ps.camera_flags & CF_CAMERA_CUT_BIT)) {
|
||||
cg.nextFrameCameraCut = qtrue;
|
||||
} else {
|
||||
cg.nextFrameCameraCut = qfalse;
|
||||
}
|
||||
|
||||
// sort out solid entities
|
||||
CG_BuildSolidList();
|
||||
// if changing server restarts, don't interpolate
|
||||
if (snap->serverTime < cgi.GetServerStartTime()) {
|
||||
// reset the camera
|
||||
cg.nextFrameTeleport = qtrue;
|
||||
}
|
||||
|
||||
// sort out solid entities
|
||||
CG_BuildSolidList();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
CG_ReadNextSnapshot
|
||||
@@ -345,55 +329,50 @@ times if the client system fails to return a
|
||||
valid snapshot.
|
||||
========================
|
||||
*/
|
||||
static snapshot_t *CG_ReadNextSnapshot( void ) {
|
||||
qboolean r;
|
||||
snapshot_t *dest;
|
||||
static snapshot_t* CG_ReadNextSnapshot(void)
|
||||
{
|
||||
qboolean r;
|
||||
snapshot_t* dest;
|
||||
|
||||
if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) {
|
||||
CG_Printf( "WARNING: CG_ReadNextSnapshot: way out of range, %i > %i",
|
||||
cg.latestSnapshotNum, cgs.processedSnapshotNum );
|
||||
}
|
||||
if (cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000) {
|
||||
cgi.Error(ERR_DROP, "CG_ReadNextSnapshot: way out of range, %i > %i",
|
||||
cg.latestSnapshotNum, cgs.processedSnapshotNum);
|
||||
}
|
||||
|
||||
while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) {
|
||||
// decide which of the two slots to load it into
|
||||
if ( cg.snap == &cg.activeSnapshots[0] ) {
|
||||
dest = &cg.activeSnapshots[1];
|
||||
} else {
|
||||
dest = &cg.activeSnapshots[0];
|
||||
}
|
||||
while (cgs.processedSnapshotNum < cg.latestSnapshotNum) {
|
||||
// decide which of the two slots to load it into
|
||||
if (cg.snap == &cg.activeSnapshots[0]) {
|
||||
dest = &cg.activeSnapshots[1];
|
||||
} else {
|
||||
dest = &cg.activeSnapshots[0];
|
||||
}
|
||||
|
||||
// try to read the snapshot from the client system
|
||||
cgs.processedSnapshotNum++;
|
||||
r = cgi.GetSnapshot( cgs.processedSnapshotNum, dest );
|
||||
// try to read the snapshot from the client system
|
||||
cgs.processedSnapshotNum++;
|
||||
r = cgi.GetSnapshot(cgs.processedSnapshotNum, dest);
|
||||
|
||||
// FIXME: why would cgi.GetSnapshot return a snapshot with the same server time
|
||||
if ( cg.snap && r && dest->serverTime == cg.snap->serverTime ) {
|
||||
//continue;
|
||||
}
|
||||
// if it succeeded, return
|
||||
if (r) {
|
||||
CG_AddLagometerSnapshotInfo(dest);
|
||||
return dest;
|
||||
}
|
||||
|
||||
// if it succeeded, return
|
||||
if ( r ) {
|
||||
CG_AddLagometerSnapshotInfo( dest );
|
||||
return dest;
|
||||
}
|
||||
// a GetSnapshot will return failure if the snapshot
|
||||
// never arrived, or is so old that its entities
|
||||
// have been shoved off the end of the circular
|
||||
// buffer in the client system.
|
||||
|
||||
// a GetSnapshot will return failure if the snapshot
|
||||
// never arrived, or is so old that its entities
|
||||
// have been shoved off the end of the circular
|
||||
// buffer in the client system.
|
||||
// record as a dropped packet
|
||||
CG_AddLagometerSnapshotInfo(NULL);
|
||||
|
||||
// record as a dropped packet
|
||||
CG_AddLagometerSnapshotInfo( NULL );
|
||||
// If there are additional snapshots, continue trying to
|
||||
// read them.
|
||||
}
|
||||
|
||||
// If there are additional snapshots, continue trying to
|
||||
// read them.
|
||||
}
|
||||
|
||||
// nothing left to read
|
||||
return NULL;
|
||||
// nothing left to read
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
CG_ProcessSnapshots
|
||||
@@ -413,80 +392,92 @@ of an interpolating one)
|
||||
|
||||
============
|
||||
*/
|
||||
void CG_ProcessSnapshots( void ) {
|
||||
snapshot_t *snap;
|
||||
int n;
|
||||
void CG_ProcessSnapshots(void)
|
||||
{
|
||||
snapshot_t* snap;
|
||||
int n;
|
||||
qboolean differentServer;
|
||||
|
||||
// see what the latest snapshot the client system has is
|
||||
cgi.GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime );
|
||||
if ( n != cg.latestSnapshotNum ) {
|
||||
if ( n < cg.latestSnapshotNum ) {
|
||||
// this should never happen
|
||||
CG_Error( "CG_ProcessSnapshots: n < cg.latestSnapshotNum" );
|
||||
}
|
||||
cg.latestSnapshotNum = n;
|
||||
}
|
||||
// see what the latest snapshot the client system has is
|
||||
cgi.GetCurrentSnapshotNumber(&n, &cg.latestSnapshotTime);
|
||||
if (n != cg.latestSnapshotNum) {
|
||||
if (n < cg.latestSnapshotNum) {
|
||||
// this should never happen
|
||||
cgi.Error(ERR_DROP,
|
||||
"CG_ProcessSnapshots: n < cg.latestSnapshotNum");
|
||||
}
|
||||
cg.latestSnapshotNum = n;
|
||||
}
|
||||
|
||||
// If we have yet to receive a snapshot, check for it.
|
||||
// Once we have gotten the first snapshot, cg.snap will
|
||||
// always have valid data for the rest of the game
|
||||
while ( !cg.snap ) {
|
||||
snap = CG_ReadNextSnapshot();
|
||||
if ( !snap ) {
|
||||
// we can't continue until we get a snapshot
|
||||
return;
|
||||
}
|
||||
// If we have yet to receive a snapshot, check for it.
|
||||
// Once we have gotten the first snapshot, cg.snap will
|
||||
// always have valid data for the rest of the game
|
||||
while (!cg.snap) {
|
||||
snap = CG_ReadNextSnapshot();
|
||||
if (!snap) {
|
||||
// we can't continue until we get a snapshot
|
||||
return;
|
||||
}
|
||||
|
||||
// set our weapon selection to what
|
||||
// the playerstate is currently using
|
||||
if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) {
|
||||
CG_SetInitialSnapshot( snap );
|
||||
}
|
||||
}
|
||||
// set our weapon selection to what
|
||||
// the playerstate is currently using
|
||||
if (!(snap->snapFlags & SNAPFLAG_NOT_ACTIVE)) {
|
||||
CG_SetInitialSnapshot(snap);
|
||||
}
|
||||
}
|
||||
|
||||
// loop until we either have a valid nextSnap with a serverTime
|
||||
// greater than cg.time to interpolate towards, or we run
|
||||
// out of available snapshots
|
||||
do {
|
||||
// if we don't have a nextframe, try and read a new one in
|
||||
if ( !cg.nextSnap ) {
|
||||
snap = CG_ReadNextSnapshot();
|
||||
// loop until we either have a valid nextSnap with a serverTime
|
||||
// greater than cg.time to interpolate towards, or we run
|
||||
// out of available snapshots
|
||||
do {
|
||||
// if we don't have a nextframe, try and read a new one in
|
||||
if (!cg.nextSnap) {
|
||||
snap = CG_ReadNextSnapshot();
|
||||
|
||||
// if we still don't have a nextframe, we will just have to
|
||||
// extrapolate
|
||||
if ( !snap ) {
|
||||
break;
|
||||
}
|
||||
// if we still don't have a nextframe, we will just have to
|
||||
// extrapolate
|
||||
if (!snap) {
|
||||
break;
|
||||
}
|
||||
|
||||
CG_SetNextSnap( snap );
|
||||
CG_SetNextSnap(snap);
|
||||
|
||||
// if time went backwards, we have a level restart
|
||||
if (cg.nextSnap->serverTime < cg.snap->serverTime) {
|
||||
// only drop if this is not a restart or loadgame
|
||||
if (!((cg.nextSnap->snapFlags ^ cg.snap->snapFlags) &
|
||||
SNAPFLAG_SERVERCOUNT)) {
|
||||
cgi.Error(
|
||||
ERR_DROP,
|
||||
"CG_ProcessSnapshots: Server time went backwards");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if time went backwards, we have a level restart
|
||||
if ( cg.nextSnap->serverTime < cg.snap->serverTime ) {
|
||||
CG_Error( "CG_ProcessSnapshots: Server time went backwards" );
|
||||
}
|
||||
}
|
||||
differentServer = cg.snap->serverTime <= cgi.GetServerStartTime();
|
||||
|
||||
// if our time is < nextFrame's, we have a nice interpolating state
|
||||
if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) {
|
||||
break;
|
||||
}
|
||||
// if our time is < nextFrame's, we have a nice interpolating state
|
||||
if (cg.time >= cg.snap->serverTime &&
|
||||
cg.time < cg.nextSnap->serverTime &&
|
||||
!differentServer) {
|
||||
break;
|
||||
}
|
||||
|
||||
// we have passed the transition from nextFrame to frame
|
||||
CG_TransitionSnapshot();
|
||||
} while ( 1 );
|
||||
|
||||
// assert our valid conditions upon exiting
|
||||
if ( cg.snap == NULL ) {
|
||||
CG_Error( "CG_ProcessSnapshots: cg.snap == NULL" );
|
||||
}
|
||||
if ( cg.time < cg.snap->serverTime ) {
|
||||
// this can happen right after a vid_restart
|
||||
cg.time = cg.snap->serverTime;
|
||||
}
|
||||
if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) {
|
||||
CG_Error( "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" );
|
||||
}
|
||||
// we have passed the transition from nextFrame to frame
|
||||
CG_TransitionSnapshot(differentServer);
|
||||
} while (1);
|
||||
|
||||
// assert our valid conditions upon exiting
|
||||
if (cg.snap == NULL) {
|
||||
cgi.Error(ERR_DROP, "CG_ProcessSnapshots: cg.snap == NULL");
|
||||
}
|
||||
if (cg.time < cg.snap->serverTime) {
|
||||
// this can happen right after a vid_restart
|
||||
cg.time = cg.snap->serverTime;
|
||||
cgi.SetTime(cg.time);
|
||||
}
|
||||
if (cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time) {
|
||||
cgi.Error(ERR_DROP,
|
||||
"CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
@@ -20,25 +20,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
typedef struct UColor_s {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
} UColor;
|
||||
// DESCRIPTION:
|
||||
// Sound function
|
||||
|
||||
typedef struct UColorHSV_s {
|
||||
float h;
|
||||
float s;
|
||||
float v;
|
||||
float a;
|
||||
} UColorHSV;
|
||||
#include "cg_local.h"
|
||||
|
||||
typedef enum { DARK, REALLYDARK, LIGHT, NORMAL } colorType_t;
|
||||
|
||||
typedef struct UBorderColor_s {
|
||||
UColor dark;
|
||||
UColor reallydark;
|
||||
UColor light;
|
||||
UColor original;
|
||||
} UBorderColor;
|
||||
void CG_ProcessSound( server_sound_t *sound )
|
||||
{
|
||||
if ( sound->stop_flag )
|
||||
{
|
||||
cgi.S_StopSound( sound->entity_number, sound->channel );
|
||||
}
|
||||
else
|
||||
{
|
||||
cgi.S_StartSound( sound->origin, sound->entity_number, sound->channel, cgs.sound_precache[sound->sound_index],
|
||||
sound->volume, sound->min_dist, sound->pitch, sound->maxDist, sound->streamed );
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2011 su44
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// cg_specialfx.c - MoHAA special effects
|
||||
|
||||
#include "cg_local.h"
|
||||
|
||||
// MoHAA footstep sounds (from ubersound.scr) :
|
||||
// snd_step_paper, snd_step_glass, snd_step_wood, snd_step_metal,
|
||||
// snd_step_grill, snd_step_stone, snd_step_dirt, snd_step_grass,
|
||||
// snd_step_mud, snd_step_puddle, snd_step_gravel, snd_step_sand,
|
||||
// snd_step_foliage, snd_step_snow, snd_step_carpet
|
||||
// BODY MOVEMENT
|
||||
// snd_step_equipment - (equipment; for walking)
|
||||
// snd_step_wade - (wade; for when wading through deeper water)
|
||||
|
||||
static void CG_FootstepMain(trace_t *trace, int iRunning, int iEquipment) {
|
||||
char sSoundName[MAX_QPATH] = "snd_step_";
|
||||
|
||||
int contents;
|
||||
int surfaceFlags;
|
||||
vec3_t pos;
|
||||
|
||||
ubersound_t *snd = 0;
|
||||
|
||||
if ( !iRunning )
|
||||
return;
|
||||
|
||||
// su44: it seems that trace_t::surfaceFlags
|
||||
// are not set if trace_t::allsolid == qtrue
|
||||
if( trace->allsolid == qtrue )
|
||||
return;
|
||||
|
||||
if ( iEquipment ) {
|
||||
snd = CG_GetUbersound( "snd_step_equipment" );
|
||||
if (snd)
|
||||
cgi.S_StartSound( trace->endpos, trace->entityNum, CHAN_ITEM, snd->sfxHandle );
|
||||
}
|
||||
|
||||
surfaceFlags = trace->surfaceFlags;
|
||||
contents = CG_PointContents(trace->endpos,-1);
|
||||
if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) ) {
|
||||
// wombat: we test if the water is deep or shallow
|
||||
VectorCopy( trace->endpos, pos );
|
||||
pos[2] += 16.0f;
|
||||
contents = CG_PointContents(pos,-1);
|
||||
if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
|
||||
snd = CG_GetUbersound( "snd_step_wade" );
|
||||
else
|
||||
snd = CG_GetUbersound( "snd_step_puddle" );
|
||||
} else {
|
||||
if ( surfaceFlags & SURF_PAPER ) {
|
||||
snd = CG_GetUbersound( "snd_step_paper" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_WOOD ) {
|
||||
snd = CG_GetUbersound( "snd_step_wood" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_METAL ) {
|
||||
snd = CG_GetUbersound( "snd_step_metal" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_ROCK ) {
|
||||
snd = CG_GetUbersound( "snd_step_stone" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_DIRT ) {
|
||||
snd = CG_GetUbersound( "snd_step_dirt" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_GRILL ) {
|
||||
snd = CG_GetUbersound( "snd_step_grill" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_GRASS ) {
|
||||
snd = CG_GetUbersound( "snd_step_grass" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_MUD ) {
|
||||
snd = CG_GetUbersound( "snd_step_mud" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_PUDDLE ) {
|
||||
snd = CG_GetUbersound( "snd_step_puddle" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_GLASS ) {
|
||||
snd = CG_GetUbersound( "snd_step_glass" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_GRAVEL ) {
|
||||
snd = CG_GetUbersound( "snd_step_gravel" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_SAND ) {
|
||||
snd = CG_GetUbersound( "snd_step_sand" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_FOLIAGE ) {
|
||||
snd = CG_GetUbersound( "snd_step_foliage" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_SNOW ) {
|
||||
snd = CG_GetUbersound( "snd_step_snow" );
|
||||
}
|
||||
else if ( surfaceFlags & SURF_CARPET ) {
|
||||
snd = CG_GetUbersound( "snd_step_carpet" );
|
||||
}
|
||||
}
|
||||
if ( !snd ) {
|
||||
if(trace->surfaceFlags) {
|
||||
CG_Printf( "CG_FootstepMain: could not load sound for surface %i\n", trace->surfaceFlags );
|
||||
}
|
||||
return;
|
||||
}
|
||||
cgi.S_StartSound( trace->endpos, trace->entityNum, CHAN_BODY, snd->sfxHandle );
|
||||
}
|
||||
|
||||
void CG_MeleeImpact(float *vStart, float *vEnd) {
|
||||
trace_t trace;
|
||||
float vMins[3] = { -4.0, -4.0, 0 };
|
||||
float vMaxs[3] = { 4.0, 4.0, 2.0 };
|
||||
CG_Trace(&trace,vStart,vMins,vMaxs,vEnd,1023,MASK_SHOT);
|
||||
if(trace.fraction != 1.f) {
|
||||
CG_FootstepMain(&trace,1,0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CG_Footstep(char *szTagName, centity_t *ent, /*refEntity_t *pREnt,*/
|
||||
int iRunning, int iEquipment)
|
||||
{
|
||||
int mask;
|
||||
int cylinder;
|
||||
int cliptoentities;
|
||||
trace_t trace;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t vStart, vEnd, forward;
|
||||
|
||||
|
||||
// CG_Printf("CG_Footstep: %s\n",szTagName);
|
||||
|
||||
vStart[0] = ent->lerpOrigin[0];
|
||||
vStart[1] = ent->lerpOrigin[1];
|
||||
vStart[2] = ent->lerpOrigin[2] + 8.0;
|
||||
if ( szTagName ) {
|
||||
tiki_t *tiki;
|
||||
int boneName;
|
||||
int tagIndex;
|
||||
vec3_t a;
|
||||
|
||||
tiki = cgs.gameTIKIs[ent->currentState.modelindex];
|
||||
|
||||
if(tiki == 0) {
|
||||
CG_Printf("CG_Footstep: tiki is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// find tag in tiki
|
||||
boneName = cgi.TIKI_GetBoneNameIndex(szTagName);
|
||||
for(tagIndex = 0; tagIndex < tiki->numBones; tagIndex++) {
|
||||
if(tiki->boneNames[tagIndex] == boneName) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(tagIndex == tiki->numBones) {
|
||||
CG_Printf("CG_Footstep: Cant find bone %s in tiki %s f\n",szTagName,tiki->name);
|
||||
return;
|
||||
}
|
||||
if(ent->bones == 0) {
|
||||
CG_Printf("CG_Footstep: entity has null bones ptr\n");
|
||||
return;
|
||||
}
|
||||
|
||||
CG_CentBoneIndexLocal2World(tagIndex, ent, vStart, a);
|
||||
vStart[2] += 8;
|
||||
}
|
||||
if ( iRunning == -1 ) {
|
||||
AngleVectors(ent->lerpAngles, forward, 0, 0);
|
||||
vStart[0] = forward[0] * -16.0 + vStart[0];
|
||||
vStart[1] = forward[1] * -16.0 + vStart[1];
|
||||
vStart[2] = forward[2] * -16.0 + vStart[2];
|
||||
vEnd[0] = forward[0] * 64.0 + vStart[0];
|
||||
vEnd[1] = forward[1] * 64.0 + vStart[1];
|
||||
vEnd[2] = forward[2] * 64.0 + vStart[2];
|
||||
mins[0] = -2.0;
|
||||
mins[1] = -2.0;
|
||||
mins[2] = -8.0;
|
||||
maxs[0] = 2.0;
|
||||
maxs[1] = 2.0;
|
||||
maxs[2] = 8.0;
|
||||
} else {
|
||||
vEnd[0] = vStart[0];
|
||||
vEnd[1] = vStart[1];
|
||||
|
||||
vStart[2] = vStart[2] + 16.0;
|
||||
vEnd[2] = vStart[2] - 64.0;
|
||||
|
||||
mins[0] = -4.0;
|
||||
mins[1] = -4.0;
|
||||
mins[2] = 0.0;
|
||||
|
||||
maxs[0] = 4.0;
|
||||
maxs[1] = 4.0;
|
||||
maxs[2] = 2.0;
|
||||
}
|
||||
if ( ent->currentState.eType == ET_PLAYER ) {
|
||||
cliptoentities = 1;
|
||||
cylinder = 1;
|
||||
mask = MASK_TREADMARK;
|
||||
} else {
|
||||
cliptoentities = 0;
|
||||
cylinder = 0;
|
||||
mask = MASK_FOOTSTEP;
|
||||
}
|
||||
CG_Trace(&trace, vStart, mins, maxs, vEnd,
|
||||
ent->currentState.number, mask/*, cylinder, cliptoentities*/);
|
||||
if ( trace.fraction != 1.0 ) {
|
||||
int equip;
|
||||
if (rand() > RAND_MAX*0.70)
|
||||
equip = qtrue; // play only in 30% of cases
|
||||
else equip = qfalse;
|
||||
CG_FootstepMain(&trace, iRunning, equip);
|
||||
} else {
|
||||
//if ( cg_debugFootsteps.integer )
|
||||
// CG_Printf("Footstep: missed floor\n");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// Special Effects code
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_commands.h"
|
||||
#include "class.h"
|
||||
|
||||
#define MAX_SPECIAL_EFFECT_COMMANDS 32
|
||||
|
||||
class specialeffectcommand_t : public Class {
|
||||
public:
|
||||
spawnthing_t* emitter;
|
||||
float fCommandTime;
|
||||
void (*endfcn)();
|
||||
Event *pEvent;
|
||||
|
||||
public:
|
||||
specialeffectcommand_t();
|
||||
};
|
||||
|
||||
class specialeffect_t : public Class
|
||||
{
|
||||
public:
|
||||
int m_iCommandCount;
|
||||
specialeffectcommand_t* m_commands[MAX_SPECIAL_EFFECT_COMMANDS];
|
||||
|
||||
public:
|
||||
specialeffect_t();
|
||||
|
||||
specialeffectcommand_t* AddNewCommand();
|
||||
};
|
||||
|
||||
#define MAX_SPECIAL_EFFECTS 99
|
||||
#define SPECIAL_EFFECT_TEST MAX_SPECIAL_EFFECTS - 1
|
||||
|
||||
class ClientSpecialEffectsManager : public Listener {
|
||||
specialeffect_t m_effects[99];
|
||||
qboolean m_bEffectsLoaded;
|
||||
int m_iNumPendingEvents;
|
||||
|
||||
public:
|
||||
CLASS_PROTOTYPE(ClientSpecialEffectsManager);
|
||||
|
||||
private:
|
||||
void ContinueEffectExecution(Event* ev);
|
||||
void ExecuteEffect(int iEffect, int iStartCommand, Vector vPos, Vector vAngles, float axis[3][3]);
|
||||
|
||||
public:
|
||||
ClientSpecialEffectsManager();
|
||||
|
||||
void LoadEffects();
|
||||
qboolean EffectsPending();
|
||||
void MakeEffect_Normal(int iEffect, Vector vPos, Vector vNormal);
|
||||
void MakeEffect_Angles(int iEffect, Vector vPos, Vector vAngles);
|
||||
void MakeEffect_Axis(int iEffect, Vector vPos, float axis[3][3]);
|
||||
specialeffect_t* GetTestEffectPointer();
|
||||
};
|
||||
|
||||
extern ClientSpecialEffectsManager sfxManager;
|
||||
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// General swiping functions
|
||||
|
||||
#include "cg_commands.h"
|
||||
|
||||
swipething_t m_swipes[MAX_SWIPES];
|
||||
extern int current_entity_number;
|
||||
extern refEntity_t *current_entity;
|
||||
extern dtiki_t* current_tiki;
|
||||
extern centity_t *current_centity;
|
||||
|
||||
void ClientGameCommandManager::SwipeOn
|
||||
(
|
||||
Event *ev
|
||||
)
|
||||
|
||||
{
|
||||
// Make a swipe for this if available
|
||||
int i;
|
||||
int freeswipe = -1;
|
||||
str tagname_start,tagname_end;
|
||||
qhandle_t shader;
|
||||
|
||||
if ( ev->NumArgs () != 4 )
|
||||
return;
|
||||
|
||||
shader = cgi.R_RegisterShader( ev->GetString( 1 ) );
|
||||
tagname_start = ev->GetString( 2 );
|
||||
tagname_end = ev->GetString( 3 );
|
||||
|
||||
for ( i=0; i < MAX_SWIPES; i++ )
|
||||
{
|
||||
swipething_t &swipe = m_swipes[i];
|
||||
|
||||
if ( !swipe.enabled ||
|
||||
(
|
||||
( swipe.entitynum == current_entity_number ) &&
|
||||
( tagname_start == swipe.tagname_start ) &&
|
||||
( tagname_end == swipe.tagname_end ) &&
|
||||
( shader == swipe.shader )
|
||||
)
|
||||
)
|
||||
{
|
||||
freeswipe = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( freeswipe == -1 )
|
||||
return;
|
||||
|
||||
swipething_t &swipe = m_swipes[freeswipe];
|
||||
|
||||
if ( !swipe.enabled )
|
||||
{
|
||||
swipe.Init ();
|
||||
swipe.enabled = qtrue;
|
||||
swipe.entitynum = current_entity_number;
|
||||
}
|
||||
|
||||
swipe.shader = cgi.R_RegisterShader( ev->GetString( 1 ) );
|
||||
swipe.tagname_start = ev->GetString ( 2 );
|
||||
swipe.tagname_end = ev->GetString ( 3 );
|
||||
swipe.life = ev->GetFloat ( 4 ) * 1000.f;
|
||||
|
||||
if ( current_centity )
|
||||
current_centity->clientFlags |= CF_UPDATESWIPE;
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::SwipeOff
|
||||
(
|
||||
Event *ev
|
||||
)
|
||||
|
||||
{
|
||||
qboolean was_enabled;
|
||||
int i;
|
||||
|
||||
was_enabled = qfalse;
|
||||
for ( i=0; i < MAX_SWIPES; i++ )
|
||||
{
|
||||
swipething_t &swipe = m_swipes[i];
|
||||
|
||||
if ( swipe.enabled && swipe.entitynum == current_entity_number )
|
||||
{
|
||||
swipe.enabled = qfalse;
|
||||
was_enabled = qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( was_enabled )
|
||||
{
|
||||
//cgi.R_SwipeBegin ( 0.f, 0.f, -1 );
|
||||
//cgi.R_SwipeEnd ();
|
||||
|
||||
if ( current_centity )
|
||||
current_centity->clientFlags &= ~CF_UPDATESWIPE;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::Swipe
|
||||
(
|
||||
Event *ev
|
||||
)
|
||||
|
||||
{
|
||||
// This does a swipe effect on the entity
|
||||
int i,swipenum;
|
||||
orientation_t _or;
|
||||
int tagnum_start,tagnum_end;
|
||||
qboolean add_cnt_point = qfalse;
|
||||
vec3_t tmp;
|
||||
|
||||
assert(current_entity);
|
||||
assert(current_tiki);
|
||||
|
||||
if (!current_entity || !current_tiki)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's find us a new (or current) swipe
|
||||
for ( swipenum=0; swipenum < MAX_SWIPES; swipenum++ )
|
||||
{
|
||||
swipething_t &swipe = m_swipes[swipenum];
|
||||
|
||||
if ( swipe.enabled && swipe.entitynum == current_entity_number )
|
||||
{
|
||||
while ( swipe.num_live_swipes > 1 )
|
||||
{
|
||||
i = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS;
|
||||
swipepoint_t &swipepoint = swipe.swipepoints[i];
|
||||
|
||||
if ( swipepoint.time < cg.time - swipe.life )
|
||||
{
|
||||
// then let's delete the previous
|
||||
swipe.first_swipe = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS;
|
||||
swipe.num_live_swipes--;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( swipe.num_live_swipes == 1 )
|
||||
{
|
||||
swipepoint_t &swipepoint = swipe.swipepoints[swipe.first_swipe];
|
||||
if ( swipepoint.time < cg.time - swipe.life )
|
||||
{
|
||||
swipe.num_live_swipes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
swipe.cntPoint.time = cg.time;
|
||||
VectorCopy ( current_entity->origin, swipe.cntPoint.points[0] );
|
||||
|
||||
tagnum_start = cgi.Tag_NumForName( current_tiki, swipe.tagname_start.c_str() );
|
||||
_or = cgi.TIKI_Orientation(current_entity, tagnum_start);
|
||||
|
||||
// Clear out the points
|
||||
VectorClear ( tmp );
|
||||
VectorClear ( swipe.cntPoint.points[0] );
|
||||
VectorClear ( swipe.cntPoint.points[1] );
|
||||
|
||||
if ( ev->NumArgs() > 0 )
|
||||
VectorCopy( ev->GetVector( 1 ), tmp );
|
||||
else
|
||||
VectorCopy ( current_entity->origin, tmp );
|
||||
|
||||
// Transform the origin of the tag by the axis of the entity and add it to the origin of the entity
|
||||
for ( i = 0; i < 3; i++ )
|
||||
{
|
||||
VectorMA ( tmp, _or.origin[i], current_entity->axis[i], tmp );
|
||||
}
|
||||
|
||||
// Copy tmp into the startpoint
|
||||
VectorCopy ( tmp, swipe.cntPoint.points[0] );
|
||||
|
||||
tagnum_end = cgi.Tag_NumForName( current_tiki, swipe.tagname_end.c_str() );
|
||||
_or = cgi.TIKI_Orientation(current_entity, tagnum_end);
|
||||
|
||||
if ( ev->NumArgs() > 0 )
|
||||
VectorCopy( ev->GetVector( 1 ), tmp );
|
||||
else
|
||||
VectorCopy ( current_entity->origin, tmp );
|
||||
|
||||
// Transform the origin of the tag by the axis of the entity and add it to the origin of the entity
|
||||
for ( i = 0; i < 3; i++ )
|
||||
{
|
||||
VectorMA ( tmp, _or.origin[i], current_entity->axis[i], tmp );
|
||||
}
|
||||
|
||||
// Copy tmp into the startpoint
|
||||
VectorCopy ( tmp, swipe.cntPoint.points[1] );
|
||||
|
||||
if ( swipe.num_live_swipes == 0 )
|
||||
add_cnt_point = qtrue;
|
||||
else
|
||||
{
|
||||
float deltime = swipe.life / float ( MAX_SWIPES );
|
||||
swipepoint_t &lastpoint = swipe.swipepoints[ ( swipe.first_swipe + swipe.num_live_swipes - 1 ) % MAX_SWIPE_POINTS];
|
||||
|
||||
if ( swipe.cntPoint.time - lastpoint.time >= deltime )
|
||||
add_cnt_point = qtrue;
|
||||
}
|
||||
|
||||
cgi.R_SwipeBegin ( cg.time, swipe.life, swipe.shader );
|
||||
|
||||
if ( add_cnt_point )
|
||||
{
|
||||
swipepoint_t &swipepoint = swipe.swipepoints[ ( swipe.first_swipe + swipe.num_live_swipes ) % MAX_SWIPE_POINTS];
|
||||
|
||||
swipepoint = swipe.cntPoint;
|
||||
|
||||
if ( swipe.num_live_swipes == MAX_SWIPE_POINTS )
|
||||
swipe.first_swipe = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS;
|
||||
else
|
||||
swipe.num_live_swipes++;
|
||||
}
|
||||
|
||||
for ( i = 0; i != swipe.num_live_swipes; i++ )
|
||||
{
|
||||
swipepoint_t &swipepoint = swipe.swipepoints[ ( swipe.first_swipe + i ) % MAX_SWIPE_POINTS];
|
||||
|
||||
cgi.R_SwipePoint ( swipepoint.points[0], swipepoint.points[1], swipepoint.time );
|
||||
}
|
||||
|
||||
if ( !add_cnt_point )
|
||||
cgi.R_SwipePoint ( swipe.cntPoint.points[0], swipe.cntPoint.points[1], swipe.cntPoint.time );
|
||||
|
||||
cgi.R_SwipeEnd ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::ClearSwipes
|
||||
(
|
||||
void
|
||||
)
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=0; i < MAX_SWIPES; i++ )
|
||||
{
|
||||
swipething_t &swipe = m_swipes[i];
|
||||
|
||||
swipe.enabled = qfalse;
|
||||
}
|
||||
|
||||
cgi.R_SwipeBegin ( 0.f, 0.f, -1 );
|
||||
cgi.R_SwipeEnd ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
CG_ClearSwipes
|
||||
|
||||
This is called at startup and for tournement restarts
|
||||
===================
|
||||
*/
|
||||
void CG_ClearSwipes( void )
|
||||
{
|
||||
commandManager.ClearSwipes();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2015 the OpenMoHAA team
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
@@ -20,7 +20,5 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
typedef struct UIPoint2D_s {
|
||||
float x;
|
||||
float y;
|
||||
} UIPoint2D;
|
||||
// DESCRIPTION:
|
||||
// Temporary models effects
|
||||
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// testemitter functions. Used for designing emitters in game
|
||||
|
||||
#include "cg_commands.h"
|
||||
#include "cg_specialfx.h"
|
||||
|
||||
cvar_t* cg_te_alpha;
|
||||
cvar_t* cg_te_dietouch;
|
||||
cvar_t* cg_te_bouncefactor;
|
||||
cvar_t* cg_te_scale;
|
||||
cvar_t* cg_te_scalemin;
|
||||
cvar_t* cg_te_scalemax;
|
||||
cvar_t* cg_te_model;
|
||||
cvar_t* cg_te_life;
|
||||
cvar_t* cg_te_color_r;
|
||||
cvar_t* cg_te_color_g;
|
||||
cvar_t* cg_te_color_b;
|
||||
cvar_t* cg_te_accel_x;
|
||||
cvar_t* cg_te_accel_y;
|
||||
cvar_t* cg_te_accel_z;
|
||||
cvar_t* cg_te_count;
|
||||
cvar_t* cg_te_fade;
|
||||
cvar_t* cg_te_fadedelay;
|
||||
cvar_t* cg_te_fadein;
|
||||
cvar_t* cg_te_spawnrate;
|
||||
cvar_t* cg_te_offsbase_x;
|
||||
cvar_t* cg_te_offsbase_y;
|
||||
cvar_t* cg_te_offsbase_z;
|
||||
cvar_t* cg_te_offsamp_x;
|
||||
cvar_t* cg_te_offsamp_y;
|
||||
cvar_t* cg_te_offsamp_z;
|
||||
cvar_t* cg_te_scalerate;
|
||||
cvar_t* cg_te_circle;
|
||||
cvar_t* cg_te_sphere;
|
||||
cvar_t* cg_te_insphere;
|
||||
cvar_t* cg_te_radius;
|
||||
cvar_t* cg_te_align;
|
||||
cvar_t* cg_te_flickeralpha;
|
||||
cvar_t* cg_te_collision;
|
||||
cvar_t* cg_te_randomroll;
|
||||
cvar_t* cg_te_anglesbase_p;
|
||||
cvar_t* cg_te_anglesbase_y;
|
||||
cvar_t* cg_te_anglesbase_r;
|
||||
cvar_t* cg_te_anglesamp_p;
|
||||
cvar_t* cg_te_anglesamp_y;
|
||||
cvar_t* cg_te_anglesamp_r;
|
||||
cvar_t* cg_te_forwardvel;
|
||||
cvar_t* cg_te_randvelbase_x;
|
||||
cvar_t* cg_te_randvelbase_y;
|
||||
cvar_t* cg_te_randvelbase_z;
|
||||
cvar_t* cg_te_randvelamp_x;
|
||||
cvar_t* cg_te_randvelamp_y;
|
||||
cvar_t* cg_te_randvelamp_z;
|
||||
cvar_t* cg_te_clampvelmin_x;
|
||||
cvar_t* cg_te_clampvelmax_x;
|
||||
cvar_t* cg_te_clampvelmin_y;
|
||||
cvar_t* cg_te_clampvelmax_y;
|
||||
cvar_t* cg_te_clampvelmin_z;
|
||||
cvar_t* cg_te_clampvelmax_z;
|
||||
cvar_t* cg_te_clampvelaxis;
|
||||
cvar_t* cg_te_volumetric;
|
||||
cvar_t* cg_te_randaxis;
|
||||
cvar_t* cg_te_axisoffsbase_x;
|
||||
cvar_t* cg_te_axisoffsbase_y;
|
||||
cvar_t* cg_te_axisoffsbase_z;
|
||||
cvar_t* cg_te_axisoffsamp_x;
|
||||
cvar_t* cg_te_axisoffsamp_y;
|
||||
cvar_t* cg_te_axisoffsamp_z;
|
||||
cvar_t* cg_te_swarm_freq;
|
||||
cvar_t* cg_te_swarm_maxspeed;
|
||||
cvar_t* cg_te_swarm_delta;
|
||||
cvar_t* cg_te_avelbase_p;
|
||||
cvar_t* cg_te_avelbase_y;
|
||||
cvar_t* cg_te_avelbase_r;
|
||||
cvar_t* cg_te_avelamp_p;
|
||||
cvar_t* cg_te_avelamp_y;
|
||||
cvar_t* cg_te_avelamp_r;
|
||||
cvar_t* cg_te_radial_scale;
|
||||
cvar_t* cg_te_radial_min;
|
||||
cvar_t* cg_te_radial_max;
|
||||
cvar_t* cg_te_friction;
|
||||
cvar_t* cg_te_varycolor;
|
||||
cvar_t* cg_te_spritegridlighting;
|
||||
cvar_t* cg_te_cone_height;
|
||||
cvar_t* cg_te_alignstretch_scale;
|
||||
cvar_t* cg_te_spawnrange_a;
|
||||
cvar_t* cg_te_spawnrange_b;
|
||||
cvar_t* cg_te_command_time;
|
||||
cvar_t* cg_te_singlelinecommand;
|
||||
cvar_t* cg_te_tag;
|
||||
cvar_t* cg_te_xangles;
|
||||
cvar_t* cg_te_yangles;
|
||||
cvar_t* cg_te_zangles;
|
||||
class specialeffect_t;
|
||||
refEntity_t te_refEnt;
|
||||
cvar_t* cg_te_emittermodel;
|
||||
cvar_t* cg_te_mode;
|
||||
cvar_t* cg_te_mode_name;
|
||||
cvar_t* cg_te_currCommand;
|
||||
cvar_t* cg_te_numCommands;
|
||||
float te_vEmitterOrigin[3];
|
||||
int te_iNumCommands;
|
||||
int te_iCurrCommand;
|
||||
specialeffect_t *pTesteffect;
|
||||
|
||||
#define MAX_TESTEMITTERS_SAVE 32
|
||||
|
||||
str cg_te_alphaG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_dietouchG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_bouncefactorG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_scaleG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_scaleminG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_scalemaxG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_modelG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_lifeG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_color_rG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_color_gG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_color_bG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_accel_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_accel_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_accel_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_countG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_fadeG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_fadedelayG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_fadeinG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_spawnrateG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_offsbase_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_offsbase_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_offsbase_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_offsamp_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_offsamp_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_offsamp_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_scalerateG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_circleG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_sphereG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_insphereG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_radiusG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_alignG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_flickeralphaG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_collisionG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randomrollG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_anglesbase_pG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_anglesbase_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_anglesbase_rG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_anglesamp_pG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_anglesamp_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_anglesamp_rG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_forwardvelG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randvelbase_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randvelbase_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randvelbase_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randvelamp_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randvelamp_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randvelamp_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelmin_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelmax_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelmin_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelmax_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelmin_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelmax_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_clampvelaxisG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_volumetricG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_randaxisG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_axisoffsbase_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_axisoffsbase_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_axisoffsbase_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_axisoffsamp_xG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_axisoffsamp_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_axisoffsamp_zG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_swarm_freqG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_swarm_maxspeedG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_swarm_deltaG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_avelbase_pG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_avelbase_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_avelbase_rG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_avelamp_pG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_avelamp_yG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_avelamp_rG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_radial_scaleG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_radial_minG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_radial_maxG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_frictionG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_varycolorG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_spritegridlightingG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_spawnrange_aG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_spawnrange_bG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_cone_heightG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_alignstretch_scaleG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_command_timeG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_singlelinecommandG[MAX_TESTEMITTERS_SAVE];
|
||||
str cg_te_tagG[MAX_TESTEMITTERS_SAVE];
|
||||
|
||||
spawnthing_t* testspawnthing = NULL;
|
||||
|
||||
void CG_SaveEffectCommandCvars(int iCommand)
|
||||
{
|
||||
cg_te_alphaG[iCommand] = cg_te_alpha->string;
|
||||
cg_te_dietouchG[iCommand] = cg_te_dietouch->string;
|
||||
cg_te_bouncefactorG[iCommand] = cg_te_bouncefactor->string;
|
||||
cg_te_scaleG[iCommand] = cg_te_scale->string;
|
||||
cg_te_scaleminG[iCommand] = cg_te_scalemin->string;
|
||||
cg_te_scalemaxG[iCommand] = cg_te_scalemax->string;
|
||||
cg_te_modelG[iCommand] = cg_te_model->string;
|
||||
cg_te_lifeG[iCommand] = cg_te_life->string;
|
||||
cg_te_color_rG[iCommand] = cg_te_color_r->string;
|
||||
cg_te_color_gG[iCommand] = cg_te_color_g->string;
|
||||
cg_te_color_bG[iCommand] = cg_te_color_b->string;
|
||||
cg_te_accel_xG[iCommand] = cg_te_accel_x->string;
|
||||
cg_te_accel_yG[iCommand] = cg_te_accel_y->string;
|
||||
cg_te_accel_zG[iCommand] = cg_te_accel_z->string;
|
||||
cg_te_countG[iCommand] = cg_te_count->string;
|
||||
cg_te_fadeG[iCommand] = cg_te_fade->string;
|
||||
cg_te_fadedelayG[iCommand] = cg_te_fadedelay->string;
|
||||
cg_te_fadeinG[iCommand] = cg_te_fadein->string;
|
||||
cg_te_spawnrateG[iCommand] = cg_te_spawnrate->string;
|
||||
cg_te_offsbase_xG[iCommand] = cg_te_offsbase_x->string;
|
||||
cg_te_offsbase_yG[iCommand] = cg_te_offsbase_y->string;
|
||||
cg_te_offsbase_zG[iCommand] = cg_te_offsbase_z->string;
|
||||
cg_te_offsamp_xG[iCommand] = cg_te_offsamp_x->string;
|
||||
cg_te_offsamp_yG[iCommand] = cg_te_offsamp_y->string;
|
||||
cg_te_offsamp_zG[iCommand] = cg_te_offsamp_z->string;
|
||||
cg_te_scalerateG[iCommand] = cg_te_scalerate->string;
|
||||
cg_te_circleG[iCommand] = cg_te_circle->string;
|
||||
cg_te_sphereG[iCommand] = cg_te_sphere->string;
|
||||
cg_te_insphereG[iCommand] = cg_te_insphere->string;
|
||||
cg_te_radiusG[iCommand] = cg_te_radius->string;
|
||||
cg_te_alignG[iCommand] = cg_te_align->string;
|
||||
cg_te_flickeralphaG[iCommand] = cg_te_flickeralpha->string;
|
||||
cg_te_collisionG[iCommand] = cg_te_collision->string;
|
||||
cg_te_randomrollG[iCommand] = cg_te_randomroll->string;
|
||||
cg_te_anglesbase_pG[iCommand] = cg_te_anglesbase_p->string;
|
||||
cg_te_anglesbase_yG[iCommand] = cg_te_anglesbase_y->string;
|
||||
cg_te_anglesbase_rG[iCommand] = cg_te_anglesbase_r->string;
|
||||
cg_te_anglesamp_pG[iCommand] = cg_te_anglesamp_p->string;
|
||||
cg_te_anglesamp_yG[iCommand] = cg_te_anglesamp_y->string;
|
||||
cg_te_anglesamp_rG[iCommand] = cg_te_anglesamp_r->string;
|
||||
cg_te_forwardvelG[iCommand] = cg_te_forwardvel->string;
|
||||
cg_te_randvelbase_xG[iCommand] = cg_te_randvelbase_x->string;
|
||||
cg_te_randvelbase_yG[iCommand] = cg_te_randvelbase_y->string;
|
||||
cg_te_randvelbase_zG[iCommand] = cg_te_randvelbase_z->string;
|
||||
cg_te_randvelamp_xG[iCommand] = cg_te_randvelamp_x->string;
|
||||
cg_te_randvelamp_yG[iCommand] = cg_te_randvelamp_y->string;
|
||||
cg_te_randvelamp_zG[iCommand] = cg_te_randvelamp_z->string;
|
||||
cg_te_clampvelmin_xG[iCommand] = cg_te_clampvelmin_x->string;
|
||||
cg_te_clampvelmax_xG[iCommand] = cg_te_clampvelmax_x->string;
|
||||
cg_te_clampvelmin_yG[iCommand] = cg_te_clampvelmin_y->string;
|
||||
cg_te_clampvelmax_yG[iCommand] = cg_te_clampvelmax_y->string;
|
||||
cg_te_clampvelmin_zG[iCommand] = cg_te_clampvelmin_z->string;
|
||||
cg_te_clampvelmax_zG[iCommand] = cg_te_clampvelmax_z->string;
|
||||
cg_te_clampvelaxisG[iCommand] = cg_te_clampvelaxis->string;
|
||||
cg_te_volumetricG[iCommand] = cg_te_volumetric->string;
|
||||
cg_te_randaxisG[iCommand] = cg_te_randaxis->string;
|
||||
cg_te_axisoffsbase_xG[iCommand] = cg_te_axisoffsbase_x->string;
|
||||
cg_te_axisoffsbase_yG[iCommand] = cg_te_axisoffsbase_y->string;
|
||||
cg_te_axisoffsbase_zG[iCommand] = cg_te_axisoffsbase_z->string;
|
||||
cg_te_axisoffsamp_xG[iCommand] = cg_te_axisoffsamp_x->string;
|
||||
cg_te_axisoffsamp_yG[iCommand] = cg_te_axisoffsamp_y->string;
|
||||
cg_te_axisoffsamp_zG[iCommand] = cg_te_axisoffsamp_z->string;
|
||||
cg_te_swarm_freqG[iCommand] = cg_te_swarm_freq->string;
|
||||
cg_te_swarm_maxspeedG[iCommand] = cg_te_swarm_maxspeed->string;
|
||||
cg_te_swarm_deltaG[iCommand] = cg_te_swarm_delta->string;
|
||||
cg_te_avelbase_pG[iCommand] = cg_te_avelbase_p->string;
|
||||
cg_te_avelbase_yG[iCommand] = cg_te_avelbase_y->string;
|
||||
cg_te_avelbase_rG[iCommand] = cg_te_avelbase_r->string;
|
||||
cg_te_avelamp_pG[iCommand] = cg_te_avelamp_p->string;
|
||||
cg_te_avelamp_yG[iCommand] = cg_te_avelamp_y->string;
|
||||
cg_te_avelamp_rG[iCommand] = cg_te_avelamp_r->string;
|
||||
cg_te_radial_scaleG[iCommand] = cg_te_radial_scale->string;
|
||||
cg_te_radial_minG[iCommand] = cg_te_radial_min->string;
|
||||
cg_te_radial_maxG[iCommand] = cg_te_radial_max->string;
|
||||
cg_te_frictionG[iCommand] = cg_te_friction->string;
|
||||
cg_te_varycolorG[iCommand] = cg_te_varycolor->string;
|
||||
cg_te_spritegridlightingG[iCommand] = cg_te_spritegridlighting->string;
|
||||
cg_te_spawnrange_aG[iCommand] = cg_te_spawnrange_a->string;
|
||||
cg_te_spawnrange_bG[iCommand] = cg_te_spawnrange_b->string;
|
||||
cg_te_cone_heightG[iCommand] = cg_te_cone_height->string;
|
||||
cg_te_alignstretch_scaleG[iCommand] = cg_te_alignstretch_scale->string;
|
||||
cg_te_command_timeG[iCommand] = cg_te_command_time->string;
|
||||
cg_te_singlelinecommandG[iCommand] = cg_te_singlelinecommand->string;
|
||||
cg_te_tagG[iCommand] = cg_te_tag->string;
|
||||
}
|
||||
|
||||
void CG_ResetEffectCommandCvars()
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_SetTestEmitterValues()
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_UpdateTestEmitter(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_SortEffectCommands()
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_TriggerTestEmitter_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_DumpBaseAndAmplitude(str* buff, char* prefix, Vector* base, Vector* amplitude)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_DumpEmitter_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_LoadBaseAndAmplitude(char** pBufer, char* szCvarX, char* szCvarY, char* szCvarZ, char* szCvarXAmp, char* szCvarYAmp, char* szCvarZAmp)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_LoadEmitter_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_TestEmitter_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_PrevEmitterCommand_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_NextEmitterCommand_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_NewEmitterCommand_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_DeleteEmitterCommand_f(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
}
|
||||
|
||||
void CG_InitTestEmitter(void)
|
||||
{
|
||||
cg_te_life = cgi.Cvar_Get("cg_te_life", "1", 0);
|
||||
cg_te_alpha = cgi.Cvar_Get("cg_te_alpha", "1", 0);
|
||||
cg_te_dietouch = cgi.Cvar_Get("cg_te_dietouch", "0", 0);
|
||||
cg_te_bouncefactor = cgi.Cvar_Get("cg_te_bouncefactor", "0.3", 0);
|
||||
cg_te_scale = cgi.Cvar_Get("cg_te_scale", "1", 0);
|
||||
cg_te_scalemin = cgi.Cvar_Get("cg_te_scalemin", "0", 0);
|
||||
cg_te_scalemax = cgi.Cvar_Get("cg_te_scalemax", "0", 0);
|
||||
cg_te_model = cgi.Cvar_Get("cg_te_model", "none", 0);
|
||||
cg_te_life = cgi.Cvar_Get("cg_te_life", "1", 0);
|
||||
cg_te_color_r = cgi.Cvar_Get("cg_te_color_r", "1", 0);
|
||||
cg_te_color_g = cgi.Cvar_Get("cg_te_color_g", "1", 0);
|
||||
cg_te_color_b = cgi.Cvar_Get("cg_te_color_b", "1", 0);
|
||||
cg_te_accel_x = cgi.Cvar_Get("cg_te_accel_x", "0", 0);
|
||||
cg_te_accel_y = cgi.Cvar_Get("cg_te_accel_y", "0", 0);
|
||||
cg_te_accel_z = cgi.Cvar_Get("cg_te_accel_z", "0", 0);
|
||||
cg_te_count = cgi.Cvar_Get("cg_te_count", "1", 0);
|
||||
cg_te_fade = cgi.Cvar_Get("cg_te_fade", "0", 0);
|
||||
cg_te_fadedelay = cgi.Cvar_Get("cg_te_fadedelay", "0", 0);
|
||||
cg_te_fadein = cgi.Cvar_Get("cg_te_fadein", "0", 0);
|
||||
cg_te_spawnrate = cgi.Cvar_Get("cg_te_spawnrate", "1", 0);
|
||||
cg_te_scalerate = cgi.Cvar_Get("cg_te_scalerate", "0", 0);
|
||||
cg_te_circle = cgi.Cvar_Get("cg_te_circle", "0", 0);
|
||||
cg_te_sphere = cgi.Cvar_Get("cg_te_sphere", "0", 0);
|
||||
cg_te_insphere = cgi.Cvar_Get("cg_te_insphere", "0", 0);
|
||||
cg_te_radius = cgi.Cvar_Get("cg_te_radius", "0", 0);
|
||||
cg_te_align = cgi.Cvar_Get("cg_te_align", "0", 0);
|
||||
cg_te_flickeralpha = cgi.Cvar_Get("cg_te_flickeralpha", "0", 0);
|
||||
cg_te_collision = cgi.Cvar_Get("cg_te_collision", "0", 0);
|
||||
cg_te_randomroll = cgi.Cvar_Get("cg_te_randomroll", "0", 0);
|
||||
cg_te_offsbase_x = cgi.Cvar_Get("cg_te_offsbase_x", "0", 0);
|
||||
cg_te_offsbase_y = cgi.Cvar_Get("cg_te_offsbase_y", "0", 0);
|
||||
cg_te_offsbase_z = cgi.Cvar_Get("cg_te_offsbase_z", "0", 0);
|
||||
cg_te_offsamp_x = cgi.Cvar_Get("cg_te_offsamp_x", "0", 0);
|
||||
cg_te_offsamp_y = cgi.Cvar_Get("cg_te_offsamp_y", "0", 0);
|
||||
cg_te_offsamp_z = cgi.Cvar_Get("cg_te_offsamp_z", "0", 0);
|
||||
cg_te_anglesbase_p = cgi.Cvar_Get("cg_te_anglesbase_p", "0", 0);
|
||||
cg_te_anglesbase_y = cgi.Cvar_Get("cg_te_anglesbase_y", "0", 0);
|
||||
cg_te_anglesbase_r = cgi.Cvar_Get("cg_te_anglesbase_r", "0", 0);
|
||||
cg_te_anglesamp_p = cgi.Cvar_Get("cg_te_anglesamp_p", "0", 0);
|
||||
cg_te_anglesamp_y = cgi.Cvar_Get("cg_te_anglesamp_y", "0", 0);
|
||||
cg_te_anglesamp_r = cgi.Cvar_Get("cg_te_anglesamp_r", "0", 0);
|
||||
cg_te_randvelbase_x = cgi.Cvar_Get("cg_te_randvelbase_x", "0", 0);
|
||||
cg_te_randvelbase_y = cgi.Cvar_Get("cg_te_randvelbase_y", "0", 0);
|
||||
cg_te_randvelbase_z = cgi.Cvar_Get("cg_te_randvelbase_z", "0", 0);
|
||||
cg_te_randvelamp_x = cgi.Cvar_Get("cg_te_randvelamp_x", "0", 0);
|
||||
cg_te_randvelamp_y = cgi.Cvar_Get("cg_te_randvelamp_y", "0", 0);
|
||||
cg_te_randvelamp_z = cgi.Cvar_Get("cg_te_randvelamp_z", "0", 0);
|
||||
cg_te_clampvelmin_x = cgi.Cvar_Get("cg_te_clampvelmin_x", "-9999", 0);
|
||||
cg_te_clampvelmax_x = cgi.Cvar_Get("cg_te_clampvelmax_x", "9999", 0);
|
||||
cg_te_clampvelmin_y = cgi.Cvar_Get("cg_te_clampvelmin_y", "-9999", 0);
|
||||
cg_te_clampvelmax_y = cgi.Cvar_Get("cg_te_clampvelmax_y", "9999", 0);
|
||||
cg_te_clampvelmin_z = cgi.Cvar_Get("cg_te_clampvelmin_z", "-9999", 0);
|
||||
cg_te_clampvelmax_z = cgi.Cvar_Get("cg_te_clampvelmax_z", "9999", 0);
|
||||
cg_te_clampvelaxis = cgi.Cvar_Get("cg_te_clampvelaxis", "0", 0);
|
||||
cg_te_forwardvel = cgi.Cvar_Get("cg_te_forwardvel", "0", 0);
|
||||
cg_te_volumetric = cgi.Cvar_Get("cg_te_volumetric", "0", 0);
|
||||
cg_te_randaxis = cgi.Cvar_Get("cg_te_randaxis", "0", 0);
|
||||
cg_te_axisoffsbase_x = cgi.Cvar_Get("cg_te_axisoffsbase_x", "0", 0);
|
||||
cg_te_axisoffsbase_y = cgi.Cvar_Get("cg_te_axisoffsbase_y", "0", 0);
|
||||
cg_te_axisoffsbase_z = cgi.Cvar_Get("cg_te_axisoffsbase_z", "0", 0);
|
||||
cg_te_axisoffsamp_x = cgi.Cvar_Get("cg_te_axisoffsamp_x", "0", 0);
|
||||
cg_te_axisoffsamp_y = cgi.Cvar_Get("cg_te_axisoffsamp_y", "0", 0);
|
||||
cg_te_axisoffsamp_z = cgi.Cvar_Get("cg_te_axisoffsamp_z", "0", 0);
|
||||
cg_te_swarm_freq = cgi.Cvar_Get("cg_te_swarm_freq", "0", 0);
|
||||
cg_te_swarm_maxspeed = cgi.Cvar_Get("cg_te_swarm_maxspeed", "0", 0);
|
||||
cg_te_swarm_delta = cgi.Cvar_Get("cg_te_swarm_delta", "0", 0);
|
||||
cg_te_avelbase_p = cgi.Cvar_Get("cg_te_avelbase_p", "0", 0);
|
||||
cg_te_avelbase_y = cgi.Cvar_Get("cg_te_avelbase_y", "0", 0);
|
||||
cg_te_avelbase_r = cgi.Cvar_Get("cg_te_avelbase_r", "0", 0);
|
||||
cg_te_avelamp_p = cgi.Cvar_Get("cg_te_avelamp_p", "0", 0);
|
||||
cg_te_avelamp_y = cgi.Cvar_Get("cg_te_avelamp_y", "0", 0);
|
||||
cg_te_avelamp_r = cgi.Cvar_Get("cg_te_avelamp_r", "0", 0);
|
||||
cg_te_radial_scale = cgi.Cvar_Get("cg_te_radial_scale", "0", 0);
|
||||
cg_te_radial_min = cgi.Cvar_Get("cg_te_radial_min", "0", 0);
|
||||
cg_te_radial_max = cgi.Cvar_Get("cg_te_radial_max", "0", 0);
|
||||
cg_te_friction = cgi.Cvar_Get("cg_te_friction", "0", 0);
|
||||
cg_te_varycolor = cgi.Cvar_Get("cg_te_varycolor", "0", 0);
|
||||
cg_te_spritegridlighting = cgi.Cvar_Get("cg_te_spritegridlighting", "0", 0);
|
||||
cg_te_spawnrange_a = cgi.Cvar_Get("cg_te_spawnrange_a", "0", 0);
|
||||
cg_te_spawnrange_b = cgi.Cvar_Get("cg_te_spawnrange_b", "0", 0);
|
||||
cg_te_cone_height = cgi.Cvar_Get("cg_te_cone_height", "0", 0);
|
||||
cg_te_alignstretch_scale = cgi.Cvar_Get("cg_te_alignstretch_scale", "0", 0);
|
||||
cg_te_command_time = cgi.Cvar_Get("cg_te_command_time", "0", 0);
|
||||
cg_te_singlelinecommand = cgi.Cvar_Get("cg_te_singlelinecommand", "", 0);
|
||||
cg_te_tag = cgi.Cvar_Get("cg_te_tag", "", 0);
|
||||
|
||||
for (int i = 0; i < MAX_TESTEMITTERS_SAVE; ++i) {
|
||||
CG_SaveEffectCommandCvars(i);
|
||||
}
|
||||
|
||||
cg_te_xangles = cgi.Cvar_Get("cg_te_xangles", "0", 0);
|
||||
cg_te_yangles = cgi.Cvar_Get("cg_te_yangles", "0", 0);
|
||||
cg_te_zangles = cgi.Cvar_Get("cg_te_zangles", "0", 0);
|
||||
cg_te_emittermodel = cgi.Cvar_Get("cg_te_emittermodel", "", 0);
|
||||
cg_te_mode = cgi.Cvar_Get("cg_te_mode", "0", 0);
|
||||
cg_te_mode_name = cgi.Cvar_Get("cg_te_mode_name", "Emitter Mode", 0);
|
||||
cg_te_currCommand = cgi.Cvar_Get("cg_te_currCommand", "0", 0);
|
||||
|
||||
te_vEmitterOrigin[2] = 0.0;
|
||||
te_vEmitterOrigin[1] = 0.0;
|
||||
te_vEmitterOrigin[0] = 0.0;
|
||||
te_refEnt.scale = 0.0;
|
||||
cg_te_numCommands = cgi.Cvar_Get("cg_te_numCommands", "0", 0);
|
||||
te_iNumCommands = 0;
|
||||
te_iCurrCommand = 0;
|
||||
|
||||
pTesteffect = sfxManager.GetTestEffectPointer();
|
||||
}
|
||||
@@ -1,298 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2010-2011 Michael Rieder
|
||||
|
||||
This file is part of OpenMohaa source code.
|
||||
|
||||
OpenMohaa source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMohaa source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMohaa source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "cg_local.h"
|
||||
|
||||
#define MAX_UBERSOUNDS 8192
|
||||
ubersound_t snd_indexes[MAX_UBERSOUNDS];
|
||||
int snd_numIndexes;
|
||||
char *buffer;
|
||||
|
||||
#define FILE_HASH_SIZE 256
|
||||
static ubersound_t* hashTable[FILE_HASH_SIZE];
|
||||
|
||||
static long generateHashValue( const char *fname ) {
|
||||
int i;
|
||||
long hash;
|
||||
char letter;
|
||||
|
||||
hash = 0;
|
||||
i = 0;
|
||||
while (fname[i] != '\0') {
|
||||
letter = tolower(fname[i]);
|
||||
hash+=(long)(letter)*(i+119);
|
||||
i++;
|
||||
}
|
||||
hash &= (FILE_HASH_SIZE-1);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static ubersound_t* US_Find( const char *snd_name ) {
|
||||
ubersound_t* snd;
|
||||
long hash;
|
||||
|
||||
hash = generateHashValue(snd_name);
|
||||
|
||||
for (snd=hashTable[hash] ; snd ; snd=snd->hashNext) {
|
||||
if (!Q_stricmp(snd_name, snd->name)) {
|
||||
return snd;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ubersound_t* CG_GetUbersound( const char *name ) {
|
||||
ubersound_t *snd;
|
||||
|
||||
snd = US_Find( name );
|
||||
|
||||
if ( !snd ) {
|
||||
CG_Printf( "CG_GetUbersound: sound \"%s\" not found.\n", name );
|
||||
return NULL;
|
||||
}
|
||||
// if there are more than one version, choose randomly
|
||||
if ( snd->variations ) {
|
||||
int i, var;
|
||||
|
||||
var = rand();
|
||||
var *= snd->variations;
|
||||
var /= RAND_MAX+1;
|
||||
|
||||
// CG_Printf( "random sound %i of %i\n", var, snd->variations );
|
||||
for (i=0;i<var;i++)
|
||||
snd = snd->nextVariation;
|
||||
}
|
||||
|
||||
if ( snd->hasLoaded == qfalse )
|
||||
snd->sfxHandle = cgi.S_RegisterSound( snd->wavfile, qfalse );
|
||||
|
||||
return snd;
|
||||
}
|
||||
|
||||
void CG_ParseUSline( char **ptr, ubersound_t *snd ) {
|
||||
const char *chan;
|
||||
const char *token;
|
||||
// name
|
||||
Q_strncpyz( snd->name, COM_Parse(ptr), sizeof(snd->name) );
|
||||
Q_strncpyz( snd->wavfile, COM_Parse(ptr), sizeof(snd->wavfile) );
|
||||
// soundparms
|
||||
if ( !Q_strncmp( COM_Parse(ptr), "soundparms", MAX_QPATH ) ) {
|
||||
snd->basevol = atof(COM_Parse(ptr));
|
||||
snd->volmod = atof(COM_Parse(ptr));
|
||||
snd->basepitch = atof(COM_Parse(ptr));
|
||||
snd->pitchmod = atof(COM_Parse(ptr));
|
||||
snd->minDist = atof(COM_Parse(ptr));
|
||||
snd->maxDist = atof(COM_Parse(ptr));
|
||||
|
||||
// channel
|
||||
chan = COM_Parse(ptr);
|
||||
if ( !Q_strncmp( chan, "auto", MAX_QPATH ) )
|
||||
snd->channel = CHAN_AUTO;
|
||||
else if ( !Q_strncmp( chan, "body", MAX_QPATH ) )
|
||||
snd->channel = CHAN_BODY;
|
||||
else if ( !Q_strncmp( chan, "item", MAX_QPATH ) )
|
||||
snd->channel = CHAN_ITEM;
|
||||
else if ( !Q_strncmp( chan, "weaponidle", MAX_QPATH ) )
|
||||
snd->channel = CHAN_WEAPONIDLE;
|
||||
else if ( !Q_strncmp( chan, "voice", MAX_QPATH ) )
|
||||
snd->channel = CHAN_VOICE;
|
||||
else if ( !Q_strncmp( chan, "local", MAX_QPATH ) )
|
||||
snd->channel = CHAN_LOCAL;
|
||||
else if ( !Q_strncmp( chan, "weapon", MAX_QPATH ) )
|
||||
snd->channel = CHAN_WEAPON;
|
||||
else if ( !Q_strncmp( chan, "dialog_secondary", MAX_QPATH ) )
|
||||
snd->channel = CHAN_DIALOG_SECONDARY;
|
||||
else if ( !Q_strncmp( chan, "dialog", MAX_QPATH ) )
|
||||
snd->channel = CHAN_DIALOG;
|
||||
else if ( !Q_strncmp( chan, "menu", MAX_QPATH ) )
|
||||
snd->channel = CHAN_MENU;
|
||||
else
|
||||
CG_Printf( "Ubersound unrecognized channel %s for %s\n", chan, snd->name );
|
||||
// loaded /Streamed
|
||||
chan = COM_Parse(ptr);
|
||||
if ( !Q_strncmp( chan, "loaded", MAX_QPATH ) )
|
||||
snd->loaded = qtrue;
|
||||
else if ( !Q_strncmp( chan, "streamed", MAX_QPATH ) )
|
||||
snd->loaded = qfalse;
|
||||
else
|
||||
CG_Printf( "Ubersound unrecognized loaded state %s for %s\n", chan, snd->name );
|
||||
}
|
||||
token = COM_Parse(ptr);
|
||||
// subtitle - su44: we need this for ubersound/uberdialog.scr loading
|
||||
if ( !Q_stricmp( token, "subtitle" ) ) {
|
||||
Q_strncpyz( snd->subtitle, COM_Parse(ptr), sizeof(snd->subtitle) );
|
||||
token = COM_Parse(ptr);
|
||||
}
|
||||
// maplist
|
||||
if ( !Q_stricmp( token, "maps" ) )
|
||||
Q_strncpyz( snd->mapstring, COM_Parse(ptr), MAPSTRING_LENGTH );
|
||||
}
|
||||
|
||||
qboolean US_CheckMapstring( const char *mapstring ) {
|
||||
char *ptr;
|
||||
const char *token;
|
||||
|
||||
ptr = (char*)mapstring;
|
||||
token = COM_Parse(&ptr);
|
||||
while (*token) {
|
||||
if ( strstr( cgs.mapname, token ) )
|
||||
return qtrue;
|
||||
token = COM_Parse(&ptr);
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
void CG_LoadUberSoundFile( const char *fname, qboolean sndVar ) {
|
||||
// sndVar decides whether the last digit (if it is a digit) provides a variation of the same sound
|
||||
int len;
|
||||
|
||||
const char *token;
|
||||
char *ptr;
|
||||
qboolean end;
|
||||
ubersound_t *oldSnd, *newSnd;
|
||||
int i;
|
||||
|
||||
CG_Printf( "=== Loading %s ===\n", fname );
|
||||
|
||||
len = cgi.FS_ReadFile( fname, &buffer, qfalse );
|
||||
|
||||
if( len <= 0 ) {
|
||||
CG_Printf( "couldn't load %s. file not found.\n", fname );
|
||||
return;
|
||||
}
|
||||
|
||||
end = qfalse;
|
||||
ptr = buffer;
|
||||
token = COM_Parse( &ptr );
|
||||
|
||||
while (*token) {
|
||||
newSnd = &snd_indexes[snd_numIndexes];
|
||||
if ( !Q_strncmp(token,"aliascache",MAX_QPATH) || !Q_strncmp(token,"alias",MAX_QPATH) ) {
|
||||
CG_ParseUSline( &ptr, newSnd );
|
||||
|
||||
if ( US_CheckMapstring( newSnd->mapstring ) == qtrue ) {
|
||||
int variation;
|
||||
|
||||
variation = atoi(newSnd->name + strlen(newSnd->name)-1);
|
||||
if ( sndVar == qtrue && variation ) {
|
||||
newSnd->name[strlen(newSnd->name)-1] = 0;
|
||||
oldSnd = US_Find(newSnd->name);
|
||||
if ( oldSnd ) {
|
||||
oldSnd->variations++;
|
||||
for (i=oldSnd->variations;i>2;i--)
|
||||
oldSnd = oldSnd->nextVariation;
|
||||
oldSnd->nextVariation = newSnd;
|
||||
if ( newSnd->loaded == qtrue ) {
|
||||
newSnd->sfxHandle = cgi.S_RegisterSound( newSnd->wavfile, qfalse );
|
||||
newSnd->hasLoaded = qtrue;
|
||||
}
|
||||
snd_numIndexes++;
|
||||
if ( snd_numIndexes >= MAX_UBERSOUNDS ) {
|
||||
snd_numIndexes--;
|
||||
CG_Error( "CG_LoadUbersound: too many aliascaches in file.\n" );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else newSnd->variations++;
|
||||
}
|
||||
|
||||
i = generateHashValue(newSnd->name);
|
||||
oldSnd = hashTable[i];
|
||||
if (oldSnd) {
|
||||
while (oldSnd->hashNext)
|
||||
oldSnd = oldSnd->hashNext;
|
||||
oldSnd->hashNext = newSnd;
|
||||
}
|
||||
else
|
||||
hashTable[i] = newSnd;
|
||||
if ( newSnd->loaded == qtrue ) {
|
||||
newSnd->sfxHandle = cgi.S_RegisterSound( newSnd->wavfile, qfalse );
|
||||
newSnd->hasLoaded = qtrue;
|
||||
}
|
||||
snd_numIndexes++;
|
||||
if ( snd_numIndexes >= MAX_UBERSOUNDS ) {
|
||||
snd_numIndexes--;
|
||||
CG_Error( "CG_LoadUbersound: too many aliascaches in file.\n" );
|
||||
}
|
||||
} else {
|
||||
Com_Memset(newSnd,0,sizeof(ubersound_t) );
|
||||
}
|
||||
} //su44: "end" token is missing in MoHAA's uberdialog.scr
|
||||
//else if ( !Q_strncmp( token, "end", MAX_QPATH ) ) {
|
||||
// end = qtrue;
|
||||
// break;
|
||||
//}
|
||||
token = COM_Parse( &ptr );
|
||||
}
|
||||
//if ( end == qfalse )
|
||||
// Com_Printf( "CG_LoadUbersound hit end of file without end statement\n" );
|
||||
|
||||
cgi.FS_FreeFile( buffer );
|
||||
CG_Printf( "=== Finished %s ===\n", fname );
|
||||
}
|
||||
|
||||
void CG_LoadUbersound( void ) {
|
||||
Com_Memset(snd_indexes, 0, sizeof(snd_indexes));
|
||||
Com_Memset(hashTable, 0, sizeof(hashTable));
|
||||
snd_numIndexes = 0;
|
||||
|
||||
CG_LoadUberSoundFile(UBERSOUND_FILE, qtrue);
|
||||
// su44: used by MoHAA voicechats
|
||||
CG_LoadUberSoundFile(UBERDIALOG_FILE, qfalse);
|
||||
}
|
||||
|
||||
const char* CG_LoadMusic( const char *musicfile ) {
|
||||
|
||||
int len;
|
||||
|
||||
const char *token;
|
||||
char *ptr;
|
||||
char path[MAX_QPATH];
|
||||
char name[MAX_QPATH];
|
||||
|
||||
if( !musicfile[ 0 ] )
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
CG_Printf( "=== Loading %s ===\n", musicfile );
|
||||
|
||||
len = cgi.FS_ReadFile( musicfile, &buffer, qfalse );
|
||||
|
||||
if( len <= 0 ) {
|
||||
CG_Printf( "couldn't load %s. file not found.\n", musicfile );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ptr = buffer;
|
||||
token = COM_Parse( &ptr );
|
||||
while (*token) {
|
||||
if ( !Q_strncmp(token,"path",MAX_QPATH) )
|
||||
Q_strncpyz( path, COM_Parse(&ptr), MAX_QPATH );
|
||||
else if ( !Q_strncmp(token,"normal",MAX_QPATH) )
|
||||
Q_strncpyz( name, COM_Parse(&ptr), MAX_QPATH );
|
||||
token = COM_Parse( &ptr );
|
||||
}
|
||||
Q_snprintf( buffer, MAX_QPATH, "%s/%s", path, name );
|
||||
return buffer;
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// UI features
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "str.h"
|
||||
|
||||
void CG_MessageMode_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.UI_ToggleDMMessageConsole(300);
|
||||
}
|
||||
|
||||
void CG_MessageMode_All_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.UI_ToggleDMMessageConsole(100);
|
||||
}
|
||||
|
||||
void CG_MessageMode_Team_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.UI_ToggleDMMessageConsole(200);
|
||||
}
|
||||
|
||||
void CG_MessageMode_Private_f(void)
|
||||
{
|
||||
int clientNum;
|
||||
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
clientNum = atoi(cgi.Argv(1)) - 1;
|
||||
if (clientNum < 0 || clientNum >= MAX_CLIENTS)
|
||||
{
|
||||
cgi.Printf(HUD_MESSAGE_CHAT_WHITE "Message Error: %s is a bad client number\n", cgi.Argv(1));
|
||||
return;
|
||||
}
|
||||
|
||||
cgi.UI_ToggleDMMessageConsole(clientNum);
|
||||
}
|
||||
|
||||
void CG_MessageSingleAll_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cgi.Argc() > 1) {
|
||||
cgi.SendClientCommand(va("dmmessage 0 %s\n", cgi.Args()));
|
||||
}
|
||||
else {
|
||||
cgi.UI_ToggleDMMessageConsole(-100);
|
||||
}
|
||||
}
|
||||
|
||||
void CG_MessageSingleTeam_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cgi.Argc() > 1) {
|
||||
cgi.SendClientCommand(va("dmmessage -1 %s\n", cgi.Args()));
|
||||
}
|
||||
else {
|
||||
cgi.UI_ToggleDMMessageConsole(-200);
|
||||
}
|
||||
}
|
||||
|
||||
void CG_MessageSingleClient_f(void)
|
||||
{
|
||||
int clientNum;
|
||||
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
clientNum = atoi(cgi.Argv(1));
|
||||
if (clientNum < 1 || clientNum > MAX_CLIENTS)
|
||||
{
|
||||
cgi.Printf(HUD_MESSAGE_CHAT_WHITE "Message Error: %s is a bad client number\n", cgi.Argv(1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (cgi.Argc() > 2)
|
||||
{
|
||||
int i;
|
||||
str sString;
|
||||
|
||||
sString = "dmmessage ";
|
||||
sString += va("%i", clientNum);
|
||||
|
||||
// copy the rest
|
||||
for (i = 2; i < cgi.Argc(); i++) {
|
||||
sString += va("%s", cgi.Argv(i));
|
||||
}
|
||||
|
||||
sString += "\n";
|
||||
cgi.SendClientCommand(sString.c_str());
|
||||
}
|
||||
else {
|
||||
cgi.UI_ToggleDMMessageConsole(-clientNum);
|
||||
}
|
||||
}
|
||||
|
||||
void CG_InstaMessageMain_f(void)
|
||||
{
|
||||
if (!voiceChat->integer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.iInstaMessageMenu = -1;
|
||||
}
|
||||
|
||||
void CG_InstaMessageGroupA_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.iInstaMessageMenu = 1;
|
||||
}
|
||||
|
||||
void CG_InstaMessageGroupB_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.iInstaMessageMenu = 2;
|
||||
}
|
||||
|
||||
void CG_InstaMessageGroupC_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.iInstaMessageMenu = 3;
|
||||
}
|
||||
|
||||
void CG_InstaMessageGroupD_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.iInstaMessageMenu = 4;
|
||||
}
|
||||
|
||||
void CG_InstaMessageGroupE_f(void)
|
||||
{
|
||||
if (!cgs.gametype) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.iInstaMessageMenu = 5;
|
||||
}
|
||||
|
||||
void CG_HudPrint_f(void)
|
||||
{
|
||||
cgi.Printf("\x1%s", cgi.Argv(0));
|
||||
}
|
||||
|
||||
int CG_CheckCaptureKey(int key, qboolean down, unsigned int time)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// Vehicles
|
||||
|
||||
#include "cg_local.h"
|
||||
#include "cg_commands.h"
|
||||
|
||||
void CG_Vehicle(centity_t* cent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::SpawnTreads(Event* ev)
|
||||
{
|
||||
// stub
|
||||
}
|
||||
|
||||
void ClientGameCommandManager::TreadsOff(Event* ev)
|
||||
{
|
||||
// stub
|
||||
}
|
||||
+678
-729
File diff suppressed because it is too large.
Load diff
+580
-570
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
//
|
||||
// cg_weapons.c -- events and effects dealing with weapons
|
||||
#include "cg_local.h"
|
||||
|
||||
/*
|
||||
==========================
|
||||
CG_MachineGunEjectBrass
|
||||
==========================
|
||||
*/
|
||||
static void CG_MachineGunEjectBrass( centity_t *cent ) {
|
||||
/*localEntity_t *le;
|
||||
refEntity_t *re;
|
||||
vec3_t velocity, xvelocity;
|
||||
vec3_t offset, xoffset;
|
||||
float waterScale = 1.0f;
|
||||
vec3_t v[3];
|
||||
|
||||
if ( cg_brassTime.integer <= 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
le = CG_AllocLocalEntity();
|
||||
re = &le->refEntity;
|
||||
|
||||
velocity[0] = 0;
|
||||
velocity[1] = -50 + 40 * crandom();
|
||||
velocity[2] = 100 + 50 * crandom();
|
||||
|
||||
le->leType = LE_FRAGMENT;
|
||||
le->startTime = cg.time;
|
||||
le->endTime = le->startTime + cg_brassTime.integer + ( cg_brassTime.integer / 4 ) * random();
|
||||
|
||||
le->pos.trType = TR_GRAVITY;
|
||||
le->pos.trTime = cg.time - (rand()&15);
|
||||
|
||||
AnglesToAxis( cent->lerpAngles, v );
|
||||
|
||||
offset[0] = 8;
|
||||
offset[1] = -4;
|
||||
offset[2] = 24;
|
||||
|
||||
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
|
||||
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
|
||||
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
|
||||
VectorAdd( cent->lerpOrigin, xoffset, re->origin );
|
||||
|
||||
VectorCopy( re->origin, le->pos.trBase );
|
||||
|
||||
if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
|
||||
waterScale = 0.10f;
|
||||
}
|
||||
|
||||
xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
|
||||
xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
|
||||
xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
|
||||
VectorScale( xvelocity, waterScale, le->pos.trDelta );
|
||||
|
||||
AxisCopy( axisDefault, re->axis );
|
||||
re->hModel = cgs.media.machinegunBrassModel;
|
||||
|
||||
le->bounceFactor = 0.4 * waterScale;
|
||||
|
||||
le->angles.trType = TR_LINEAR;
|
||||
le->angles.trTime = cg.time;
|
||||
le->angles.trBase[0] = rand()&31;
|
||||
le->angles.trBase[1] = rand()&31;
|
||||
le->angles.trBase[2] = rand()&31;
|
||||
le->angles.trDelta[0] = 2;
|
||||
le->angles.trDelta[1] = 1;
|
||||
le->angles.trDelta[2] = 0;
|
||||
|
||||
le->leFlags = LEF_TUMBLE;
|
||||
le->leBounceSoundType = LEBS_BRASS;
|
||||
le->leMarkType = LEMT_NONE;*/
|
||||
}
|
||||
|
||||
/*
|
||||
==========================
|
||||
CG_ShotgunEjectBrass
|
||||
==========================
|
||||
*/
|
||||
static void CG_ShotgunEjectBrass( centity_t *cent ) {
|
||||
//localEntity_t *le;
|
||||
//refEntity_t *re;
|
||||
//vec3_t velocity, xvelocity;
|
||||
//vec3_t offset, xoffset;
|
||||
//vec3_t v[3];
|
||||
//int i;
|
||||
|
||||
//if ( cg_brassTime.integer <= 0 ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//for ( i = 0; i < 2; i++ ) {
|
||||
// float waterScale = 1.0f;
|
||||
|
||||
// le = CG_AllocLocalEntity();
|
||||
// re = &le->refEntity;
|
||||
|
||||
// velocity[0] = 60 + 60 * crandom();
|
||||
// if ( i == 0 ) {
|
||||
// velocity[1] = 40 + 10 * crandom();
|
||||
// } else {
|
||||
// velocity[1] = -40 + 10 * crandom();
|
||||
// }
|
||||
// velocity[2] = 100 + 50 * crandom();
|
||||
|
||||
// le->leType = LE_FRAGMENT;
|
||||
// le->startTime = cg.time;
|
||||
// le->endTime = le->startTime + cg_brassTime.integer*3 + cg_brassTime.integer * random();
|
||||
|
||||
// le->pos.trType = TR_GRAVITY;
|
||||
// le->pos.trTime = cg.time;
|
||||
|
||||
// AnglesToAxis( cent->lerpAngles, v );
|
||||
|
||||
// offset[0] = 8;
|
||||
// offset[1] = 0;
|
||||
// offset[2] = 24;
|
||||
|
||||
// xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
|
||||
// xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
|
||||
// xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
|
||||
// VectorAdd( cent->lerpOrigin, xoffset, re->origin );
|
||||
// VectorCopy( re->origin, le->pos.trBase );
|
||||
// if ( CG_PointContents( re->origin, -1 ) & CONTENTS_WATER ) {
|
||||
// waterScale = 0.10f;
|
||||
// }
|
||||
|
||||
// xvelocity[0] = velocity[0] * v[0][0] + velocity[1] * v[1][0] + velocity[2] * v[2][0];
|
||||
// xvelocity[1] = velocity[0] * v[0][1] + velocity[1] * v[1][1] + velocity[2] * v[2][1];
|
||||
// xvelocity[2] = velocity[0] * v[0][2] + velocity[1] * v[1][2] + velocity[2] * v[2][2];
|
||||
// VectorScale( xvelocity, waterScale, le->pos.trDelta );
|
||||
|
||||
// AxisCopy( axisDefault, re->axis );
|
||||
// re->hModel = cgs.media.shotgunBrassModel;
|
||||
// le->bounceFactor = 0.3f;
|
||||
|
||||
// le->angles.trType = TR_LINEAR;
|
||||
// le->angles.trTime = cg.time;
|
||||
// le->angles.trBase[0] = rand()&31;
|
||||
// le->angles.trBase[1] = rand()&31;
|
||||
// le->angles.trBase[2] = rand()&31;
|
||||
// le->angles.trDelta[0] = 1;
|
||||
// le->angles.trDelta[1] = 0.5;
|
||||
// le->angles.trDelta[2] = 0;
|
||||
|
||||
// le->leFlags = LEF_TUMBLE;
|
||||
// le->leBounceSoundType = LEBS_BRASS;
|
||||
// le->leMarkType = LEMT_NONE;
|
||||
//}
|
||||
}
|
||||
|
||||
|
||||
#ifdef MISSIONPACK
|
||||
/*
|
||||
==========================
|
||||
CG_NailgunEjectBrass
|
||||
==========================
|
||||
*/
|
||||
static void CG_NailgunEjectBrass( centity_t *cent ) {
|
||||
localEntity_t *smoke;
|
||||
vec3_t origin;
|
||||
vec3_t v[3];
|
||||
vec3_t offset;
|
||||
vec3_t xoffset;
|
||||
vec3_t up;
|
||||
|
||||
AnglesToAxis( cent->lerpAngles, v );
|
||||
|
||||
offset[0] = 0;
|
||||
offset[1] = -12;
|
||||
offset[2] = 24;
|
||||
|
||||
xoffset[0] = offset[0] * v[0][0] + offset[1] * v[1][0] + offset[2] * v[2][0];
|
||||
xoffset[1] = offset[0] * v[0][1] + offset[1] * v[1][1] + offset[2] * v[2][1];
|
||||
xoffset[2] = offset[0] * v[0][2] + offset[1] * v[1][2] + offset[2] * v[2][2];
|
||||
VectorAdd( cent->lerpOrigin, xoffset, origin );
|
||||
|
||||
VectorSet( up, 0, 0, 64 );
|
||||
|
||||
smoke = CG_SmokePuff( origin, up, 32, 1, 1, 1, 0.33f, 700, cg.time, 0, 0, cgs.media.smokePuffShader );
|
||||
// use the optimized local entity add
|
||||
smoke->leType = LE_SCALE_FADE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
========================================================================================
|
||||
|
||||
VIEW WEAPON
|
||||
|
||||
========================================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_CalculateWeaponPosition
|
||||
==============
|
||||
*/
|
||||
static void CG_CalculateWeaponPosition( vec3_t origin, vec3_t angles ) {
|
||||
float scale;
|
||||
int delta;
|
||||
float fracsin;
|
||||
|
||||
VectorCopy( cg.refdef.vieworg, origin );
|
||||
VectorCopy( cg.refdefViewAngles, angles );
|
||||
|
||||
// on odd legs, invert some angles
|
||||
if ( cg.bobcycle & 1 ) {
|
||||
scale = -cg.xyspeed;
|
||||
} else {
|
||||
scale = cg.xyspeed;
|
||||
}
|
||||
|
||||
// gun angles from bobbing
|
||||
angles[ROLL] += scale * cg.bobfracsin * 0.005;
|
||||
angles[YAW] += scale * cg.bobfracsin * 0.01;
|
||||
angles[PITCH] += cg.xyspeed * cg.bobfracsin * 0.005;
|
||||
|
||||
// drop the weapon when landing
|
||||
delta = cg.time - cg.landTime;
|
||||
if ( delta < LAND_DEFLECT_TIME ) {
|
||||
origin[2] += cg.landChange*0.25 * delta / LAND_DEFLECT_TIME;
|
||||
} else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) {
|
||||
origin[2] += cg.landChange*0.25 *
|
||||
(LAND_DEFLECT_TIME + LAND_RETURN_TIME - delta) / LAND_RETURN_TIME;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// drop the weapon when stair climbing
|
||||
delta = cg.time - cg.stepTime;
|
||||
if ( delta < STEP_TIME/2 ) {
|
||||
origin[2] -= cg.stepChange*0.25 * delta / (STEP_TIME/2);
|
||||
} else if ( delta < STEP_TIME ) {
|
||||
origin[2] -= cg.stepChange*0.25 * (STEP_TIME - delta) / (STEP_TIME/2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// idle drift
|
||||
scale = cg.xyspeed + 40;
|
||||
fracsin = sin( cg.time * 0.001 );
|
||||
angles[ROLL] += scale * fracsin * 0.01;
|
||||
angles[YAW] += scale * fracsin * 0.01;
|
||||
angles[PITCH] += scale * fracsin * 0.01;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
CG_AddViewWeapon
|
||||
|
||||
Add the weapon, and flash for the player's view
|
||||
==============
|
||||
*/
|
||||
void CG_AddViewWeapon( playerState_t *ps ) {
|
||||
//refEntity_t hand;
|
||||
//centity_t *cent;
|
||||
//clientInfo_t *ci;
|
||||
//float fovOffset;
|
||||
//vec3_t angles;
|
||||
|
||||
////if ( ps->stats[STAT_TEAM] == TEAM_SPECTATOR ) {
|
||||
//// return;
|
||||
////}
|
||||
|
||||
//if ( ps->pm_type == PM_INTERMISSION ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//// no gun if in third person view or a camera is active
|
||||
////if ( cg.renderingThirdPerson || cg.cameraMode) {
|
||||
//if ( cg.renderingThirdPerson ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
|
||||
////// allow the gun to be completely removed
|
||||
////if ( !cg_drawGun.integer ) {
|
||||
//// vec3_t origin;
|
||||
|
||||
//// if ( cg.predictedPlayerState.eFlags & EF_FIRING ) {
|
||||
//// // special hack for lightning gun...
|
||||
//// VectorCopy( cg.refdef.vieworg, origin );
|
||||
//// VectorMA( origin, -8, cg.refdef.viewaxis[2], origin );
|
||||
//// CG_LightningBolt( &cg_entities[ps->clientNum], origin );
|
||||
//// }
|
||||
//// return;
|
||||
////}
|
||||
|
||||
//// don't draw if testing a gun model
|
||||
//if ( cg.testGun ) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
//// drop gun lower at higher fov
|
||||
//if ( cg_fov.integer > 90 ) {
|
||||
// fovOffset = -0.2 * ( cg_fov.integer - 90 );
|
||||
//} else {
|
||||
// fovOffset = 0;
|
||||
//}
|
||||
|
||||
//cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum];
|
||||
|
||||
|
||||
//memset (&hand, 0, sizeof(hand));
|
||||
|
||||
//// set up gun position
|
||||
//CG_CalculateWeaponPosition( hand.origin, angles );
|
||||
|
||||
//VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[0], hand.origin );
|
||||
//VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin );
|
||||
//VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin );
|
||||
|
||||
//AnglesToAxis( angles, hand.axis );
|
||||
|
||||
//// map torso animations to weapon animations
|
||||
//if ( cg_gun_frame.integer ) {
|
||||
// // development tool
|
||||
// hand.frame = hand.oldframe = cg_gun_frame.integer;
|
||||
// hand.backlerp = 0;
|
||||
//} else {
|
||||
// // get clientinfo for animation map
|
||||
// ci = &cgs.clientinfo[ cent->currentState.clientNum ];
|
||||
// hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame );
|
||||
// hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame );
|
||||
// hand.backlerp = cent->pe.torso.backlerp;
|
||||
//}
|
||||
|
||||
//hand.hModel = weapon->handsModel;
|
||||
//hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT;
|
||||
|
||||
//// add everything onto the hand
|
||||
//CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity, ps->stats[STAT_TEAM] );
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
WEAPON SELECTION
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_NextWeapon_f
|
||||
===============
|
||||
*/
|
||||
void CG_NextWeapon_f( void ) {
|
||||
cg.iWeaponCommand = 12;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_PrevWeapon_f
|
||||
===============
|
||||
*/
|
||||
void CG_PrevWeapon_f( void ) {
|
||||
cg.iWeaponCommand = 11;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_PrevWeapon_f
|
||||
===============
|
||||
*/
|
||||
void CG_UseLastWeapon_f( void )
|
||||
{
|
||||
cg.iWeaponCommand = 13;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_HolsterWeapon_f
|
||||
===============
|
||||
*/
|
||||
void CG_HolsterWeapon_f( void )
|
||||
{
|
||||
cg.iWeaponCommand = 14;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_DropWeapon_f
|
||||
===============
|
||||
*/
|
||||
void CG_DropWeapon_f( void )
|
||||
{
|
||||
cg.iWeaponCommand = 15;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
CG_ToggleItem_f
|
||||
===============
|
||||
*/
|
||||
void CG_ToggleItem_f()
|
||||
{
|
||||
cg.iWeaponCommand = 7;
|
||||
cg.iWeaponCommandSend = 0;
|
||||
}
|
||||
|
||||
// su44: encode current weapon command for MoHAA
|
||||
int CG_WeaponCommandButtonBits() {
|
||||
int ret;
|
||||
if( !cg.iWeaponCommand )
|
||||
return 0;
|
||||
|
||||
ret = (cg.iWeaponCommand << 7) & 0x780;
|
||||
|
||||
cg.iWeaponCommandSend++;
|
||||
|
||||
if( cg.iWeaponCommandSend > 2 )
|
||||
cg.iWeaponCommand = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 2023 the OpenMoHAA team
|
||||
|
||||
This file is part of OpenMoHAA source code.
|
||||
|
||||
OpenMoHAA source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
OpenMoHAA source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenMoHAA source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// DESCRIPTION:
|
||||
// Renderer types
|
||||
|
||||
#ifndef __TR_TYPES_H
|
||||
#define __TR_TYPES_H
|
||||
|
||||
|
||||
#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces
|
||||
#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing
|
||||
#define MAX_POINTS 32
|
||||
#define MAX_SPRITES 1024
|
||||
|
||||
// refdef flags
|
||||
#define RDF_NOWORLDMODEL 1 // used for player configuration screen
|
||||
#define RDF_FULLBRIGHT 2 // fullbright intensity
|
||||
#define RDF_HYPERSPACE 4 // teleportation effect
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float pos[2];
|
||||
float size[2];
|
||||
} letterloc_t;
|
||||
|
||||
typedef struct fontheader_s
|
||||
{
|
||||
int indirection[256];
|
||||
letterloc_t locations[256];
|
||||
char name[64];
|
||||
float height;
|
||||
float aspectRatio;
|
||||
void *shader;
|
||||
int trhandle; // the last renderer handle this font used
|
||||
} fontheader_t;
|
||||
|
||||
typedef struct {
|
||||
vec3_t xyz;
|
||||
float st[2];
|
||||
byte modulate[4];
|
||||
} polyVert_t;
|
||||
|
||||
typedef struct poly_s {
|
||||
qhandle_t hShader;
|
||||
int numVerts;
|
||||
polyVert_t *verts;
|
||||
} poly_t;
|
||||
|
||||
typedef enum {
|
||||
RT_MODEL,
|
||||
RT_SPRITE,
|
||||
RT_BEAM,
|
||||
RT_PORTALSURFACE, // doesn't draw anything, just info for portals
|
||||
|
||||
RT_MAX_REF_ENTITY_TYPE
|
||||
} refEntityType_t;
|
||||
|
||||
typedef enum {
|
||||
lensflare = ( 1 << 0 ),
|
||||
viewlensflare = ( 1 << 1 ),
|
||||
additive = ( 1 << 2 )
|
||||
} dlighttype_t;
|
||||
|
||||
struct tikiFrame_s;
|
||||
struct dtiki_s;
|
||||
|
||||
typedef struct {
|
||||
refEntityType_t reType;
|
||||
|
||||
int renderfx;
|
||||
|
||||
qhandle_t hModel; // opaque type outside refresh
|
||||
qhandle_t hOldModel;
|
||||
|
||||
// most recent data
|
||||
vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN)
|
||||
int parentEntity;
|
||||
|
||||
vec3_t axis[3]; // rotation vectors
|
||||
qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale
|
||||
float origin[3]; // also used as MODEL_BEAM's "from"
|
||||
frameInfo_t frameInfo[MAX_FRAMEINFOS];
|
||||
float actionWeight;
|
||||
short wasframe;
|
||||
float scale; // scale of the thing
|
||||
|
||||
// previous data for frame interpolation
|
||||
float oldorigin[3]; // also used as MODEL_BEAM's "to"
|
||||
|
||||
// texturing
|
||||
int skinNum; // inline skin index
|
||||
qhandle_t customShader; // use one image for the entire thing
|
||||
|
||||
// misc
|
||||
byte shaderRGBA[4]; // colors used by colorSrc=vertex shaders
|
||||
float shaderTexCoord[2]; // texture coordinates used by tcMod=vertex modifiers
|
||||
float shaderTime; // subtracted from refdef time to control effect start times
|
||||
|
||||
int entityNumber; // the real entity number
|
||||
|
||||
byte surfaces[MAX_MODEL_SURFACES]; // the surface state of the entity
|
||||
float shader_data[ 2 ]; // data passed in from shader manipulation
|
||||
|
||||
int *bone_tag;
|
||||
vec4_t *bone_quat;
|
||||
|
||||
// renderer use only
|
||||
struct tikiFrame_s *of,
|
||||
*nf;
|
||||
struct dtiki_s *tiki;
|
||||
int bonestart;
|
||||
int morphstart;
|
||||
qboolean hasMorph;
|
||||
|
||||
// extra sprite information
|
||||
float radius;
|
||||
float rotation;
|
||||
|
||||
} refEntity_t;
|
||||
|
||||
#define MAX_RENDER_STRINGS 8
|
||||
#define MAX_RENDER_STRING_LENGTH 32
|
||||
|
||||
typedef struct {
|
||||
int x, y, width, height;
|
||||
float fov_x, fov_y;
|
||||
vec3_t vieworg;
|
||||
vec3_t viewaxis[3]; // transformation matrix
|
||||
|
||||
// time in milliseconds for shader effects and other time dependent rendering issues
|
||||
int time;
|
||||
|
||||
int rdflags; // RDF_NOWORLDMODEL, etc
|
||||
|
||||
// 1 bits will prevent the associated area from rendering at all
|
||||
byte areamask[MAX_MAP_AREA_BYTES];
|
||||
|
||||
// fog stuff
|
||||
float farplane_distance;
|
||||
vec3_t farplane_color;
|
||||
qboolean farplane_cull;
|
||||
|
||||
// sky portal stuff
|
||||
qboolean sky_portal;
|
||||
float sky_alpha;
|
||||
vec3_t sky_origin;
|
||||
vec3_t sky_axis[ 3 ];
|
||||
|
||||
} refdef_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
STEREO_CENTER,
|
||||
STEREO_LEFT,
|
||||
STEREO_RIGHT
|
||||
} stereoFrame_t;
|
||||
|
||||
|
||||
/*
|
||||
** glconfig_t
|
||||
**
|
||||
** Contains variables specific to the OpenGL configuration
|
||||
** being run right now. These are constant once the OpenGL
|
||||
** subsystem is initialized.
|
||||
*/
|
||||
typedef enum {
|
||||
TC_NONE,
|
||||
TC_S3TC, // this is for the GL_S3_s3tc extension.
|
||||
TC_S3TC_ARB // this is for the GL_EXT_texture_compression_s3tc extension.
|
||||
} textureCompression_t;
|
||||
|
||||
typedef enum {
|
||||
GLDRV_ICD, // driver is integrated with window system
|
||||
// WARNING: there are tests that check for
|
||||
// > GLDRV_ICD for minidriverness, so this
|
||||
// should always be the lowest value in this
|
||||
// enum set
|
||||
GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver
|
||||
GLDRV_VOODOO, // driver is a 3Dfx standalone driver
|
||||
// XreaL BEGIN
|
||||
GLDRV_DEFAULT, // old OpenGL system
|
||||
GLDRV_OPENGL3, // new driver system
|
||||
GLDRV_MESA // crap
|
||||
// XreaL END
|
||||
} glDriverType_t;
|
||||
|
||||
typedef enum {
|
||||
GLHW_GENERIC, // where everthing works the way it should
|
||||
GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is
|
||||
// the hardware type then there can NOT exist a secondary
|
||||
// display adapter
|
||||
GLHW_RIVA128, // where you can't interpolate alpha
|
||||
GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures
|
||||
GLHW_PERMEDIA2, // where you don't have src*dst
|
||||
// XreaL BEGIN
|
||||
GLHW_ATI, // where you don't have proper GLSL support
|
||||
GLHW_ATI_DX10, // ATI Radeon HD series DX10 hardware
|
||||
GLHW_NV_DX10 // Geforce 8/9 class DX10 hardware
|
||||
// XreaL END
|
||||
} glHardwareType_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char renderer_string[ MAX_STRING_CHARS ];
|
||||
char vendor_string[ MAX_STRING_CHARS ];
|
||||
char version_string[ MAX_STRING_CHARS ];
|
||||
char extensions_string[ MAX_STRING_CHARS * 2 ];
|
||||
|
||||
int maxTextureSize; // queried from GL
|
||||
int maxActiveTextures; // multitexture ability
|
||||
|
||||
int colorBits, depthBits, stencilBits;
|
||||
|
||||
glDriverType_t driverType;
|
||||
glHardwareType_t hardwareType;
|
||||
|
||||
qboolean deviceSupportsGamma;
|
||||
textureCompression_t textureCompression;
|
||||
qboolean textureEnvAddAvailable;
|
||||
|
||||
int vidWidth, vidHeight;
|
||||
// aspect is the screen's physical width / height, which may be different
|
||||
// than scrWidth / scrHeight if the pixels are non-square
|
||||
// normal screens should be 4/3, but wide aspect monitors may be 16/9
|
||||
float windowAspect;
|
||||
|
||||
int displayFrequency;
|
||||
|
||||
// synonymous with "does rendering consume the entire screen?", therefore
|
||||
// a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that
|
||||
// used CDS.
|
||||
qboolean isFullscreen;
|
||||
qboolean stereoEnabled;
|
||||
qboolean smpActive; // dual processor
|
||||
int registerCombinerAvailable;
|
||||
qboolean secondaryColorAvailable;
|
||||
qboolean VAR;
|
||||
qboolean fence;
|
||||
// ioq3
|
||||
int numTextureUnits;
|
||||
} glconfig_t;
|
||||
|
||||
#if !defined _WIN32
|
||||
|
||||
#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so.3.1"
|
||||
#define OPENGL_DRIVER_NAME "libGL.so"
|
||||
|
||||
#else
|
||||
|
||||
#define _3DFX_DRIVER_NAME "3dfxvgl"
|
||||
#define OPENGL_DRIVER_NAME "opengl32"
|
||||
|
||||
#endif // !defined _WIN32
|
||||
|
||||
|
||||
#endif // __TR_TYPES_H
|
||||
+110
-129
@@ -23,11 +23,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#include "client.h"
|
||||
#include "cl_ui.h"
|
||||
#include "../botlib/botlib.h"
|
||||
#include "tiki.h"
|
||||
#include <localization.h>
|
||||
|
||||
extern botlib_export_t *botlib_export;
|
||||
|
||||
extern qboolean loadCamera(const char *name);
|
||||
extern void startCamera(int time);
|
||||
extern qboolean getCameraInfo(int time, vec3_t *origin, vec3_t *angles);
|
||||
@@ -47,33 +45,30 @@ CL_GetGlconfig
|
||||
====================
|
||||
*/
|
||||
void CL_GetGlconfig( glconfig_t *glconfig ) {
|
||||
glconfig_ver19_t *pgl = ( glconfig_ver19_t * )glconfig;
|
||||
|
||||
strncpy( pgl->renderer_string, cls.glconfig.renderer_string, sizeof( pgl->renderer_string ) );
|
||||
strncpy( pgl->vendor_string, cls.glconfig.vendor_string, sizeof( pgl->vendor_string ) );
|
||||
strncpy( pgl->version_string, cls.glconfig.version_string, sizeof( pgl->version_string ) );
|
||||
strncpy( pgl->extensions_string, cls.glconfig.extensions_string, sizeof( pgl->extensions_string ) );
|
||||
pgl->maxTextureSize = cls.glconfig.maxTextureSize;
|
||||
pgl->numTextureUnits = cls.glconfig.numTextureUnits;
|
||||
pgl->colorBits = cls.glconfig.colorBits;
|
||||
pgl->depthBits = cls.glconfig.depthBits;
|
||||
pgl->stencilBits = cls.glconfig.stencilBits;
|
||||
pgl->driverType = cls.glconfig.driverType;
|
||||
pgl->hardwareType = cls.glconfig.hardwareType;
|
||||
pgl->deviceSupportsGamma = cls.glconfig.deviceSupportsGamma;
|
||||
pgl->textureCompression = cls.glconfig.textureCompression;
|
||||
pgl->textureEnvAddAvailable = cls.glconfig.textureEnvAddAvailable;
|
||||
pgl->vidWidth = cls.glconfig.vidWidth;
|
||||
pgl->vidHeight = cls.glconfig.vidHeight;
|
||||
pgl->windowAspect = cls.glconfig.windowAspect;
|
||||
pgl->displayFrequency = cls.glconfig.displayFrequency;
|
||||
pgl->isFullscreen = cls.glconfig.isFullscreen;
|
||||
pgl->stereoEnabled = cls.glconfig.stereoEnabled;
|
||||
pgl->smpActive = cls.glconfig.smpActive;
|
||||
pgl->registerCombinerAvailable = cls.glconfig.registerCombinerAvailable;
|
||||
pgl->secondaryColorAvailable = cls.glconfig.secondaryColorAvailable;
|
||||
pgl->VAR = cls.glconfig.VAR;
|
||||
pgl->fence = cls.glconfig.fence;
|
||||
strncpy( glconfig->renderer_string, cls.glconfig.renderer_string, sizeof( glconfig->renderer_string ) );
|
||||
strncpy( glconfig->vendor_string, cls.glconfig.vendor_string, sizeof( glconfig->vendor_string ) );
|
||||
strncpy( glconfig->version_string, cls.glconfig.version_string, sizeof( glconfig->version_string ) );
|
||||
strncpy( glconfig->extensions_string, cls.glconfig.extensions_string, sizeof( glconfig->extensions_string ) );
|
||||
glconfig->maxTextureSize = cls.glconfig.maxTextureSize;
|
||||
glconfig->colorBits = cls.glconfig.colorBits;
|
||||
glconfig->depthBits = cls.glconfig.depthBits;
|
||||
glconfig->stencilBits = cls.glconfig.stencilBits;
|
||||
glconfig->driverType = cls.glconfig.driverType;
|
||||
glconfig->hardwareType = cls.glconfig.hardwareType;
|
||||
glconfig->deviceSupportsGamma = cls.glconfig.deviceSupportsGamma;
|
||||
glconfig->textureCompression = cls.glconfig.textureCompression;
|
||||
glconfig->textureEnvAddAvailable = cls.glconfig.textureEnvAddAvailable;
|
||||
glconfig->vidWidth = cls.glconfig.vidWidth;
|
||||
glconfig->vidHeight = cls.glconfig.vidHeight;
|
||||
glconfig->windowAspect = cls.glconfig.windowAspect;
|
||||
glconfig->displayFrequency = cls.glconfig.displayFrequency;
|
||||
glconfig->isFullscreen = cls.glconfig.isFullscreen;
|
||||
glconfig->stereoEnabled = cls.glconfig.stereoEnabled;
|
||||
glconfig->smpActive = cls.glconfig.smpActive;
|
||||
glconfig->registerCombinerAvailable = cls.glconfig.registerCombinerAvailable;
|
||||
glconfig->secondaryColorAvailable = cls.glconfig.secondaryColorAvailable;
|
||||
glconfig->VAR = cls.glconfig.VAR;
|
||||
glconfig->fence = cls.glconfig.fence;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,6 +158,10 @@ CL_GetSnapshot
|
||||
qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
|
||||
clSnapshot_t *clSnap;
|
||||
int i, count;
|
||||
int pnum;
|
||||
int parents[MAX_ENTITIES_IN_SNAPSHOT];
|
||||
entityState_t *s1;
|
||||
int pcount = 0;
|
||||
|
||||
if ( snapshotNumber > cl.snap.messageNum ) {
|
||||
Com_Error( ERR_DROP, "CL_GetSnapshot: snapshotNumber > cl.snapshot.messageNum" );
|
||||
@@ -192,41 +191,81 @@ qboolean CL_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) {
|
||||
snapshot->serverTime = clSnap->serverTime;
|
||||
Com_Memcpy( snapshot->areamask, clSnap->areamask, sizeof( snapshot->areamask ) );
|
||||
snapshot->ps = clSnap->ps;
|
||||
|
||||
// wombat: sounds
|
||||
count = clSnap->number_of_sounds;
|
||||
if (snapshot->number_of_sounds > MAX_SERVER_SOUNDS) {
|
||||
Com_DPrintf("CL_GetSnapshot: truncated %i sounds to %i\n", count, MAX_SERVER_SOUNDS);
|
||||
count = MAX_SERVER_SOUNDS;
|
||||
}
|
||||
|
||||
snapshot->number_of_sounds = count;
|
||||
Com_Memcpy(snapshot->sounds, clSnap->sounds, sizeof(snapshot->sounds[0])* count);
|
||||
|
||||
count = clSnap->numEntities;
|
||||
if ( count > MAX_ENTITIES_IN_SNAPSHOT ) {
|
||||
Com_DPrintf( "CL_GetSnapshot: truncated %i visible entities to %i\n", count, MAX_ENTITIES_IN_SNAPSHOT );
|
||||
count = MAX_ENTITIES_IN_SNAPSHOT;
|
||||
}
|
||||
snapshot->numEntities = count;
|
||||
|
||||
snapshot->numEntities = 0;
|
||||
for ( i = 0 ; i < count ; i++ ) {
|
||||
snapshot->entities[i] =
|
||||
cl.parseEntities[ ( clSnap->parseEntitiesNum + i ) & (MAX_PARSE_ENTITIES-1) ];
|
||||
s1 = &cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)];
|
||||
pnum = s1->parent;
|
||||
|
||||
if (pnum == ENTITYNUM_NONE) {
|
||||
parents[s1->number] = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parents[pnum] == -2) {
|
||||
parents[s1->number] = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add it later
|
||||
parents[s1->number] = pnum;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
snapshot->entities[snapshot->numEntities++] = *s1;
|
||||
}
|
||||
|
||||
// wombat: sounds
|
||||
count = clSnap->number_of_sounds;
|
||||
if ( snapshot->number_of_sounds > MAX_SOUNDS_IN_SNAPSHOT ) {
|
||||
Com_DPrintf( "CL_GetSnapshot: truncated %i sounds to %i\n", count, MAX_SOUNDS_IN_SNAPSHOT );
|
||||
count = MAX_SOUNDS_IN_SNAPSHOT;
|
||||
for(pcount = 0; pcount < 8 && snapshot->numEntities != count; pcount++)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
s1 = &cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)];
|
||||
pnum = parents[s1->number];
|
||||
if (pnum >= 0 && parents[pnum] == -2) {
|
||||
snapshot->entities[snapshot->numEntities++] = *s1;
|
||||
}
|
||||
}
|
||||
}
|
||||
snapshot->number_of_sounds = count;
|
||||
Com_Memcpy( snapshot->sounds, clSnap->sounds, sizeof(snapshot->sounds[0])*count );
|
||||
|
||||
// FIXME: configstring changes and server commands!!!
|
||||
if (pcount >= 8)
|
||||
{
|
||||
for (i = count; i < snapshot->numEntities; i++)
|
||||
{
|
||||
s1 = &cl.parseEntities[(clSnap->parseEntitiesNum + i) & (MAX_PARSE_ENTITIES - 1)];
|
||||
if (parents[s1->number] >= 0) {
|
||||
Com_DPrintf(
|
||||
"CL_GetSnapshot: entity %d with parent %d and model '%s' at %.2f %.2f %.2f, could not find parent.\n",
|
||||
s1->number,
|
||||
s1->parent,
|
||||
CL_ConfigString(CS_MODELS + s1->modelindex),
|
||||
s1->origin[0],
|
||||
s1->origin[1],
|
||||
s1->origin[2]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_SetUserCmdValue
|
||||
=====================
|
||||
*/
|
||||
void CL_SetUserCmdValue( int userCmdValue, float sensitivityScale ) {
|
||||
cl.cgameUserCmdValue = userCmdValue;
|
||||
cl.cgameSensitivity = sensitivityScale;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CL_AddCgameCommand
|
||||
@@ -357,31 +396,6 @@ rescan:
|
||||
Com_Error( ERR_SERVERDISCONNECT, "Server disconnected\n" );
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "bcs0" ) ) {
|
||||
Com_sprintf( bigConfigString, BIG_INFO_STRING, "cs %s \"%s", Cmd_Argv(1), Cmd_Argv(2) );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "bcs1" ) ) {
|
||||
s = Cmd_Argv(2);
|
||||
if( strlen(bigConfigString) + strlen(s) >= BIG_INFO_STRING ) {
|
||||
Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
|
||||
}
|
||||
strcat( bigConfigString, s );
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "bcs2" ) ) {
|
||||
s = Cmd_Argv(2);
|
||||
if( strlen(bigConfigString) + strlen(s) + 1 >= BIG_INFO_STRING ) {
|
||||
Com_Error( ERR_DROP, "bcs exceeded BIG_INFO_STRING" );
|
||||
}
|
||||
strcat( bigConfigString, s );
|
||||
strcat( bigConfigString, "\"" );
|
||||
s = bigConfigString;
|
||||
goto rescan;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "cs" ) ) {
|
||||
CL_ConfigstringModified();
|
||||
// reparse the string, because CL_ConfigstringModified may have done another Cmd_TokenizeString()
|
||||
@@ -389,33 +403,6 @@ rescan:
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
if ( !strcmp( cmd, "map_restart" ) ) {
|
||||
// clear notify lines and outgoing commands before passing
|
||||
// the restart to the cgame
|
||||
Con_ClearNotify();
|
||||
Com_Memset( cl.cmds, 0, sizeof( cl.cmds ) );
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
// the clientLevelShot command is used during development
|
||||
// to generate 128*128 screenshots from the intermission
|
||||
// point of levels for the menu system to use
|
||||
// we pass it along to the cgame to make apropriate adjustments,
|
||||
// but we also clear the console and notify lines here
|
||||
if ( !strcmp( cmd, "clientLevelShot" ) ) {
|
||||
// don't do it if we aren't running the server locally,
|
||||
// otherwise malicious remote servers could overwrite
|
||||
// the existing thumbnails
|
||||
if ( !com_sv_running->integer ) {
|
||||
return qfalse;
|
||||
}
|
||||
// close the console
|
||||
Con_Close();
|
||||
// take a special screenshot next frame
|
||||
Cbuf_AddText( "wait ; wait ; wait ; wait ; screenshot levelshot\n" );
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
// we may want to put a "connect to other server" command here
|
||||
|
||||
// cgame can now act on the command
|
||||
@@ -441,7 +428,7 @@ void CL_CM_LoadMap( const char *mapname ) {
|
||||
CL_CG_Malloc
|
||||
====================
|
||||
*/
|
||||
void *CL_CG_Malloc( int size )
|
||||
void *CL_CG_Malloc(int size )
|
||||
{
|
||||
return Z_TagMalloc( size, TAG_CGAME );
|
||||
}
|
||||
@@ -483,7 +470,6 @@ CL_ShutdownCGame
|
||||
====================
|
||||
*/
|
||||
void CL_ShutdownCGame( void ) {
|
||||
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CGAME );
|
||||
cls.cgameStarted = qfalse;
|
||||
|
||||
if( cge )
|
||||
@@ -523,8 +509,8 @@ sfxHandle_t CL_RegisterSound( const char *sample, qboolean streamed ) {
|
||||
CL_StartLocalSound
|
||||
====================
|
||||
*/
|
||||
void CL_StartLocalSound( const char *sound_name ) {
|
||||
S_StartLocalSound( sound_name, qfalse );
|
||||
void CL_StartLocalSound(const char* soundName, qboolean forceLoad) {
|
||||
S_StartLocalSoundByName(soundName, qfalse );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -611,8 +597,8 @@ void CL_InitCGameDLL( clientGameImport_t *cgi, clientGameExport_t **cge ) {
|
||||
cgi->S_StartLocalSound = CL_StartLocalSound;
|
||||
cgi->S_StopSound = S_StopSound;
|
||||
cgi->S_AddLoopingSound = S_AddLoopingSound;
|
||||
cgi->S_ClearLoopingSounds = S_ClearLoopingSounds;
|
||||
cgi->S_Respatialize = S_Respatialize;
|
||||
cgi->S_ClearLoopingSounds = S_ClearLoopingSoundsNoParam;
|
||||
cgi->S_Respatialize = S_RespatializeOld;
|
||||
cgi->S_BeginRegistration = S_BeginRegistration;
|
||||
cgi->S_EndRegistration = S_EndRegistration;
|
||||
cgi->S_UpdateEntity = S_UpdateEntity;
|
||||
@@ -739,10 +725,11 @@ void CL_InitCGameDLL( clientGameImport_t *cgi, clientGameExport_t **cge ) {
|
||||
cgi->FS_CanonicalFilename = FS_CanonicalFilename;
|
||||
|
||||
cgi->fsDebug = fs_debug;
|
||||
cgi->hudDrawElements = cls.HudDrawElements;
|
||||
cgi->HudDrawElements = cls.HudDrawElements;
|
||||
cgi->anim = &cls.anim;
|
||||
cgi->stopWatch = &cls.stopwatch;
|
||||
cgi->pUnknownVar = NULL;
|
||||
// FIXME
|
||||
//cgi->pUnknownVar = NULL;
|
||||
|
||||
cls.cgameStarted = qtrue;
|
||||
}
|
||||
@@ -756,20 +743,20 @@ static void CL_ViewModelAnimation_Init() {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < MAX_FRAMEINFOS; i++ ) {
|
||||
cls.anim.vmFrameInfo[ i ].index = 0;
|
||||
cls.anim.vmFrameInfo[ i ].time = 0.0;
|
||||
cls.anim.vmFrameInfo[ i ].weight = 0.0;
|
||||
cls.anim.g_VMFrameInfo[ i ].index = 0;
|
||||
cls.anim.g_VMFrameInfo[ i ].time = 0.0;
|
||||
cls.anim.g_VMFrameInfo[ i ].weight = 0.0;
|
||||
}
|
||||
|
||||
VectorClear( cls.anim.currentVMPosOffset );
|
||||
cls.anim.lastVMAnim = -1;
|
||||
cls.anim.lastVMAnimChanged = -1;
|
||||
cls.anim.currentVMAnimSlot = 0;
|
||||
cls.anim.currentVMDuration = 9999;
|
||||
cls.anim.crossBlending = qfalse;
|
||||
cls.anim.lastEquippedWeaponStat = -1;
|
||||
cls.anim.lastActiveItem[ 0 ] = 0;
|
||||
cls.anim.lastAnimPrefixIndex = 0;
|
||||
VectorClear( cls.anim.g_vCurrentVMPosOffset );
|
||||
cls.anim.g_iLastVMAnim = -1;
|
||||
cls.anim.g_iLastVMAnimChanged = -1;
|
||||
cls.anim.g_iCurrentVMAnimSlot = 0;
|
||||
cls.anim.g_iCurrentVMDuration = 9999;
|
||||
cls.anim.g_bCrossblending = qfalse;
|
||||
cls.anim.g_iLastEquippedWeaponStat = -1;
|
||||
cls.anim.g_szLastActiveItem[ 0 ] = 0;
|
||||
cls.anim.g_iLastAnimPrefixIndex = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -833,9 +820,6 @@ void CL_InitCGame( void ) {
|
||||
|
||||
t1 = Sys_Milliseconds();
|
||||
|
||||
// put away the console
|
||||
Con_Close();
|
||||
|
||||
// find the current mapname
|
||||
info = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SERVERINFO ];
|
||||
mapname = Info_ValueForKey( info, "mapname" );
|
||||
@@ -874,9 +858,6 @@ void CL_InitCGame( void ) {
|
||||
|
||||
t2 = Sys_Milliseconds();
|
||||
|
||||
// clear anything that got printed
|
||||
Con_ClearNotify();
|
||||
|
||||
Com_Printf( "CL_InitCGame: %5.2f seconds\n", ( t2 - t1 ) / 1000.0 );
|
||||
}
|
||||
|
||||
|
||||
+5
-52
@@ -133,7 +133,7 @@ static cin_cache cinTable[MAX_VIDEO_HANDLES];
|
||||
static int currentHandle = -1;
|
||||
static int CL_handle = -1;
|
||||
|
||||
extern int s_soundtime; // sample PAIRS
|
||||
extern "C" int s_soundtime; // sample PAIRS
|
||||
|
||||
|
||||
void CIN_CloseAllVideos(void) {
|
||||
@@ -1142,17 +1142,17 @@ redump:
|
||||
case ZA_SOUND_MONO:
|
||||
if (!cinTable[currentHandle].silent) {
|
||||
ssize = RllDecodeMonoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
|
||||
S_RawSamples(0, ssize, 22050, 2, 1, (byte *)sbuf, 1.0f, -1);
|
||||
S_RawSamples(0, 22050, 2, 1, (byte *)sbuf, 1.0f);
|
||||
}
|
||||
break;
|
||||
case ZA_SOUND_STEREO:
|
||||
if (!cinTable[currentHandle].silent) {
|
||||
if (cinTable[currentHandle].numQuads == -1) {
|
||||
S_Update();
|
||||
s_rawend[0] = s_soundtime;
|
||||
s_rawend = s_soundtime;
|
||||
}
|
||||
ssize = RllDecodeStereoToStereo( framedata, sbuf, cinTable[currentHandle].RoQFrameSize, 0, (unsigned short)cinTable[currentHandle].roq_flags);
|
||||
S_RawSamples(0, ssize, 22050, 2, 2, (byte *)sbuf, 1.0f, -1);
|
||||
S_RawSamples(0, 22050, 2, 2, (byte *)sbuf, 1.0f);
|
||||
}
|
||||
break;
|
||||
case ROQ_QUAD_INFO:
|
||||
@@ -1467,11 +1467,9 @@ int CIN_PlayCinematic( const char *arg, int x, int y, int w, int h, int systemBi
|
||||
if (cinTable[currentHandle].alterGameState) {
|
||||
cls.state = CA_CINEMATIC;
|
||||
}
|
||||
|
||||
Con_Close();
|
||||
|
||||
if (!cinTable[currentHandle].silent) {
|
||||
s_rawend[0] = s_soundtime;
|
||||
s_rawend = s_soundtime;
|
||||
}
|
||||
|
||||
return currentHandle;
|
||||
@@ -1645,48 +1643,3 @@ void SCR_StopCinematic(void) {
|
||||
CL_handle = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void CIN_UploadCinematic(int handle) {
|
||||
if (handle >= 0 && handle < MAX_VIDEO_HANDLES) {
|
||||
if (!cinTable[handle].buf) {
|
||||
return;
|
||||
}
|
||||
if (cinTable[handle].playonwalls <= 0 && cinTable[handle].dirty) {
|
||||
if (cinTable[handle].playonwalls == 0) {
|
||||
cinTable[handle].playonwalls = -1;
|
||||
} else {
|
||||
if (cinTable[handle].playonwalls == -1) {
|
||||
cinTable[handle].playonwalls = -2;
|
||||
} else {
|
||||
cinTable[handle].dirty = qfalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resample the video if needed
|
||||
if (cinTable[handle].dirty && (cinTable[handle].CIN_WIDTH != cinTable[handle].drawX || cinTable[handle].CIN_HEIGHT != cinTable[handle].drawY)) {
|
||||
int *buf2;
|
||||
|
||||
buf2 = ( int * )Hunk_AllocateTempMemory( 256*256*4 );
|
||||
|
||||
CIN_ResampleCinematic(handle, buf2);
|
||||
|
||||
re.UploadCinematic( cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, 256, 256, (byte *)buf2, handle, qtrue);
|
||||
cinTable[handle].dirty = qfalse;
|
||||
Hunk_FreeTempMemory(buf2);
|
||||
} else {
|
||||
// Upload video at normal resolution
|
||||
re.UploadCinematic( cinTable[handle].CIN_WIDTH, cinTable[handle].CIN_HEIGHT, cinTable[handle].drawX, cinTable[handle].drawY,
|
||||
cinTable[handle].buf, handle, cinTable[handle].dirty);
|
||||
cinTable[handle].dirty = qfalse;
|
||||
}
|
||||
|
||||
if (cl_inGameVideo->integer == 0 && cinTable[handle].playonwalls == 1) {
|
||||
cinTable[handle].playonwalls--;
|
||||
}
|
||||
else if (cl_inGameVideo->integer != 0 && cinTable[handle].playonwalls != 1) {
|
||||
cinTable[handle].playonwalls = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,789 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// console.c
|
||||
|
||||
#include "client.h"
|
||||
|
||||
|
||||
int g_console_field_width = 78;
|
||||
int g_console_charWidth = SMALLCHAR_WIDTH, g_console_charHeight = SMALLCHAR_HEIGHT;
|
||||
|
||||
#define NUM_CON_TIMES 4
|
||||
|
||||
#define CON_TEXTSIZE 32768
|
||||
typedef struct {
|
||||
qboolean initialized;
|
||||
|
||||
short text[CON_TEXTSIZE];
|
||||
int current; // line where next message will be printed
|
||||
int x; // offset in current line for next print
|
||||
int display; // bottom of console displays this line
|
||||
|
||||
int linewidth; // characters across screen
|
||||
int totallines; // total lines in console scrollback
|
||||
|
||||
float xadjust; // for wide aspect screens
|
||||
|
||||
float displayFrac; // aproaches finalFrac at scr_conspeed
|
||||
float finalFrac; // 0.0 to 1.0 lines of console to display
|
||||
|
||||
int vislines; // in scanlines
|
||||
|
||||
int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
|
||||
// for transparent notify lines
|
||||
vec4_t color;
|
||||
} console_t;
|
||||
|
||||
extern console_t con;
|
||||
|
||||
console_t con;
|
||||
|
||||
cvar_t *con_conspeed;
|
||||
cvar_t *con_notifytime;
|
||||
cvar_t *con_drawnotify;
|
||||
|
||||
#define DEFAULT_CONSOLE_WIDTH 78
|
||||
|
||||
vec4_t console_color = {1.0, 1.0, 1.0, 1.0};
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ToggleConsole_f
|
||||
================
|
||||
*/
|
||||
void Con_ToggleConsole_f (void) {
|
||||
// Can't toggle the console when it's the only thing available
|
||||
if ( cls.state == CA_DISCONNECTED && Key_GetCatcher( ) == KEYCATCH_CONSOLE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Field_Clear( &g_consoleField );
|
||||
g_consoleField.widthInChars = g_console_field_width;
|
||||
|
||||
Con_ClearNotify ();
|
||||
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_CONSOLE );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode_f (void) {
|
||||
chat_playerNum = -1;
|
||||
chat_team = qfalse;
|
||||
Field_Clear( &chatField );
|
||||
chatField.widthInChars = 30;
|
||||
|
||||
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode2_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode2_f (void) {
|
||||
chat_playerNum = -1;
|
||||
chat_team = qtrue;
|
||||
Field_Clear( &chatField );
|
||||
chatField.widthInChars = 25;
|
||||
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode3_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode3_f (void) {
|
||||
chat_team = qfalse;
|
||||
Field_Clear( &chatField );
|
||||
chatField.widthInChars = 30;
|
||||
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_MessageMode4_f
|
||||
================
|
||||
*/
|
||||
void Con_MessageMode4_f (void) {
|
||||
chat_team = qfalse;
|
||||
Field_Clear( &chatField );
|
||||
chatField.widthInChars = 30;
|
||||
Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_MESSAGE );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Clear_f
|
||||
================
|
||||
*/
|
||||
void Con_Clear_f (void) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
|
||||
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
|
||||
}
|
||||
|
||||
Con_Bottom(); // go to end
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Dump_f
|
||||
|
||||
Save the console contents out to a file
|
||||
================
|
||||
*/
|
||||
void Con_Dump_f (void)
|
||||
{
|
||||
int l, x, i;
|
||||
short *line;
|
||||
fileHandle_t f;
|
||||
char buffer[1024];
|
||||
|
||||
if (Cmd_Argc() != 2)
|
||||
{
|
||||
Com_Printf ("usage: condump <filename>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf ("Dumped console text to %s.\n", Cmd_Argv(1) );
|
||||
|
||||
f = FS_FOpenFileWrite( Cmd_Argv( 1 ) );
|
||||
if (!f)
|
||||
{
|
||||
Com_Printf ("ERROR: couldn't open.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// skip empty lines
|
||||
for (l = con.current - con.totallines + 1 ; l <= con.current ; l++)
|
||||
{
|
||||
line = con.text + (l%con.totallines)*con.linewidth;
|
||||
for (x=0 ; x<con.linewidth ; x++)
|
||||
if ((line[x] & 0xff) != ' ')
|
||||
break;
|
||||
if (x != con.linewidth)
|
||||
break;
|
||||
}
|
||||
|
||||
// write the remaining lines
|
||||
buffer[con.linewidth] = 0;
|
||||
for ( ; l <= con.current ; l++)
|
||||
{
|
||||
line = con.text + (l%con.totallines)*con.linewidth;
|
||||
for(i=0; i<con.linewidth; i++)
|
||||
buffer[i] = line[i] & 0xff;
|
||||
for (x=con.linewidth-1 ; x>=0 ; x--)
|
||||
{
|
||||
if (buffer[x] == ' ')
|
||||
buffer[x] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
strcat( buffer, "\n" );
|
||||
FS_Write(buffer, strlen(buffer), f);
|
||||
}
|
||||
|
||||
FS_FCloseFile( f );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_ClearNotify
|
||||
================
|
||||
*/
|
||||
void Con_ClearNotify( void ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
|
||||
con.times[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_CheckResize
|
||||
|
||||
If the line width has changed, reformat the buffer.
|
||||
================
|
||||
*/
|
||||
void Con_CheckResize (void)
|
||||
{
|
||||
int i, j, width, oldwidth, oldtotallines, numlines, numchars;
|
||||
short tbuf[CON_TEXTSIZE];
|
||||
|
||||
width = (SCREEN_WIDTH / g_console_charWidth) - 2;
|
||||
|
||||
if (width == con.linewidth)
|
||||
return;
|
||||
|
||||
if (width < 1) // video hasn't been initialized yet
|
||||
{
|
||||
width = DEFAULT_CONSOLE_WIDTH;
|
||||
con.linewidth = width;
|
||||
con.totallines = CON_TEXTSIZE / con.linewidth;
|
||||
for(i=0; i<CON_TEXTSIZE; i++)
|
||||
|
||||
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
oldwidth = con.linewidth;
|
||||
con.linewidth = width;
|
||||
oldtotallines = con.totallines;
|
||||
con.totallines = CON_TEXTSIZE / con.linewidth;
|
||||
numlines = oldtotallines;
|
||||
|
||||
if (con.totallines < numlines)
|
||||
numlines = con.totallines;
|
||||
|
||||
numchars = oldwidth;
|
||||
|
||||
if (con.linewidth < numchars)
|
||||
numchars = con.linewidth;
|
||||
|
||||
Com_Memcpy (tbuf, con.text, CON_TEXTSIZE * sizeof(short));
|
||||
for(i=0; i<CON_TEXTSIZE; i++)
|
||||
|
||||
con.text[i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
|
||||
|
||||
|
||||
for (i=0 ; i<numlines ; i++)
|
||||
{
|
||||
for (j=0 ; j<numchars ; j++)
|
||||
{
|
||||
con.text[(con.totallines - 1 - i) * con.linewidth + j] =
|
||||
tbuf[((con.current - i + oldtotallines) %
|
||||
oldtotallines) * oldwidth + j];
|
||||
}
|
||||
}
|
||||
|
||||
Con_ClearNotify ();
|
||||
}
|
||||
|
||||
con.current = con.totallines - 1;
|
||||
con.display = con.current;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_Init
|
||||
================
|
||||
*/
|
||||
void Con_Init (void) {
|
||||
int i;
|
||||
|
||||
con_notifytime = Cvar_Get ("con_notifytime", "3", 0);
|
||||
con_conspeed = Cvar_Get ("scr_conspeed", "3", 0);
|
||||
con_drawnotify = Cvar_Get ("con_drawnotify", "0", 0);
|
||||
|
||||
Field_Clear( &g_consoleField );
|
||||
g_consoleField.widthInChars = g_console_field_width;
|
||||
for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
|
||||
Field_Clear( &historyEditLines[i] );
|
||||
historyEditLines[i].widthInChars = g_console_field_width;
|
||||
}
|
||||
CL_LoadConsoleHistory( );
|
||||
|
||||
Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
|
||||
Cmd_AddCommand ("messagemode", Con_MessageMode_f);
|
||||
Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
|
||||
Cmd_AddCommand ("messagemode3", Con_MessageMode3_f);
|
||||
Cmd_AddCommand ("messagemode4", Con_MessageMode4_f);
|
||||
Cmd_AddCommand ("clear", Con_Clear_f);
|
||||
Cmd_AddCommand ("condump", Con_Dump_f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Con_Linefeed
|
||||
===============
|
||||
*/
|
||||
void Con_Linefeed (qboolean skipnotify)
|
||||
{
|
||||
int i;
|
||||
|
||||
// mark time for transparent overlay
|
||||
if (con.current >= 0)
|
||||
{
|
||||
if (skipnotify)
|
||||
con.times[con.current % NUM_CON_TIMES] = 0;
|
||||
else
|
||||
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
|
||||
}
|
||||
|
||||
con.x = 0;
|
||||
if (con.display == con.current)
|
||||
con.display++;
|
||||
con.current++;
|
||||
for(i=0; i<con.linewidth; i++)
|
||||
con.text[(con.current%con.totallines)*con.linewidth+i] = (ColorIndex(COLOR_WHITE)<<8) | ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_ConsolePrint
|
||||
|
||||
Handles cursor positioning, line wrapping, etc
|
||||
All console printing must go through this in order to be logged to disk
|
||||
If no console is visible, the text will appear at the top of the game window
|
||||
================
|
||||
*/
|
||||
void CL_ConsolePrint( char *txt ) {
|
||||
int y;
|
||||
int c, l;
|
||||
int color;
|
||||
qboolean skipnotify = qfalse; // NERVE - SMF
|
||||
int prev; // NERVE - SMF
|
||||
|
||||
// TTimo - prefix for text that shows up in console but not in notify
|
||||
// backported from RTCW
|
||||
if ( !Q_strncmp( txt, "[skipnotify]", 12 ) ) {
|
||||
skipnotify = qtrue;
|
||||
txt += 12;
|
||||
}
|
||||
|
||||
// for some demos we don't want to ever show anything on the console
|
||||
if ( cl_noprint && cl_noprint->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!con.initialized) {
|
||||
con.color[0] =
|
||||
con.color[1] =
|
||||
con.color[2] =
|
||||
con.color[3] = 1.0f;
|
||||
con.linewidth = -1;
|
||||
Con_CheckResize ();
|
||||
con.initialized = qtrue;
|
||||
}
|
||||
|
||||
color = ColorIndex(COLOR_WHITE);
|
||||
|
||||
while ( (c = *txt) != 0 ) {
|
||||
if ( Q_IsColorString( txt ) ) {
|
||||
color = ColorIndex( *(txt+1) );
|
||||
txt += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// count word length
|
||||
for (l=0 ; l< con.linewidth ; l++) {
|
||||
if ( txt[l] <= ' ') {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// word wrap
|
||||
if (l != con.linewidth && (con.x + l >= con.linewidth) ) {
|
||||
Con_Linefeed(skipnotify);
|
||||
|
||||
}
|
||||
|
||||
txt++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
Con_Linefeed (skipnotify);
|
||||
break;
|
||||
case '\r':
|
||||
con.x = 0;
|
||||
break;
|
||||
default: // display character and advance
|
||||
y = con.current % con.totallines;
|
||||
con.text[y*con.linewidth+con.x] = (color << 8) | c;
|
||||
con.x++;
|
||||
if (con.x >= con.linewidth) {
|
||||
Con_Linefeed(skipnotify);
|
||||
con.x = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// mark time for transparent overlay
|
||||
if (con.current >= 0) {
|
||||
// NERVE - SMF
|
||||
if ( skipnotify ) {
|
||||
prev = con.current % NUM_CON_TIMES - 1;
|
||||
if ( prev < 0 )
|
||||
prev = NUM_CON_TIMES - 1;
|
||||
con.times[prev] = 0;
|
||||
}
|
||||
else
|
||||
// -NERVE - SMF
|
||||
con.times[con.current % NUM_CON_TIMES] = cls.realtime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
DRAWING
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DrawInput
|
||||
|
||||
Draw the editline after a ] prompt
|
||||
================
|
||||
*/
|
||||
void Con_DrawInput (void) {
|
||||
int y;
|
||||
|
||||
if ( cls.state != CA_DISCONNECTED && !(Key_GetCatcher( ) & KEYCATCH_CONSOLE ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
y = con.vislines - ( g_console_charHeight * 2 );
|
||||
|
||||
re.SetColor( con.color );
|
||||
|
||||
re.Text_PaintChar(&cls.consoleFont, con.xadjust + 1 * g_console_charWidth, y, 1.f, ']', 0);
|
||||
|
||||
Field_Draw(&cls.consoleFont, &g_consoleField, con.xadjust + 2 * g_console_charWidth, y,
|
||||
SCREEN_WIDTH - 3 * g_console_charWidth, qtrue, qtrue);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DrawNotify
|
||||
|
||||
Draws the last few lines of output transparently over the game top
|
||||
================
|
||||
*/
|
||||
void Con_DrawNotify (void)
|
||||
{
|
||||
int x, v;
|
||||
short *text;
|
||||
int i;
|
||||
int time;
|
||||
int skip;
|
||||
int currentColor;
|
||||
|
||||
currentColor = 7;
|
||||
re.SetColor( g_color_table[currentColor] );
|
||||
|
||||
v = 0;
|
||||
for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++)
|
||||
{
|
||||
if (i < 0)
|
||||
continue;
|
||||
time = con.times[i % NUM_CON_TIMES];
|
||||
if (time == 0)
|
||||
continue;
|
||||
time = cls.realtime - time;
|
||||
if (time > con_notifytime->value*1000)
|
||||
continue;
|
||||
text = con.text + (i % con.totallines)*con.linewidth;
|
||||
|
||||
if (Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (x = 0 ; x < con.linewidth ; x++) {
|
||||
if ( ( text[x] & 0xff ) == ' ' ) {
|
||||
continue;
|
||||
}
|
||||
if ( ( (text[x]>>8)&7 ) != currentColor ) {
|
||||
currentColor = (text[x]>>8)&7;
|
||||
re.SetColor( g_color_table[currentColor] );
|
||||
}
|
||||
re.Text_PaintChar(&cls.consoleFont, cl_conXOffset->integer + con.xadjust + (x+1)*g_console_charWidth, v, 1.f, text[x] & 0xff,0);
|
||||
}
|
||||
|
||||
v += g_console_charHeight;
|
||||
}
|
||||
|
||||
re.SetColor( NULL );
|
||||
|
||||
if (Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the chat line
|
||||
if ( Key_GetCatcher( ) & KEYCATCH_MESSAGE )
|
||||
{
|
||||
if (chat_team)
|
||||
{
|
||||
//SCR_DrawBigString (8, v, "say_team:", 1.0f, qfalse );
|
||||
re.Text_Paint(&cls.consoleFont, 8, v, 1.f, 1.f, "say_team:", 0, 0, qtrue,qfalse);
|
||||
skip = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
//SCR_DrawBigString (8, v, "say:", 1.0f, qfalse );
|
||||
re.Text_Paint(&cls.consoleFont, 8, v, 1.f, 1.f, "say:", 0, 0, qtrue,qfalse);
|
||||
skip = 5;
|
||||
}
|
||||
|
||||
// TODO: make this use facfont?
|
||||
Field_BigDraw(&cls.consoleFont, &chatField, skip * g_console_charWidth, v,
|
||||
SCREEN_WIDTH - ( skip + 1 ) * g_console_charWidth, qtrue, qtrue );
|
||||
|
||||
v += g_console_charHeight;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Con_DrawSolidConsole
|
||||
|
||||
Draws the console with the solid background
|
||||
================
|
||||
*/
|
||||
void Con_DrawSolidConsole( float frac ) {
|
||||
int i, x, y;
|
||||
int rows;
|
||||
short *text;
|
||||
int row;
|
||||
int lines;
|
||||
// qhandle_t conShader;
|
||||
int currentColor;
|
||||
vec4_t color;
|
||||
|
||||
lines = cls.glconfig.vidHeight * frac;
|
||||
if (lines <= 0)
|
||||
return;
|
||||
|
||||
if (lines > cls.glconfig.vidHeight )
|
||||
lines = cls.glconfig.vidHeight;
|
||||
|
||||
// on wide screens, we will center the text
|
||||
con.xadjust = 0;
|
||||
SCR_AdjustFrom640( &con.xadjust, NULL, NULL, NULL );
|
||||
|
||||
// draw the background
|
||||
y = frac * SCREEN_HEIGHT - 2;
|
||||
if ( y < 1 ) {
|
||||
y = 0;
|
||||
}
|
||||
else {
|
||||
//SCR_DrawPic( 0, 0, SCREEN_WIDTH, y, cls.consoleShader );
|
||||
// IneQuation: transparent MoHAA-style console
|
||||
color[0] = 0.1125f;
|
||||
color[1] = 0.15f;
|
||||
color[2] = 0.21f;
|
||||
color[3] = 0.85f;
|
||||
SCR_FillRect(0, 0, SCREEN_WIDTH, y, color);
|
||||
}
|
||||
|
||||
color[0] = 0.7f;
|
||||
color[1] = 0.6f;
|
||||
color[2] = 0.05f;
|
||||
color[3] = 1;
|
||||
SCR_FillRect( 0, y, SCREEN_WIDTH, 2, color );
|
||||
|
||||
|
||||
// draw the version number
|
||||
|
||||
/*color[0] = 0.7;
|
||||
color[1] = 0.6;
|
||||
color[2] = 0.05;
|
||||
color[3] = 1;*/
|
||||
re.SetColor( color/*g_color_table[ColorIndex(COLOR_RED)]*/ );
|
||||
|
||||
i = strlen( Q3_VERSION );
|
||||
|
||||
for (x=0 ; x<i ; x++) {
|
||||
|
||||
re.Text_PaintChar(&cls.consoleFont, cls.glconfig.vidWidth - ( i - x ) * g_console_charWidth,
|
||||
(lines-(g_console_charHeight+g_console_charHeight/2)), 1.f, Q3_VERSION[x], 0);
|
||||
|
||||
}
|
||||
|
||||
// draw the text
|
||||
con.vislines = lines;
|
||||
rows = (lines - g_console_charWidth) / g_console_charWidth; // rows of text to draw
|
||||
|
||||
y = lines - g_console_charHeight * 3;
|
||||
|
||||
// draw from the bottom up
|
||||
if (con.display != con.current)
|
||||
{
|
||||
// draw arrows to show the buffer is backscrolled
|
||||
re.SetColor( g_color_table[ColorIndex(COLOR_RED)] );
|
||||
for (x=0 ; x<con.linewidth ; x+=4)
|
||||
re.Text_PaintChar(&cls.consoleFont, con.xadjust + (x+1)*SMALLCHAR_WIDTH, y, 1.f, '^',0);
|
||||
y -= SMALLCHAR_HEIGHT;
|
||||
rows--;
|
||||
}
|
||||
|
||||
row = con.display;
|
||||
|
||||
if ( con.x == 0 ) {
|
||||
row--;
|
||||
}
|
||||
|
||||
currentColor = 7;
|
||||
re.SetColor( g_color_table[currentColor] );
|
||||
|
||||
for (i=0 ; i<rows ; i++, y -= g_console_charHeight, row--)
|
||||
{
|
||||
if (row < 0)
|
||||
break;
|
||||
if (con.current - row >= con.totallines) {
|
||||
// past scrollback wrap point
|
||||
continue;
|
||||
}
|
||||
|
||||
text = con.text + (row % con.totallines)*con.linewidth;
|
||||
|
||||
for (x=0 ; x<con.linewidth ; x++) {
|
||||
if ( ( text[x] & 0xff ) == ' ' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( (text[x]>>8)&7 ) != currentColor ) {
|
||||
currentColor = (text[x]>>8)&7;
|
||||
re.SetColor(g_color_table[currentColor]);
|
||||
}
|
||||
re.Text_PaintChar(&cls.consoleFont, con.xadjust + (x+1)*g_console_charWidth, y, 1.f, text[x] & 0xff,0);
|
||||
}
|
||||
}
|
||||
|
||||
// draw the input prompt, user text, and cursor if desired
|
||||
Con_DrawInput ();
|
||||
|
||||
re.SetColor( NULL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Con_DrawConsole
|
||||
==================
|
||||
*/
|
||||
void Con_DrawConsole( void ) {
|
||||
// check for console width changes from a vid mode change
|
||||
Con_CheckResize ();
|
||||
|
||||
// if disconnected, render console full screen
|
||||
if ( cls.state == CA_DISCONNECTED ) {
|
||||
if ( !( Key_GetCatcher( ) & (KEYCATCH_UI | KEYCATCH_CGAME)) ) {
|
||||
Con_DrawSolidConsole( 1.0 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( con.displayFrac ) {
|
||||
Con_DrawSolidConsole( con.displayFrac );
|
||||
} else {
|
||||
// draw notify lines
|
||||
if ( cls.state == CA_ACTIVE && con_drawnotify->integer ) {
|
||||
Con_DrawNotify ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//================================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
Con_RunConsole
|
||||
|
||||
Scroll it up or down
|
||||
==================
|
||||
*/
|
||||
void Con_RunConsole (void) {
|
||||
// decide on the destination height of the console
|
||||
if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE )
|
||||
con.finalFrac = 0.5; // half screen
|
||||
else
|
||||
con.finalFrac = 0; // none visible
|
||||
|
||||
// scroll towards the destination height
|
||||
if (con.finalFrac < con.displayFrac)
|
||||
{
|
||||
con.displayFrac -= con_conspeed->value*cls.realFrametime*0.001;
|
||||
if (con.finalFrac > con.displayFrac)
|
||||
con.displayFrac = con.finalFrac;
|
||||
|
||||
}
|
||||
else if (con.finalFrac > con.displayFrac)
|
||||
{
|
||||
con.displayFrac += con_conspeed->value*cls.realFrametime*0.001;
|
||||
if (con.finalFrac < con.displayFrac)
|
||||
con.displayFrac = con.finalFrac;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Con_PageUp( void ) {
|
||||
con.display -= 2;
|
||||
if ( con.current - con.display >= con.totallines ) {
|
||||
con.display = con.current - con.totallines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Con_PageDown( void ) {
|
||||
con.display += 2;
|
||||
if (con.display > con.current) {
|
||||
con.display = con.current;
|
||||
}
|
||||
}
|
||||
|
||||
void Con_Top( void ) {
|
||||
con.display = con.totallines;
|
||||
if ( con.current - con.display >= con.totallines ) {
|
||||
con.display = con.current - con.totallines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Con_Bottom( void ) {
|
||||
con.display = con.current;
|
||||
}
|
||||
|
||||
|
||||
void Con_Close( void ) {
|
||||
if ( !com_cl_running->integer ) {
|
||||
return;
|
||||
}
|
||||
Field_Clear( &g_consoleField );
|
||||
Con_ClearNotify ();
|
||||
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_CONSOLE );
|
||||
con.finalFrac = 0; // none visible
|
||||
con.displayFrac = 0;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
// cl_consolecmds.cpp : New client console commands.
|
||||
|
||||
#include "client.h"
|
||||
#include "glb_local.h"
|
||||
#include "listener.h"
|
||||
|
||||
/*
|
||||
===============
|
||||
|
||||
+60
-27
@@ -566,7 +566,7 @@ CL_CmdButtons
|
||||
*/
|
||||
void CL_CmdButtons( usercmd_t *cmd ) {
|
||||
int i;
|
||||
|
||||
|
||||
//
|
||||
// figure button bits
|
||||
// send a button bit even if the key was pressed and released in
|
||||
@@ -579,18 +579,28 @@ void CL_CmdButtons( usercmd_t *cmd ) {
|
||||
in_buttons[i].wasPressed = qfalse;
|
||||
}
|
||||
|
||||
// if ( Key_GetCatcher( ) ) {
|
||||
// cmd->buttons |= BUTTON_TALK; // su44: is there a TALK button in MoHAA?
|
||||
// }
|
||||
if (UI_MenuActive() || UI_ConsoleIsOpen()) {
|
||||
cmd->buttons |= BUTTON_TALK;
|
||||
}
|
||||
|
||||
if (in_speed.active == !cl_run->integer) {
|
||||
cmd->buttons |= BUTTON_RUN;
|
||||
}
|
||||
|
||||
if (cge) {
|
||||
// send weapon commands from cg
|
||||
cmd->buttons |= cge->CG_WeaponCommandButtonBits();
|
||||
}
|
||||
|
||||
// allow the game to know if any key at all is
|
||||
// currently pressed, even if it isn't bound to anything
|
||||
if ( anykeydown && Key_GetCatcher( ) == 0 ) {
|
||||
cmd->buttons |= BUTTON_ANY;
|
||||
if ( anykeydown && Key_GetCatcher() == 0) {
|
||||
cmd->buttons |= BUTTON_ANY2;
|
||||
}
|
||||
|
||||
// su44: add weapon command bits
|
||||
cmd->buttons |= cl.cgameUserCmdValue;
|
||||
if (anykeydown) {
|
||||
cmd->buttons |= BUTTON_ANY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -696,27 +706,43 @@ void CL_CreateNewCommands( void ) {
|
||||
cmd = &cl.cmds[cmdNum];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_GetEyeInfo
|
||||
CL_EyeInfo
|
||||
|
||||
Create a new usereyes_t structure for this frame
|
||||
Gather eyes data from client game module
|
||||
=================
|
||||
*/
|
||||
void CL_GetEyeInfo(usereyes_t *info) {
|
||||
info->angles[0] = cl.eyeAngles[0];
|
||||
info->angles[1] = cl.eyeAngles[1];
|
||||
VectorCopy(cl.eyeOrigin,info->ofs);
|
||||
}
|
||||
/*
|
||||
=================
|
||||
CL_SetEyeInfo
|
||||
=================
|
||||
*/
|
||||
void CL_SetEyeInfo(vec3_t origin, vec3_t angles) {
|
||||
VectorCopy(angles,cl.eyeAngles);
|
||||
VectorCopy(origin,cl.eyeOrigin);
|
||||
void CL_EyeInfo(usereyes_t* info) {
|
||||
int i;
|
||||
vec3_t vAngles, vOfs;
|
||||
|
||||
if (cge) {
|
||||
// copy the eye offset
|
||||
cge->CG_EyeOffset(&vOfs);
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
vOfs[i] += 0.5;
|
||||
if (vOfs[i] < -127.0) {
|
||||
vOfs[i] = -127.0;
|
||||
} else if (vOfs[i] > 128.0) {
|
||||
vOfs[i] = 128.0;
|
||||
}
|
||||
|
||||
info->ofs[i] = vOfs[i];
|
||||
}
|
||||
|
||||
cge->CG_EyeAngles(&vAngles);
|
||||
info->angles[0] = vAngles[0];
|
||||
info->angles[1] = vAngles[1];
|
||||
} else {
|
||||
// clear the eye offset
|
||||
for (i = 0; i < 3; i++) {
|
||||
info->ofs[i] = 0;
|
||||
}
|
||||
|
||||
info->angles[0] = info->angles[1] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -839,7 +865,7 @@ void CL_WritePacket( void ) {
|
||||
for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
|
||||
MSG_WriteByte( &buf, clc_clientCommand );
|
||||
MSG_WriteLong( &buf, i );
|
||||
MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
|
||||
MSG_WriteScrambledString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
|
||||
}
|
||||
|
||||
// we want to send all the usercmds that were generated in the last
|
||||
@@ -872,7 +898,7 @@ void CL_WritePacket( void ) {
|
||||
// write the command count
|
||||
MSG_WriteByte( &buf, count );
|
||||
|
||||
CL_GetEyeInfo( &eyeInfo );
|
||||
CL_EyeInfo( &eyeInfo );
|
||||
MSG_WriteDeltaEyeInfo( &buf, &cl.outPackets[ oldPacketNum ].p_eyeinfo, &eyeInfo );
|
||||
// use the checksum feed in the key
|
||||
key = clc.checksumFeed;
|
||||
@@ -889,6 +915,13 @@ void CL_WritePacket( void ) {
|
||||
oldcmd = cmd;
|
||||
}
|
||||
}
|
||||
else {
|
||||
eyeInfo.ofs[0] = 0;
|
||||
eyeInfo.ofs[1] = 0;
|
||||
eyeInfo.ofs[2] = 0;
|
||||
eyeInfo.angles[0] = cl.viewangles[0];
|
||||
eyeInfo.angles[1] = cl.viewangles[1];
|
||||
}
|
||||
|
||||
//
|
||||
// deliver the message
|
||||
@@ -901,7 +934,7 @@ void CL_WritePacket( void ) {
|
||||
clc.lastPacketSentTime = cls.realtime;
|
||||
|
||||
if ( cl_showSend->integer ) {
|
||||
Com_Printf( "%i ", buf.cursize );
|
||||
Com_Printf( "%zu ", buf.cursize );
|
||||
}
|
||||
|
||||
CL_Netchan_Transmit (&clc.netchan, &buf);
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
void setType( inventory_type_t *t );
|
||||
void Create( float x, float y, FakkInventory *parent );
|
||||
bool HasAnyItems( void );
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void OnLeftMouseDown( Event *ev );
|
||||
void OnRightMouseDown( Event *ev );
|
||||
void OnLeftMouseUp( Event *ev );
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
~FakkInventory();
|
||||
|
||||
void setInventory( inventory_t *i );
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void OnMouseMove( Event *ev );
|
||||
void OnMouseLeave( Event *ev );
|
||||
void OnMouseEnter( Event *ev );
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
void NextItem( void );
|
||||
void PrevItem( void );
|
||||
qboolean isDying( void );
|
||||
qboolean KeyEvent( int key, unsigned int time );
|
||||
qboolean KeyEvent( int key, unsigned int time ) override;
|
||||
void PlaySound( invsound_t type );
|
||||
void Timeout( Event *ev );
|
||||
void ChangeItem( int sign );
|
||||
|
||||
+52
-730
@@ -29,14 +29,10 @@ key up events are sent even if in console mode
|
||||
|
||||
*/
|
||||
|
||||
field_t historyEditLines[COMMAND_HISTORY];
|
||||
|
||||
int nextHistoryLine; // the last line in the history buffer, not masked
|
||||
int historyLine; // the line being displayed from history buffer
|
||||
// will be <= nextHistoryLine
|
||||
|
||||
field_t g_consoleField;
|
||||
field_t chatField;
|
||||
qboolean chat_team;
|
||||
|
||||
int chat_playerNum;
|
||||
@@ -45,18 +41,18 @@ int chat_playerNum;
|
||||
qboolean key_overstrikeMode;
|
||||
|
||||
int anykeydown;
|
||||
qkey_t keys[MAX_KEYS];
|
||||
qkey_t altkeys[MAX_KEYS];
|
||||
qkey_t ctrlkeys[MAX_KEYS];
|
||||
qkey_t keys[K_LASTKEY];
|
||||
qkey_t altkeys[K_LASTKEY];
|
||||
qkey_t ctrlkeys[K_LASTKEY];
|
||||
|
||||
qboolean menubound[MAX_KEYS];
|
||||
qboolean menubound[K_LASTKEY];
|
||||
|
||||
qboolean alt_down;
|
||||
qboolean ctrl_down;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
int keynum;
|
||||
const char *name;
|
||||
int keynum;
|
||||
} keyname_t;
|
||||
|
||||
|
||||
@@ -73,15 +69,16 @@ keyname_t keynames[] =
|
||||
{"LEFTARROW", K_LEFTARROW},
|
||||
{"RIGHTARROW", K_RIGHTARROW},
|
||||
|
||||
{"ALT", K_ALT},
|
||||
{"LALT", K_LALT},
|
||||
{"ALT", K_LALT},
|
||||
// wombat: mohaa knows LCTRL and RCTRL, LSHIFT, RSHIFT
|
||||
{"CTRL", K_CTRL},
|
||||
{"LCTRL", K_CTRL},
|
||||
{"RCTRL", K_CTRL},
|
||||
|
||||
{"SHIFT", K_SHIFT},
|
||||
{"LSHIFT", K_SHIFT},
|
||||
{"RSHIFT", K_SHIFT},
|
||||
{"LCTRL", K_LCTRL},
|
||||
{"CTRL", K_LCTRL},
|
||||
{"LSHIFT", K_LSHIFT},
|
||||
{"SHIFT", K_LSHIFT},
|
||||
{"RALT", K_RALT},
|
||||
{"RCTRL", K_RCTRL},
|
||||
{"RSHIFT", K_RSHIFT},
|
||||
|
||||
{"COMMAND", K_COMMAND},
|
||||
|
||||
@@ -193,539 +190,13 @@ keyname_t keynames[] =
|
||||
|
||||
{"SEMICOLON", ';'}, // because a raw semicolon seperates commands
|
||||
|
||||
{"WORLD_0", K_WORLD_0},
|
||||
{"WORLD_1", K_WORLD_1},
|
||||
{"WORLD_2", K_WORLD_2},
|
||||
{"WORLD_3", K_WORLD_3},
|
||||
{"WORLD_4", K_WORLD_4},
|
||||
{"WORLD_5", K_WORLD_5},
|
||||
{"WORLD_6", K_WORLD_6},
|
||||
{"WORLD_7", K_WORLD_7},
|
||||
{"WORLD_8", K_WORLD_8},
|
||||
{"WORLD_9", K_WORLD_9},
|
||||
{"WORLD_10", K_WORLD_10},
|
||||
{"WORLD_11", K_WORLD_11},
|
||||
{"WORLD_12", K_WORLD_12},
|
||||
{"WORLD_13", K_WORLD_13},
|
||||
{"WORLD_14", K_WORLD_14},
|
||||
{"WORLD_15", K_WORLD_15},
|
||||
{"WORLD_16", K_WORLD_16},
|
||||
{"WORLD_17", K_WORLD_17},
|
||||
{"WORLD_18", K_WORLD_18},
|
||||
{"WORLD_19", K_WORLD_19},
|
||||
{"WORLD_20", K_WORLD_20},
|
||||
{"WORLD_21", K_WORLD_21},
|
||||
{"WORLD_22", K_WORLD_22},
|
||||
{"WORLD_23", K_WORLD_23},
|
||||
{"WORLD_24", K_WORLD_24},
|
||||
{"WORLD_25", K_WORLD_25},
|
||||
{"WORLD_26", K_WORLD_26},
|
||||
{"WORLD_27", K_WORLD_27},
|
||||
{"WORLD_28", K_WORLD_28},
|
||||
{"WORLD_29", K_WORLD_29},
|
||||
{"WORLD_30", K_WORLD_30},
|
||||
{"WORLD_31", K_WORLD_31},
|
||||
{"WORLD_32", K_WORLD_32},
|
||||
{"WORLD_33", K_WORLD_33},
|
||||
{"WORLD_34", K_WORLD_34},
|
||||
{"WORLD_35", K_WORLD_35},
|
||||
{"WORLD_36", K_WORLD_36},
|
||||
{"WORLD_37", K_WORLD_37},
|
||||
{"WORLD_38", K_WORLD_38},
|
||||
{"WORLD_39", K_WORLD_39},
|
||||
{"WORLD_40", K_WORLD_40},
|
||||
{"WORLD_41", K_WORLD_41},
|
||||
{"WORLD_42", K_WORLD_42},
|
||||
{"WORLD_43", K_WORLD_43},
|
||||
{"WORLD_44", K_WORLD_44},
|
||||
{"WORLD_45", K_WORLD_45},
|
||||
{"WORLD_46", K_WORLD_46},
|
||||
{"WORLD_47", K_WORLD_47},
|
||||
{"WORLD_48", K_WORLD_48},
|
||||
{"WORLD_49", K_WORLD_49},
|
||||
{"WORLD_50", K_WORLD_50},
|
||||
{"WORLD_51", K_WORLD_51},
|
||||
{"WORLD_52", K_WORLD_52},
|
||||
{"WORLD_53", K_WORLD_53},
|
||||
{"WORLD_54", K_WORLD_54},
|
||||
{"WORLD_55", K_WORLD_55},
|
||||
{"WORLD_56", K_WORLD_56},
|
||||
{"WORLD_57", K_WORLD_57},
|
||||
{"WORLD_58", K_WORLD_58},
|
||||
{"WORLD_59", K_WORLD_59},
|
||||
{"WORLD_60", K_WORLD_60},
|
||||
{"WORLD_61", K_WORLD_61},
|
||||
{"WORLD_62", K_WORLD_62},
|
||||
{"WORLD_63", K_WORLD_63},
|
||||
{"WORLD_64", K_WORLD_64},
|
||||
{"WORLD_65", K_WORLD_65},
|
||||
{"WORLD_66", K_WORLD_66},
|
||||
{"WORLD_67", K_WORLD_67},
|
||||
{"WORLD_68", K_WORLD_68},
|
||||
{"WORLD_69", K_WORLD_69},
|
||||
{"WORLD_70", K_WORLD_70},
|
||||
{"WORLD_71", K_WORLD_71},
|
||||
{"WORLD_72", K_WORLD_72},
|
||||
{"WORLD_73", K_WORLD_73},
|
||||
{"WORLD_74", K_WORLD_74},
|
||||
{"WORLD_75", K_WORLD_75},
|
||||
{"WORLD_76", K_WORLD_76},
|
||||
{"WORLD_77", K_WORLD_77},
|
||||
{"WORLD_78", K_WORLD_78},
|
||||
{"WORLD_79", K_WORLD_79},
|
||||
{"WORLD_80", K_WORLD_80},
|
||||
{"WORLD_81", K_WORLD_81},
|
||||
{"WORLD_82", K_WORLD_82},
|
||||
{"WORLD_83", K_WORLD_83},
|
||||
{"WORLD_84", K_WORLD_84},
|
||||
{"WORLD_85", K_WORLD_85},
|
||||
{"WORLD_86", K_WORLD_86},
|
||||
{"WORLD_87", K_WORLD_87},
|
||||
{"WORLD_88", K_WORLD_88},
|
||||
{"WORLD_89", K_WORLD_89},
|
||||
{"WORLD_90", K_WORLD_90},
|
||||
{"WORLD_91", K_WORLD_91},
|
||||
{"WORLD_92", K_WORLD_92},
|
||||
{"WORLD_93", K_WORLD_93},
|
||||
{"WORLD_94", K_WORLD_94},
|
||||
{"WORLD_95", K_WORLD_95},
|
||||
|
||||
{"WINDOWS", K_SUPER},
|
||||
{"COMPOSE", K_COMPOSE},
|
||||
{"MODE", K_MODE},
|
||||
{"HELP", K_HELP},
|
||||
{"PRINT", K_PRINT},
|
||||
{"SYSREQ", K_SYSREQ},
|
||||
{"SCROLLOCK", K_SCROLLOCK },
|
||||
{"BREAK", K_BREAK},
|
||||
{"MENU", K_MENU},
|
||||
{"POWER", K_POWER},
|
||||
{"EURO", K_EURO},
|
||||
{"UNDO", K_UNDO},
|
||||
{ "LWINKEY", K_LWINKEY },
|
||||
{ "RWINKEY", K_RWINKEY },
|
||||
{ "MENUKEY", K_MENUKEY },
|
||||
|
||||
{NULL,0}
|
||||
};
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
EDIT FIELDS
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
Field_Draw
|
||||
|
||||
Handles horizontal scrolling and cursor blinking
|
||||
x, y, and width are in pixels
|
||||
===================
|
||||
*/
|
||||
void Field_VariableSizeDraw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor,
|
||||
qboolean noColorEscape ) {
|
||||
int len;
|
||||
int drawLen;
|
||||
int prestep;
|
||||
int cursorChar;
|
||||
char str[MAX_STRING_CHARS];
|
||||
// int i;
|
||||
|
||||
drawLen = edit->widthInChars - 1; // - 1 so there is always a space for the cursor
|
||||
len = strlen( edit->buffer );
|
||||
|
||||
// guarantee that cursor will be visible
|
||||
if ( len <= drawLen ) {
|
||||
prestep = 0;
|
||||
} else {
|
||||
if ( edit->scroll + drawLen > len ) {
|
||||
edit->scroll = len - drawLen;
|
||||
if ( edit->scroll < 0 ) {
|
||||
edit->scroll = 0;
|
||||
}
|
||||
}
|
||||
prestep = edit->scroll;
|
||||
}
|
||||
|
||||
if ( prestep + drawLen > len ) {
|
||||
drawLen = len - prestep;
|
||||
}
|
||||
|
||||
// extract <drawLen> characters from the field at <prestep>
|
||||
if ( drawLen >= MAX_STRING_CHARS ) {
|
||||
Com_Error( ERR_DROP, "drawLen >= MAX_STRING_CHARS" );
|
||||
}
|
||||
|
||||
Com_Memcpy( str, edit->buffer + prestep, drawLen );
|
||||
str[ drawLen ] = 0;
|
||||
|
||||
// draw it
|
||||
/*if ( size == SMALLCHAR_WIDTH ) {
|
||||
float color[4];
|
||||
|
||||
color[0] = color[1] = color[2] = color[3] = 1.0;
|
||||
SCR_DrawSmallStringExt( x, y, str, color, qfalse, noColorEscape );
|
||||
} else {
|
||||
// draw big string with drop shadow
|
||||
SCR_DrawBigString( x, y, str, 1.0, noColorEscape );
|
||||
}*/
|
||||
re.Text_Paint(font, x, y, 1.f, 1.f, str, 0, 0, !noColorEscape,0);
|
||||
|
||||
// draw the cursor
|
||||
if ( showCursor ) {
|
||||
if ( (int)( cls.realtime >> 8 ) & 1 ) {
|
||||
return; // off blink
|
||||
}
|
||||
|
||||
if ( key_overstrikeMode ) {
|
||||
cursorChar = '|';
|
||||
} else {
|
||||
cursorChar = '_';
|
||||
}
|
||||
|
||||
// i = drawLen - strlen( str );
|
||||
str[edit->cursor] = 0;
|
||||
|
||||
/*if ( size == SMALLCHAR_WIDTH ) {
|
||||
SCR_DrawSmallChar( x + ( edit->cursor - prestep - i ) * size, y, cursorChar );
|
||||
} else {
|
||||
str[0] = cursorChar;
|
||||
str[1] = 0;
|
||||
SCR_DrawBigString( x + ( edit->cursor - prestep - i ) * size, y, str, 1.0, qfalse );
|
||||
|
||||
}*/
|
||||
//str[edit->cursor - prestep - i] = cursorChar;
|
||||
//str[edit->cursor - prestep - i + 1] = 0;
|
||||
re.Text_PaintChar(&cls.consoleFont, x + re.Text_Width(&cls.consoleFont, str, 0, !noColorEscape), y, 1.f, cursorChar,0);
|
||||
}
|
||||
}
|
||||
|
||||
void Field_Draw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape )
|
||||
{
|
||||
Field_VariableSizeDraw(font, edit, x, y, width, showCursor, noColorEscape );
|
||||
}
|
||||
|
||||
void Field_BigDraw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape )
|
||||
{
|
||||
Field_VariableSizeDraw(font, edit, x, y, width, showCursor, noColorEscape );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Field_Paste
|
||||
================
|
||||
*/
|
||||
void Field_Paste( field_t *edit ) {
|
||||
char *cbd;
|
||||
int pasteLen, i;
|
||||
|
||||
cbd = Sys_GetClipboardData();
|
||||
|
||||
if ( !cbd ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// send as if typed, so insert / overstrike works properly
|
||||
pasteLen = strlen( cbd );
|
||||
for ( i = 0 ; i < pasteLen ; i++ ) {
|
||||
Field_CharEvent( edit, cbd[i] );
|
||||
}
|
||||
|
||||
Z_Free( cbd );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Field_KeyDownEvent
|
||||
|
||||
Performs the basic line editing functions for the console,
|
||||
in-game talk, and menu fields
|
||||
|
||||
Key events are used for non-printable characters, others are gotten from char events.
|
||||
=================
|
||||
*/
|
||||
void Field_KeyDownEvent( field_t *edit, int key ) {
|
||||
int len;
|
||||
|
||||
// shift-insert is paste
|
||||
if ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keys[K_SHIFT].down ) {
|
||||
Field_Paste( edit );
|
||||
return;
|
||||
}
|
||||
|
||||
key = tolower( key );
|
||||
len = strlen( edit->buffer );
|
||||
|
||||
switch ( key ) {
|
||||
case K_DEL:
|
||||
if ( edit->cursor < len ) {
|
||||
memmove( edit->buffer + edit->cursor,
|
||||
edit->buffer + edit->cursor + 1, len - edit->cursor );
|
||||
}
|
||||
break;
|
||||
|
||||
case K_RIGHTARROW:
|
||||
if ( edit->cursor < len ) {
|
||||
edit->cursor++;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_LEFTARROW:
|
||||
if ( edit->cursor > 0 ) {
|
||||
edit->cursor--;
|
||||
}
|
||||
break;
|
||||
|
||||
case K_HOME:
|
||||
edit->cursor = 0;
|
||||
break;
|
||||
|
||||
case K_END:
|
||||
edit->cursor = len;
|
||||
break;
|
||||
|
||||
case K_INS:
|
||||
key_overstrikeMode = !key_overstrikeMode;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Change scroll if cursor is no longer visible
|
||||
if ( edit->cursor < edit->scroll ) {
|
||||
edit->scroll = edit->cursor;
|
||||
} else if ( edit->cursor >= edit->scroll + edit->widthInChars && edit->cursor <= len ) {
|
||||
edit->scroll = edit->cursor - edit->widthInChars + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
Field_CharEvent
|
||||
==================
|
||||
*/
|
||||
void Field_CharEvent( field_t *edit, int ch ) {
|
||||
int len;
|
||||
|
||||
if ( ch == 'v' - 'a' + 1 ) { // ctrl-v is paste
|
||||
Field_Paste( edit );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ch == 'c' - 'a' + 1 ) { // ctrl-c clears the field
|
||||
Field_Clear( edit );
|
||||
return;
|
||||
}
|
||||
|
||||
len = strlen( edit->buffer );
|
||||
|
||||
if ( ch == 'h' - 'a' + 1 ) { // ctrl-h is backspace
|
||||
if ( edit->cursor > 0 ) {
|
||||
memmove( edit->buffer + edit->cursor - 1,
|
||||
edit->buffer + edit->cursor, len + 1 - edit->cursor );
|
||||
edit->cursor--;
|
||||
if ( edit->cursor < edit->scroll )
|
||||
{
|
||||
edit->scroll--;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ch == 'a' - 'a' + 1 ) { // ctrl-a is home
|
||||
edit->cursor = 0;
|
||||
edit->scroll = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ch == 'e' - 'a' + 1 ) { // ctrl-e is end
|
||||
edit->cursor = len;
|
||||
edit->scroll = edit->cursor - edit->widthInChars;
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// ignore any other non printable chars
|
||||
//
|
||||
if ( ch < 32 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key_overstrikeMode ) {
|
||||
if ( edit->cursor == MAX_EDIT_LINE - 1 )
|
||||
return;
|
||||
edit->buffer[edit->cursor] = ch;
|
||||
edit->cursor++;
|
||||
} else { // insert mode
|
||||
if ( len == MAX_EDIT_LINE - 1 ) {
|
||||
return; // all full
|
||||
}
|
||||
memmove( edit->buffer + edit->cursor + 1,
|
||||
edit->buffer + edit->cursor, len + 1 - edit->cursor );
|
||||
edit->buffer[edit->cursor] = ch;
|
||||
edit->cursor++;
|
||||
}
|
||||
|
||||
|
||||
if ( edit->cursor >= edit->widthInChars ) {
|
||||
edit->scroll++;
|
||||
}
|
||||
|
||||
if ( edit->cursor == len + 1) {
|
||||
edit->buffer[edit->cursor] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
CONSOLE LINE EDITING
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
====================
|
||||
Console_Key
|
||||
|
||||
Handles history and console scrollback
|
||||
====================
|
||||
*/
|
||||
void Console_Key (int key) {
|
||||
// ctrl-L clears screen
|
||||
if ( key == 'l' && keys[K_CTRL].down ) {
|
||||
Cbuf_AddText ("clear\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// enter finishes the line
|
||||
if ( key == K_ENTER || key == K_KP_ENTER ) {
|
||||
// if not in the game explicitly prepend a slash if needed
|
||||
if ( cls.state != CA_ACTIVE && g_consoleField.buffer[0] != '\\'
|
||||
&& g_consoleField.buffer[0] != '/' ) {
|
||||
char temp[MAX_EDIT_LINE-1];
|
||||
|
||||
Q_strncpyz( temp, g_consoleField.buffer, sizeof( temp ) );
|
||||
Com_sprintf( g_consoleField.buffer, sizeof( g_consoleField.buffer ), "\\%s", temp );
|
||||
g_consoleField.cursor++;
|
||||
}
|
||||
|
||||
Com_Printf ( "]%s\n", g_consoleField.buffer );
|
||||
|
||||
// leading slash is an explicit command
|
||||
if ( g_consoleField.buffer[0] == '\\' || g_consoleField.buffer[0] == '/' ) {
|
||||
Cbuf_AddText( g_consoleField.buffer+1 ); // valid command
|
||||
Cbuf_AddText ("\n");
|
||||
} else {
|
||||
// other text will be chat messages
|
||||
if ( !g_consoleField.buffer[0] ) {
|
||||
return; // empty lines just scroll the console without adding to history
|
||||
} else {
|
||||
Cbuf_AddText ("cmd say ");
|
||||
Cbuf_AddText( g_consoleField.buffer );
|
||||
Cbuf_AddText ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// copy line to history buffer
|
||||
historyEditLines[nextHistoryLine % COMMAND_HISTORY] = g_consoleField;
|
||||
nextHistoryLine++;
|
||||
historyLine = nextHistoryLine;
|
||||
|
||||
Field_Clear( &g_consoleField );
|
||||
|
||||
g_consoleField.widthInChars = g_console_field_width;
|
||||
|
||||
CL_SaveConsoleHistory( );
|
||||
|
||||
if ( cls.state == CA_DISCONNECTED ) {
|
||||
SCR_UpdateScreen (); // force an update, because the command
|
||||
} // may take some time
|
||||
return;
|
||||
}
|
||||
|
||||
// command completion
|
||||
|
||||
if (key == K_TAB) {
|
||||
Field_AutoComplete(&g_consoleField);
|
||||
return;
|
||||
}
|
||||
|
||||
// command history (ctrl-p ctrl-n for unix style)
|
||||
|
||||
if ( (key == K_MWHEELUP && keys[K_SHIFT].down) || ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
|
||||
( ( tolower(key) == 'p' ) && keys[K_CTRL].down ) ) {
|
||||
if ( nextHistoryLine - historyLine < COMMAND_HISTORY
|
||||
&& historyLine > 0 ) {
|
||||
historyLine--;
|
||||
}
|
||||
g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
|
||||
return;
|
||||
}
|
||||
|
||||
if ( (key == K_MWHEELDOWN && keys[K_SHIFT].down) || ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
|
||||
( ( tolower(key) == 'n' ) && keys[K_CTRL].down ) ) {
|
||||
historyLine++;
|
||||
if (historyLine >= nextHistoryLine) {
|
||||
historyLine = nextHistoryLine;
|
||||
Field_Clear( &g_consoleField );
|
||||
g_consoleField.widthInChars = g_console_field_width;
|
||||
return;
|
||||
}
|
||||
g_consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
|
||||
return;
|
||||
}
|
||||
|
||||
// console scrolling
|
||||
if ( key == K_PGUP ) {
|
||||
Con_PageUp();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key == K_PGDN) {
|
||||
Con_PageDown();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key == K_MWHEELUP) { //----(SA) added some mousewheel functionality to the console
|
||||
Con_PageUp();
|
||||
if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
|
||||
Con_PageUp();
|
||||
Con_PageUp();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key == K_MWHEELDOWN) { //----(SA) added some mousewheel functionality to the console
|
||||
Con_PageDown();
|
||||
if(keys[K_CTRL].down) { // hold <ctrl> to accelerate scrolling
|
||||
Con_PageDown();
|
||||
Con_PageDown();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ctrl-home = top of console
|
||||
if ( key == K_HOME && keys[K_CTRL].down ) {
|
||||
Con_Top();
|
||||
return;
|
||||
}
|
||||
|
||||
// ctrl-end = bottom of console
|
||||
if ( key == K_END && keys[K_CTRL].down ) {
|
||||
Con_Bottom();
|
||||
return;
|
||||
}
|
||||
|
||||
// pass to the normal editline routine
|
||||
Field_KeyDownEvent( &g_consoleField, key );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
Message_Key
|
||||
@@ -740,33 +211,14 @@ void Message_Key( int key ) {
|
||||
|
||||
if (key == K_ESCAPE) {
|
||||
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
|
||||
Field_Clear( &chatField );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( key == K_ENTER || key == K_KP_ENTER )
|
||||
{
|
||||
if ( chatField.buffer[0] && cls.state == CA_ACTIVE ) {
|
||||
if (chat_playerNum != -1 )
|
||||
|
||||
Com_sprintf( buffer, sizeof( buffer ), "tell %i \"%s\"\n", chat_playerNum, chatField.buffer );
|
||||
|
||||
else if (chat_team)
|
||||
|
||||
Com_sprintf( buffer, sizeof( buffer ), "say_team \"%s\"\n", chatField.buffer );
|
||||
else
|
||||
Com_sprintf( buffer, sizeof( buffer ), "say \"%s\"\n", chatField.buffer );
|
||||
|
||||
|
||||
|
||||
CL_AddReliableCommand( buffer );
|
||||
}
|
||||
Key_SetCatcher( Key_GetCatcher( ) & ~KEYCATCH_MESSAGE );
|
||||
Field_Clear( &chatField );
|
||||
return;
|
||||
}
|
||||
|
||||
Field_KeyDownEvent( &chatField, key );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
@@ -788,7 +240,7 @@ Key_IsDown
|
||||
===================
|
||||
*/
|
||||
qboolean Key_IsDown( int keynum ) {
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
@@ -870,7 +322,7 @@ const char *Key_KeynumToString( int keynum ) {
|
||||
return "<KEY NOT FOUND>";
|
||||
}
|
||||
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return "<OUT OF RANGE>";
|
||||
}
|
||||
|
||||
@@ -917,7 +369,7 @@ const char *Key_KeynumToBindString( int keynum ) {
|
||||
return "Not Bound";
|
||||
}
|
||||
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return "Out of Range";
|
||||
}
|
||||
|
||||
@@ -945,7 +397,7 @@ Key_SetBinding
|
||||
===================
|
||||
*/
|
||||
void Key_SetBinding( int keynum, const char *binding ) {
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -968,7 +420,7 @@ Key_SetAltBinding
|
||||
===================
|
||||
*/
|
||||
void Key_SetAltBinding( int keynum, const char *binding ) {
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -991,7 +443,7 @@ Key_SetCtrlBinding
|
||||
===================
|
||||
*/
|
||||
void Key_SetCtrlBinding( int keynum, const char *binding ) {
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1014,8 +466,8 @@ void Key_SetCtrlBinding( int keynum, const char *binding ) {
|
||||
Key_GetBinding
|
||||
===================
|
||||
*/
|
||||
char *Key_GetBinding( int keynum ) {
|
||||
if ( keynum < 0 || keynum >= MAX_KEYS ) {
|
||||
const char *Key_GetBinding( int keynum ) {
|
||||
if ( keynum < 0 || keynum >= K_LASTKEY ) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -1032,7 +484,7 @@ int Key_GetKey(const char *binding) {
|
||||
int i;
|
||||
|
||||
if (binding) {
|
||||
for (i=0 ; i < MAX_KEYS ; i++) {
|
||||
for (i=0 ; i < K_LASTKEY ; i++) {
|
||||
if (keys[i].binding && Q_stricmp(binding, keys[i].binding) == 0) {
|
||||
return i;
|
||||
}
|
||||
@@ -1049,7 +501,7 @@ Key_GetKeynameForCommand
|
||||
const char *Key_GetKeynameForCommand( const char *command ) {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < MAX_KEYS; i++ ) {
|
||||
for( i = 0; i < K_LASTKEY; i++ ) {
|
||||
if( !keys[ i ].binding ) {
|
||||
continue;
|
||||
}
|
||||
@@ -1069,9 +521,9 @@ Key_GetKeysForCommand
|
||||
void Key_GetKeysForCommand( const char *command, int *key1, int *key2 ) {
|
||||
int i;
|
||||
|
||||
*key1 = *key2 = 0;
|
||||
*key1 = *key2 = -1;
|
||||
|
||||
for( i = 0; i < MAX_KEYS; i++ ) {
|
||||
for( i = 0; i < K_LASTKEY; i++ ) {
|
||||
if( !keys[ i ].binding ) {
|
||||
continue;
|
||||
}
|
||||
@@ -1170,7 +622,7 @@ void Key_Unbindall_f (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i < MAX_KEYS; i++)
|
||||
for (i=0 ; i < K_LASTKEY; i++)
|
||||
if (keys[i].binding)
|
||||
Key_SetBinding (i, "");
|
||||
}
|
||||
@@ -1323,7 +775,7 @@ void Key_WriteBindings( fileHandle_t f ) {
|
||||
|
||||
FS_Printf (f, "unbindall\n" );
|
||||
|
||||
for (i=0 ; i<MAX_KEYS ; i++) {
|
||||
for (i=0 ; i<K_LASTKEY ; i++) {
|
||||
if (keys[i].binding && keys[i].binding[0] ) {
|
||||
FS_Printf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keys[i].binding);
|
||||
|
||||
@@ -1342,7 +794,7 @@ Key_Bindlist_f
|
||||
void Key_Bindlist_f( void ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < MAX_KEYS ; i++ ) {
|
||||
for ( i = 0 ; i < K_LASTKEY ; i++ ) {
|
||||
if ( keys[i].binding && keys[i].binding[0] ) {
|
||||
Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), keys[i].binding );
|
||||
}
|
||||
@@ -1358,7 +810,7 @@ Key_AltBindlist_f
|
||||
void Key_AltBindlist_f( void ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < MAX_KEYS ; i++ ) {
|
||||
for ( i = 0 ; i < K_LASTKEY ; i++ ) {
|
||||
if ( altkeys[i].binding && altkeys[i].binding[0] ) {
|
||||
Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), altkeys[i].binding );
|
||||
}
|
||||
@@ -1374,7 +826,7 @@ Key_CtrlBindlist_f
|
||||
void Key_CtrlBindlist_f( void ) {
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < MAX_KEYS ; i++ ) {
|
||||
for ( i = 0 ; i < K_LASTKEY ; i++ ) {
|
||||
if ( ctrlkeys[i].binding && ctrlkeys[i].binding[0] ) {
|
||||
Com_Printf( "%s \"%s\"\n", Key_KeynumToString(i), ctrlkeys[i].binding );
|
||||
}
|
||||
@@ -1487,15 +939,21 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
|
||||
}
|
||||
}
|
||||
|
||||
if( ( key == K_ALT || key == K_INS ) && cl_altbindings->integer ) {
|
||||
if( ( key == K_LALT || key == K_INS ) && cl_altbindings->integer ) {
|
||||
alt_down = down;
|
||||
}
|
||||
|
||||
if( ( key == K_CTRL || key == K_DEL ) && cl_ctrlbindings->integer ) {
|
||||
if( ( key == K_LCTRL || key == K_DEL ) && cl_ctrlbindings->integer ) {
|
||||
ctrl_down = down;
|
||||
}
|
||||
|
||||
if( cls.state > CA_DISCONNECTED && cge && !cls.keyCatchers && cge->CG_CheckCaptureKey( key, down, time ) && key != K_ESCAPE )
|
||||
if (down && !CL_FinishedIntro())
|
||||
{
|
||||
UI_StartStageKeyEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
if( cls.state > CA_DISCONNECTED && cge && !Key_GetCatcher() && cge->CG_CheckCaptureKey( key, down, time ) && key != K_ESCAPE )
|
||||
{
|
||||
if( key != '`' && key != '~' )
|
||||
return;
|
||||
@@ -1506,6 +964,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
|
||||
if( !down ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( Cvar_VariableIntegerValue( "ui_console" ) )
|
||||
{
|
||||
UI_ToggleConsole();
|
||||
@@ -1521,10 +980,10 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
|
||||
|
||||
if( down )
|
||||
{
|
||||
if( alt_down && key != K_ALT && key != K_INS ) {
|
||||
if( alt_down && key != K_LALT && key != K_INS ) {
|
||||
altkeys[ key ].down = down;
|
||||
}
|
||||
if( down && ctrl_down && key != K_CTRL ) {
|
||||
if( down && ctrl_down && key != K_LCTRL ) {
|
||||
ctrlkeys[ key ].down = down;
|
||||
}
|
||||
}
|
||||
@@ -1537,7 +996,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
|
||||
{
|
||||
if (down)
|
||||
{
|
||||
if (keys[K_ALT].down)
|
||||
if (keys[K_LALT].down)
|
||||
{
|
||||
Key_ClearStates();
|
||||
Cvar_SetValue( "r_fullscreen",
|
||||
@@ -1559,10 +1018,10 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
|
||||
}
|
||||
}
|
||||
|
||||
if( in_guimouse || key <= K_MOUSE3 || key > K_JOY1 )
|
||||
if (!in_guimouse || key <= K_MOUSE3 || key > K_JOY1)
|
||||
{
|
||||
// keys can still be used for bound actions
|
||||
if( down && ( key < 128 || key == K_MOUSE4 ) &&
|
||||
if (down && (key <= K_BACKSPACE || key == K_MOUSE4) &&
|
||||
( clc.demoplaying || cls.state == CA_CINEMATIC ) && Key_GetCatcher() == 0 ) {
|
||||
Cvar_Set( "nextdemo", "" );
|
||||
key = K_ESCAPE;
|
||||
@@ -1605,7 +1064,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) {
|
||||
UI_KeyEvent( key, time );
|
||||
} else if( cls.loading & KEYCATCH_MESSAGE ) {
|
||||
Message_Key( key );
|
||||
} else if( cls.state != CA_DISCONNECTED ) {
|
||||
} else if( cls.state != CA_DISCONNECTED || menubound[key]) {
|
||||
// send the bound action
|
||||
kb = altkeys[ key ].binding;
|
||||
if( !kb || !altkeys[ key ].down ) {
|
||||
@@ -1713,7 +1172,7 @@ void Key_ClearStates (void)
|
||||
|
||||
anykeydown = 0;
|
||||
|
||||
for ( i=0 ; i < MAX_KEYS ; i++ ) {
|
||||
for ( i=0 ; i < K_LASTKEY ; i++ ) {
|
||||
if ( keys[i].down ) {
|
||||
CL_KeyEvent( i, qfalse, 0 );
|
||||
|
||||
@@ -1740,142 +1199,5 @@ Key_SetCatcher
|
||||
====================
|
||||
*/
|
||||
void Key_SetCatcher( int catcher ) {
|
||||
// If the catcher state is changing, clear all key states
|
||||
if( catcher != keyCatchers )
|
||||
Key_ClearStates( );
|
||||
|
||||
keyCatchers = catcher;
|
||||
}
|
||||
|
||||
// This must not exceed MAX_CMD_LINE
|
||||
#define MAX_CONSOLE_SAVE_BUFFER 1024
|
||||
#define CONSOLE_HISTORY_FILE "omhistory"
|
||||
static char consoleSaveBuffer[ MAX_CONSOLE_SAVE_BUFFER ];
|
||||
static int consoleSaveBufferSize = 0;
|
||||
|
||||
/*
|
||||
================
|
||||
CL_LoadConsoleHistory
|
||||
|
||||
Load the console history from cl_consoleHistory
|
||||
================
|
||||
*/
|
||||
void CL_LoadConsoleHistory( void )
|
||||
{
|
||||
const char *token;
|
||||
char *text_p;
|
||||
int i, numChars, numLines = 0;
|
||||
fileHandle_t f;
|
||||
|
||||
consoleSaveBufferSize = FS_FOpenFileRead( CONSOLE_HISTORY_FILE, &f, qfalse, qtrue );
|
||||
if( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
|
||||
return;
|
||||
}
|
||||
|
||||
if( consoleSaveBufferSize <= MAX_CONSOLE_SAVE_BUFFER &&
|
||||
FS_Read( consoleSaveBuffer, consoleSaveBufferSize, f ) == consoleSaveBufferSize )
|
||||
{
|
||||
text_p = consoleSaveBuffer;
|
||||
|
||||
for( i = COMMAND_HISTORY - 1; i >= 0; i-- )
|
||||
{
|
||||
if( !*( token = COM_Parse( &text_p ) ) )
|
||||
break;
|
||||
|
||||
historyEditLines[ i ].cursor = atoi( token );
|
||||
|
||||
if( !*( token = COM_Parse( &text_p ) ) )
|
||||
break;
|
||||
|
||||
historyEditLines[ i ].scroll = atoi( token );
|
||||
|
||||
if( !*( token = COM_Parse( &text_p ) ) )
|
||||
break;
|
||||
|
||||
numChars = atoi( token );
|
||||
text_p++;
|
||||
if( numChars > ( strlen( consoleSaveBuffer ) - ( text_p - consoleSaveBuffer ) ) )
|
||||
{
|
||||
Com_DPrintf( S_COLOR_YELLOW "WARNING: probable corrupt history\n" );
|
||||
break;
|
||||
}
|
||||
Com_Memcpy( historyEditLines[ i ].buffer,
|
||||
text_p, numChars );
|
||||
historyEditLines[ i ].buffer[ numChars ] = '\0';
|
||||
text_p += numChars;
|
||||
|
||||
numLines++;
|
||||
}
|
||||
|
||||
memmove( &historyEditLines[ 0 ], &historyEditLines[ i + 1 ],
|
||||
numLines * sizeof( field_t ) );
|
||||
for( i = numLines; i < COMMAND_HISTORY; i++ )
|
||||
Field_Clear( &historyEditLines[ i ] );
|
||||
|
||||
historyLine = nextHistoryLine = numLines;
|
||||
}
|
||||
else
|
||||
Com_Printf( "Couldn't read %s.\n", CONSOLE_HISTORY_FILE );
|
||||
|
||||
FS_FCloseFile( f );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
CL_SaveConsoleHistory
|
||||
|
||||
Save the console history into the cvar cl_consoleHistory
|
||||
so that it persists across invocations of q3
|
||||
================
|
||||
*/
|
||||
void CL_SaveConsoleHistory( void )
|
||||
{
|
||||
int i;
|
||||
int lineLength, saveBufferLength, additionalLength;
|
||||
fileHandle_t f;
|
||||
|
||||
consoleSaveBuffer[ 0 ] = '\0';
|
||||
|
||||
i = ( nextHistoryLine - 1 ) % COMMAND_HISTORY;
|
||||
do
|
||||
{
|
||||
if( historyEditLines[ i ].buffer[ 0 ] )
|
||||
{
|
||||
lineLength = strlen( historyEditLines[ i ].buffer );
|
||||
saveBufferLength = strlen( consoleSaveBuffer );
|
||||
|
||||
//ICK
|
||||
additionalLength = lineLength + strlen( "999 999 999 " );
|
||||
|
||||
if( saveBufferLength + additionalLength < MAX_CONSOLE_SAVE_BUFFER )
|
||||
{
|
||||
Q_strcat( consoleSaveBuffer, MAX_CONSOLE_SAVE_BUFFER,
|
||||
va( "%d %d %d %s ",
|
||||
historyEditLines[ i ].cursor,
|
||||
historyEditLines[ i ].scroll,
|
||||
lineLength,
|
||||
historyEditLines[ i ].buffer ) );
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
i = ( i - 1 + COMMAND_HISTORY ) % COMMAND_HISTORY;
|
||||
}
|
||||
while( i != ( nextHistoryLine - 1 ) % COMMAND_HISTORY );
|
||||
|
||||
consoleSaveBufferSize = strlen( consoleSaveBuffer );
|
||||
|
||||
f = FS_FOpenFileWrite( CONSOLE_HISTORY_FILE );
|
||||
if( !f )
|
||||
{
|
||||
Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
|
||||
return;
|
||||
}
|
||||
|
||||
if( FS_Write( consoleSaveBuffer, consoleSaveBufferSize, f ) < consoleSaveBufferSize )
|
||||
Com_Printf( "Couldn't write %s.\n", CONSOLE_HISTORY_FILE );
|
||||
|
||||
FS_FCloseFile( f );
|
||||
}
|
||||
+148
-172
@@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#include "client.h"
|
||||
#include "server.h"
|
||||
#include "cl_ui.h"
|
||||
#include "tiki.h"
|
||||
#include <cm_terrain.h>
|
||||
#include "../sys/sys_local.h"
|
||||
#include <limits.h>
|
||||
@@ -31,6 +32,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#include "../sys/sys_loadlib.h"
|
||||
#endif
|
||||
|
||||
#include "gcdkeyc.h"
|
||||
|
||||
cvar_t *cl_nodelta;
|
||||
cvar_t *cl_debugMove;
|
||||
|
||||
@@ -96,6 +99,18 @@ cvar_t *wombat;
|
||||
cvar_t *cl_r_fullscreen;
|
||||
|
||||
cvar_t *cl_consoleKeys;
|
||||
cvar_t *name;
|
||||
|
||||
cvar_t* j_pitch;
|
||||
cvar_t* j_yaw;
|
||||
cvar_t* j_forward;
|
||||
cvar_t* j_side;
|
||||
cvar_t* j_up;
|
||||
cvar_t* j_pitch_axis;
|
||||
cvar_t* j_yaw_axis;
|
||||
cvar_t* j_forward_axis;
|
||||
cvar_t* j_side_axis;
|
||||
cvar_t* j_up_axis;
|
||||
|
||||
clientActive_t cl;
|
||||
clientConnection_t clc;
|
||||
@@ -206,7 +221,7 @@ CL_ChangeReliableCommand
|
||||
======================
|
||||
*/
|
||||
void CL_ChangeReliableCommand( void ) {
|
||||
int r, index, l;
|
||||
size_t r, index, l;
|
||||
|
||||
r = clc.reliableSequence - (random() * 5);
|
||||
index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
|
||||
@@ -234,7 +249,7 @@ Dumps the current net message, prefixed by the length
|
||||
====================
|
||||
*/
|
||||
void CL_WriteDemoMessage ( msg_t *msg, int headerBytes ) {
|
||||
int len, swlen;
|
||||
size_t len, swlen;
|
||||
|
||||
// write the packet sequence
|
||||
len = clc.serverMessageSequence;
|
||||
@@ -313,7 +328,7 @@ void CL_Record_f( void ) {
|
||||
byte bufData[MAX_MSGLEN];
|
||||
msg_t buf;
|
||||
int i;
|
||||
int len;
|
||||
size_t len;
|
||||
entityState_t *ent;
|
||||
entityState_t nullstate;
|
||||
char *s;
|
||||
@@ -407,7 +422,8 @@ void CL_Record_f( void ) {
|
||||
continue;
|
||||
}
|
||||
MSG_WriteByte (&buf, svc_baseline);
|
||||
MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue );
|
||||
// FIXME
|
||||
MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue, 0.0 );
|
||||
}
|
||||
|
||||
MSG_WriteByte( &buf, svc_EOF );
|
||||
@@ -544,7 +560,7 @@ CL_ReadDemoMessage
|
||||
=================
|
||||
*/
|
||||
void CL_ReadDemoMessage( void ) {
|
||||
int r;
|
||||
size_t r;
|
||||
msg_t buf;
|
||||
byte bufData[ MAX_MSGLEN ];
|
||||
int s;
|
||||
@@ -675,7 +691,7 @@ void CL_PlayDemo_f( void ) {
|
||||
}
|
||||
Q_strncpyz( clc.demoName, Cmd_Argv(1), sizeof( clc.demoName ) );
|
||||
|
||||
Con_Close();
|
||||
UI_CloseConsole();
|
||||
|
||||
cls.state = CA_CONNECTED;
|
||||
clc.demoplaying = qtrue;
|
||||
@@ -789,40 +805,38 @@ memory on the hunk from cgame, ui, and renderer
|
||||
=====================
|
||||
*/
|
||||
void CL_MapLoading( qboolean flush, const char *pszMapName ) {
|
||||
if ( com_dedicated->integer ) {
|
||||
cls.state = CA_DISCONNECTED;
|
||||
Key_SetCatcher( KEYCATCH_CONSOLE );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !com_cl_running->integer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Con_Close();
|
||||
Key_SetCatcher( 0 );
|
||||
UI_ClearState();
|
||||
UI_ForceMenuOff(false);
|
||||
|
||||
// if we are already connected to the local host, stay connected
|
||||
if ( cls.state >= CA_CONNECTED && !Q_stricmp( cls.servername, "localhost" ) ) {
|
||||
cls.state = CA_CONNECTED; // so the connect screen is drawn
|
||||
Com_Memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) );
|
||||
Com_Memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) );
|
||||
Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );
|
||||
clc.lastPacketSentTime = -9999;
|
||||
SCR_UpdateScreen();
|
||||
} else {
|
||||
// clear nextmap so the cinematic shutdown doesn't execute it
|
||||
Cvar_Set( "nextmap", "" );
|
||||
CL_Disconnect( qtrue );
|
||||
Q_strncpyz( cls.servername, "localhost", sizeof(cls.servername) );
|
||||
cls.state = CA_CHALLENGING; // so the connect screen is drawn
|
||||
Key_SetCatcher( 0 );
|
||||
SCR_UpdateScreen();
|
||||
clc.connectTime = -RETRANSMIT_TIMEOUT;
|
||||
NET_StringToAdr( cls.servername, &clc.serverAddress);
|
||||
// we don't need a challenge on the localhost
|
||||
if (pszMapName) {
|
||||
// if we are already connected to the local host, stay connected
|
||||
if (cls.state >= CA_CONNECTED && !Q_stricmp(cls.servername, "localhost")) {
|
||||
cls.state = CA_CONNECTED; // so the connect screen is drawn
|
||||
Com_Memset(cls.updateInfoString, 0, sizeof(cls.updateInfoString));
|
||||
Com_Memset(clc.serverMessage, 0, sizeof(clc.serverMessage));
|
||||
Com_Memset(&cl.gameState, 0, sizeof(cl.gameState));
|
||||
clc.lastPacketSentTime = -9999;
|
||||
}
|
||||
else {
|
||||
// clear nextmap so the cinematic shutdown doesn't execute it
|
||||
Cvar_Set("nextmap", "");
|
||||
CL_Disconnect(qtrue);
|
||||
Q_strncpyz(cls.servername, "localhost", sizeof(cls.servername));
|
||||
cls.state = CA_CHALLENGING; // so the connect screen is drawn
|
||||
clc.connectStartTime = cls.realtime;
|
||||
clc.connectTime = -RETRANSMIT_TIMEOUT;
|
||||
NET_StringToAdr(cls.servername, &clc.serverAddress);
|
||||
// we don't need a challenge on the localhost
|
||||
|
||||
CL_CheckForResend();
|
||||
CL_CheckForResend();
|
||||
}
|
||||
|
||||
CL_FlushMemory();
|
||||
UI_BeginLoad(pszMapName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,7 +1061,8 @@ in anyway.
|
||||
*/
|
||||
void CL_RequestAuthorization( void ) {
|
||||
char nums[64];
|
||||
int i, j, l;
|
||||
int i, j;
|
||||
size_t l;
|
||||
cvar_t *fs;
|
||||
|
||||
if ( !cls.authorizeServer.port ) {
|
||||
@@ -1205,7 +1220,7 @@ void CL_Connect( const char *server ) {
|
||||
SV_Frame( 0 );
|
||||
|
||||
CL_Disconnect( qtrue );
|
||||
Con_Close();
|
||||
UI_CloseConsole();
|
||||
|
||||
/* MrE: 2000-09-13: now called in CL_DownloadsComplete
|
||||
CL_FlushMemory( );
|
||||
@@ -1228,11 +1243,6 @@ void CL_Connect( const char *server ) {
|
||||
|
||||
Com_Printf( "%s resolved to %s\n", cls.servername, serverString );
|
||||
|
||||
if( cl_guidServerUniq->integer )
|
||||
CL_UpdateGUID( serverString, strlen( serverString ) );
|
||||
else
|
||||
CL_UpdateGUID( NULL, 0 );
|
||||
|
||||
// if we aren't playing on a lan, we need to authenticate
|
||||
// with the cd key
|
||||
// wombat: no authorization in mohaa. need to send challenge to server though
|
||||
@@ -1243,9 +1253,9 @@ void CL_Connect( const char *server ) {
|
||||
cls.state = CA_CONNECTING;
|
||||
}
|
||||
|
||||
Key_SetCatcher( 0 );
|
||||
clc.connectTime = -99999; // CL_CheckForResend() will fire immediately
|
||||
clc.connectPacketCount = 0;
|
||||
clc.connectStartTime = 0;
|
||||
|
||||
// server connection string
|
||||
Cvar_Set( "cl_currentServerAddress", server );
|
||||
@@ -1265,7 +1275,7 @@ void CL_Connect_f( void ) {
|
||||
Com_Printf( "usage: connect [server]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
server = Cmd_Argv (1);
|
||||
|
||||
CL_Connect( server );
|
||||
@@ -1415,6 +1425,10 @@ void CL_ResetPureClientAtServer( void ) {
|
||||
CL_AddReliableCommand( va("vdr") );
|
||||
}
|
||||
|
||||
qboolean CL_Allowed_Vid_Restart() {
|
||||
return cls.state == CA_DISCONNECTED || cls.state == CA_ACTIVE;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_Vid_Restart_f
|
||||
@@ -1426,33 +1440,30 @@ because the renderer doesn't know what graphics to reload
|
||||
=================
|
||||
*/
|
||||
void CL_Vid_Restart_f( void ) {
|
||||
|
||||
// Settings may have changed so stop recording now
|
||||
if( CL_VideoRecording( ) ) {
|
||||
CL_CloseAVI( );
|
||||
if (!CL_Allowed_Vid_Restart()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(clc.demorecording)
|
||||
CL_StopRecord_f();
|
||||
Com_Printf("-------- CL_Vid_Restart_f --------\n");
|
||||
cls.vid_restart = qtrue;
|
||||
|
||||
// don't let them loop during the restart
|
||||
S_StopAllSounds( qtrue );
|
||||
S_StopAllSounds(qtrue);
|
||||
|
||||
SV_ClearSvsTimeFixups();
|
||||
|
||||
S_BeginRegistration();
|
||||
|
||||
// shutdown the renderer and clear the renderer interface
|
||||
CL_ShutdownRef();
|
||||
// shutdown the CGame
|
||||
CL_ShutdownCGame();
|
||||
// initialize the renderer interface
|
||||
CL_InitRef();
|
||||
// client is no longer pure untill new checksums are sent
|
||||
CL_ResetPureClientAtServer();
|
||||
// clear pak references
|
||||
FS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF );
|
||||
// reinitialize the filesystem if the game directory or checksum has changed
|
||||
FS_ConditionalRestart( clc.checksumFeed );
|
||||
// initialize the ui library
|
||||
UI_ResolutionChange();
|
||||
|
||||
cls.rendererRegistered = qfalse;
|
||||
cls.uiStarted = qfalse;
|
||||
cls.cgameStarted = qfalse;
|
||||
|
||||
// unpause so the cgame definately gets a snapshot and renders a frame
|
||||
Com_Unpause();
|
||||
@@ -1463,6 +1474,8 @@ void CL_Vid_Restart_f( void ) {
|
||||
|
||||
S_Init();
|
||||
|
||||
cls.vid_restart = qfalse;
|
||||
Com_Printf("----- finished CL_Vid_Restart_f ----\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1595,34 +1608,11 @@ void CL_DownloadsComplete( void ) {
|
||||
// let the client game init and load data
|
||||
cls.state = CA_LOADING;
|
||||
|
||||
// Pump the loop, this may change gamestate!
|
||||
Com_EventLoop();
|
||||
CL_StartHunkUsers();
|
||||
// Pump the loop, this may change gamestate!
|
||||
Com_EventLoop();
|
||||
|
||||
// if the gamestate was changed by calling Com_EventLoop
|
||||
// then we loaded everything already and we don't want to do it again.
|
||||
if ( cls.state != CA_LOADING ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// starting to load a map so we get out of full screen ui mode
|
||||
Cvar_Set("r_uiFullScreen", "0");
|
||||
|
||||
// flush client memory and start loading stuff
|
||||
// this will also (re)load the UI
|
||||
// if this is a local client then only the client part of the hunk
|
||||
// will be cleared, note that this is done after the hunk mark has been set
|
||||
CL_FlushMemory();
|
||||
|
||||
// initialize the CGame
|
||||
cls.cgameStarted = qtrue;
|
||||
CL_InitCGame();
|
||||
|
||||
// set pure checksums
|
||||
CL_SendPureChecksums();
|
||||
|
||||
CL_WritePacket();
|
||||
CL_WritePacket();
|
||||
CL_WritePacket();
|
||||
CL_StartHunkUsers();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1821,7 +1811,11 @@ void CL_CheckForResend( void ) {
|
||||
// }
|
||||
NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "getchallenge");
|
||||
break;
|
||||
|
||||
case CA_AUTHORIZING:
|
||||
// resend the cd key authorization
|
||||
gcd_compute_response(cl_cdkey, Cmd_Argv(1), cls.gcdResponse, CDResponseMethod_REAUTH);
|
||||
NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "authorizeThis %s", cls.gcdResponse);
|
||||
break;
|
||||
case CA_CHALLENGING:
|
||||
/*
|
||||
wombat: sending conect here: an example connect string from MOHAA looks like this:
|
||||
@@ -1834,7 +1828,11 @@ wombat: sending conect here: an example connect string from MOHAA looks like thi
|
||||
Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );
|
||||
Info_SetValueForKey( info, "protocol", va("%i", PROTOCOL_VERSION ) );
|
||||
Info_SetValueForKey( info, "qport", va("%i", port ) );
|
||||
Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
|
||||
Info_SetValueForKey(info, "challenge", va("%i", clc.challenge));
|
||||
Info_SetValueForKey(info, "version", TARGET_GAME_VERSION);
|
||||
#if TARGET_GAME_PROTOCOL >= 15
|
||||
Info_SetValueForKey(info, "clientType", "Breakthrough");
|
||||
#endif
|
||||
|
||||
strcpy(data, "connect ");
|
||||
// TTimo adding " " around the userinfo string to avoid truncated userinfo on the server
|
||||
@@ -2093,7 +2091,7 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
|
||||
|
||||
// challenge from the server we are connecting to
|
||||
if ( !Q_stricmp(c, "challengeResponse") ) {
|
||||
if ( cls.state != CA_CONNECTING ) {
|
||||
if ( cls.state != CA_CONNECTING && cls.state != CA_AUTHORIZING ) {
|
||||
Com_Printf( "Unwanted challenge response received. Ignored.\n" );
|
||||
} else {
|
||||
// start sending challenge repsonse instead of challenge request packets
|
||||
@@ -2158,8 +2156,10 @@ void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
|
||||
}
|
||||
|
||||
// cd check
|
||||
if ( !Q_stricmp(c, "keyAuthorize") ) {
|
||||
// we don't use these now, so dump them on the floor
|
||||
if ( !Q_stricmp(c, "getKey") ) {
|
||||
cls.state = CA_AUTHORIZING;
|
||||
gcd_compute_response(cl_cdkey, Cmd_Argv(1), cls.gcdResponse, CDResponseMethod_NEWAUTH);
|
||||
NET_OutOfBandPrint(NS_CLIENT, from, "authorizeThis %s", cls.gcdResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2291,7 +2291,7 @@ qboolean CL_CheckPaused(void)
|
||||
// if paused->modified is set, the cvar has only been changed in
|
||||
// this frame. Keep paused in this frame to ensure the server doesn't
|
||||
// lag behind.
|
||||
if(paused->integer || paused->modified)
|
||||
if(paused->integer)
|
||||
return qtrue;
|
||||
|
||||
return qfalse;
|
||||
@@ -2306,6 +2306,8 @@ CL_CheckUserinfo
|
||||
==================
|
||||
*/
|
||||
void CL_CheckUserinfo( void ) {
|
||||
char szSanitizedName[MAX_NAME_LENGTH];
|
||||
|
||||
// don't add reliable commands when not yet connected
|
||||
if(cls.state < CA_CHALLENGING)
|
||||
return;
|
||||
@@ -2317,11 +2319,19 @@ void CL_CheckUserinfo( void ) {
|
||||
// send a reliable userinfo update if needed
|
||||
if(cvar_modifiedFlags & CVAR_USERINFO)
|
||||
{
|
||||
if (Com_SanitizeName(name->string, szSanitizedName)) {
|
||||
Cvar_Set("name", szSanitizedName);
|
||||
}
|
||||
|
||||
cvar_modifiedFlags &= ~CVAR_USERINFO;
|
||||
CL_AddReliableCommand( va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
void CL_SetFrameNumber(int frameNumber) {
|
||||
re.SetFrameNumber(frameNumber);
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_Frame
|
||||
@@ -2346,14 +2356,13 @@ void CL_Frame ( int msec ) {
|
||||
cls.realtime += cls.frametime;
|
||||
SCR_UpdateScreen();
|
||||
S_Update();
|
||||
Con_RunConsole();
|
||||
cls.framecount++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( cls.state == CA_DISCONNECTED && !( Key_GetCatcher( ) & KEYCATCH_UI )
|
||||
if ( cls.state == CA_DISCONNECTED && !UI_MenuActive()
|
||||
&& !com_sv_running->integer ) {
|
||||
// if disconnected, bring up the menu
|
||||
S_StopAllSounds( qtrue );
|
||||
@@ -2461,8 +2470,6 @@ void CL_Frame ( int msec ) {
|
||||
// advance local effects for next frame
|
||||
SCR_RunCinematic();
|
||||
|
||||
Con_RunConsole();
|
||||
|
||||
cls.framecount++;
|
||||
}
|
||||
|
||||
@@ -2480,16 +2487,18 @@ void QDECL CL_RefPrintf( int print_level, const char *fmt, ...) {
|
||||
va_list argptr;
|
||||
char msg[MAXPRINTMSG];
|
||||
|
||||
va_start (argptr,fmt);
|
||||
Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
|
||||
va_end (argptr);
|
||||
va_start(argptr, fmt);
|
||||
Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if ( print_level == PRINT_ALL ) {
|
||||
Com_Printf ("%s", msg);
|
||||
} else if ( print_level == PRINT_WARNING ) {
|
||||
Com_Printf (S_COLOR_YELLOW "%s", msg); // yellow
|
||||
} else if ( print_level == PRINT_DEVELOPER ) {
|
||||
Com_DPrintf (S_COLOR_RED "%s", msg); // red
|
||||
if (print_level == PRINT_ALL) {
|
||||
Com_Printf("%s", msg);
|
||||
}
|
||||
else if (print_level == PRINT_WARNING || print_level == PRINT_DEVELOPER) {
|
||||
Com_DPrintf("%s", msg);
|
||||
}
|
||||
else if (print_level == PRINT_DEVELOPER_2 && developer->integer) {
|
||||
Com_DPrintf("%s", msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2528,27 +2537,6 @@ void CL_ShutdownRef( void ) {
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
CL_InitRenderer
|
||||
============
|
||||
*/
|
||||
void CL_InitRenderer( void ) {
|
||||
// this sets up the renderer and calls R_Init
|
||||
re.BeginRegistration( &cls.glconfig );
|
||||
|
||||
// load character sets
|
||||
cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" );
|
||||
cls.whiteShader = re.RegisterShader( "*white" );
|
||||
// cls.consoleShader = re.RegisterShader( "console" );
|
||||
re.RegisterFont("courier-16", 0, &cls.consoleFont);
|
||||
g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
|
||||
g_consoleField.widthInChars = g_console_field_width;
|
||||
// IneQuation
|
||||
g_console_charWidth = re.Text_Width(&cls.consoleFont, "=", 0, qfalse);
|
||||
g_console_charHeight = re.Text_Height(&cls.consoleFont, "|", 0, qfalse);
|
||||
}
|
||||
|
||||
/*
|
||||
============================
|
||||
CL_StartHunkUsers
|
||||
@@ -2588,7 +2576,7 @@ void CL_StartHunkUsers( void ) {
|
||||
CL_RefMalloc
|
||||
============
|
||||
*/
|
||||
void *CL_RefMalloc( int size ) {
|
||||
void *CL_RefMalloc(size_t size) {
|
||||
return Z_TagMalloc( size, TAG_RENDERER );
|
||||
}
|
||||
|
||||
@@ -2607,7 +2595,7 @@ void CL_RefClear( void )
|
||||
CL_RefStaticMalloc
|
||||
============
|
||||
*/
|
||||
void *CL_RefStaticMalloc( int size ) {
|
||||
void *CL_RefStaticMalloc( size_t size ) {
|
||||
void *ptr = Z_TagMalloc( size, TAG_STATIC_RENDERER );
|
||||
Com_Memset( ptr, 0, size );
|
||||
return ptr;
|
||||
@@ -2627,7 +2615,7 @@ void CL_RefStaticClear( void ) {
|
||||
CL_CG_PermanentMark
|
||||
============
|
||||
*/
|
||||
int CL_CG_PermanentMark( vec3_t origin, vec3_t dir, float orientation,
|
||||
int CL_CG_PermanentMark(const vec3_t origin, const vec3_t dir, float orientation,
|
||||
float fSScale, float fTScale, float red, float green, float blue, float alpha,
|
||||
qboolean dolighting, float fSCenter, float fTCenter,
|
||||
markFragment_t *pMarkFragments, void *pPolyVerts )
|
||||
@@ -2720,14 +2708,17 @@ void CL_InitRef( void ) {
|
||||
ri.Malloc = CL_RefMalloc;
|
||||
ri.Free = Z_Free;
|
||||
ri.Clear = CL_RefClear;
|
||||
ri.Hunk_Clear = CL_RefStaticClear;
|
||||
ri.Hunk_Alloc = Hunk_Alloc;
|
||||
ri.Hunk_Clear = CL_RefStaticClear;
|
||||
#ifdef HUNK_DEBUG
|
||||
ri.Hunk_AllocDebug = Hunk_AllocDebug;
|
||||
#else
|
||||
ri.Hunk_Alloc = CL_RefStaticMalloc;
|
||||
#endif
|
||||
ri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;
|
||||
ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
|
||||
ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
|
||||
ri.CM_ClusterPVS = CM_ClusterPVS;
|
||||
|
||||
ri.FS_FOpenFile = FS_FOpenFileRead;
|
||||
ri.FS_OpenFile = FS_FOpenFileRead;
|
||||
ri.FS_CloseFile = FS_FCloseFile;
|
||||
ri.FS_Read = FS_Read;
|
||||
ri.FS_Seek = FS_Seek;
|
||||
@@ -2767,18 +2758,6 @@ void CL_InitRef( void ) {
|
||||
ri.GetCentroidRadiusInternal = TIKI_GetCentroidRadiusInternal;
|
||||
ri.GetFrameInternal = TIKI_GetFrameInternal;
|
||||
|
||||
// cinematic stuff
|
||||
|
||||
ri.CIN_UploadCinematic = CIN_UploadCinematic;
|
||||
ri.CIN_PlayCinematic = CIN_PlayCinematic;
|
||||
ri.CIN_RunCinematic = CIN_RunCinematic;
|
||||
|
||||
ri.CL_WriteAVIVideoFrame = CL_WriteAVIVideoFrame;
|
||||
|
||||
ri.IN_Init = IN_Init;
|
||||
ri.IN_Shutdown = IN_Shutdown;
|
||||
//ri.IN_Restart = IN_Restart;
|
||||
|
||||
#ifdef USE_RENDERER_DLL
|
||||
// su44: load renderer dll
|
||||
cl_renderer = Cvar_Get("cl_renderer", "glom", CVAR_ARCHIVE);
|
||||
@@ -2847,27 +2826,13 @@ qboolean CL_SetVidMode( int mode ) {
|
||||
}
|
||||
|
||||
void CL_SetFullscreen( qboolean fullscreen ) {
|
||||
re.SetFullscreen( fullscreen, &cls.glconfig );
|
||||
re.SetFullscreen( fullscreen );
|
||||
|
||||
if( cge ) {
|
||||
cge->CG_GetRendererConfig();
|
||||
}
|
||||
}
|
||||
|
||||
void CL_SetModel_f( void ) {
|
||||
char *arg;
|
||||
char name[256];
|
||||
|
||||
arg = Cmd_Argv( 1 );
|
||||
if (arg[0]) {
|
||||
Cvar_Set( "model", arg );
|
||||
Cvar_Set( "headmodel", arg );
|
||||
} else {
|
||||
Cvar_VariableStringBuffer( "model", name, sizeof(name) );
|
||||
Com_Printf("model is set to %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
void CL_VidMode_f( void ) {
|
||||
char text[ 16 ];
|
||||
int mode;
|
||||
@@ -2994,6 +2959,8 @@ it by filling it with 2048 bytes of random data.
|
||||
*/
|
||||
static void CL_GenerateQKey(void)
|
||||
{
|
||||
// FIXME: unimplemented
|
||||
/*
|
||||
int len = 0;
|
||||
unsigned char buff[ QKEY_SIZE ];
|
||||
fileHandle_t f;
|
||||
@@ -3023,6 +2990,7 @@ static void CL_GenerateQKey(void)
|
||||
FS_FCloseFile( f );
|
||||
Com_Printf( "QKEY generated\n" );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3043,13 +3011,11 @@ void CL_Init( void ) {
|
||||
|
||||
start = Sys_Milliseconds();
|
||||
|
||||
Con_Init ();
|
||||
|
||||
CL_ClearState ();
|
||||
S_StopAllSounds( qtrue );
|
||||
|
||||
cls.state = CA_DISCONNECTED; // no longer CA_UNINITIALIZED
|
||||
cls.keyCatchers = 2;
|
||||
Key_SetCatcher(KEYCATCH_UI);
|
||||
cls.realtime = 0;
|
||||
|
||||
CL_InitInput ();
|
||||
@@ -3158,7 +3124,7 @@ void CL_Init( void ) {
|
||||
cl_consoleKeys = Cvar_Get( "cl_consoleKeys", "~ ` 0x7e 0x60", CVAR_ARCHIVE );
|
||||
|
||||
// userinfo
|
||||
Cvar_Get ("name", "UnnamedSoldier", CVAR_USERINFO | CVAR_ARCHIVE );
|
||||
name = Cvar_Get ("name", "UnnamedSoldier", CVAR_USERINFO | CVAR_ARCHIVE );
|
||||
Cvar_Get ("rate", "5000", CVAR_USERINFO | CVAR_ARCHIVE );
|
||||
Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE );
|
||||
Cvar_Get ("password", "", CVAR_USERINFO);
|
||||
@@ -3208,7 +3174,6 @@ void CL_Init( void ) {
|
||||
Cmd_AddCommand ("showip", CL_ShowIP_f );
|
||||
Cmd_AddCommand ("fs_openedList", CL_OpenedPK3List_f );
|
||||
Cmd_AddCommand ("fs_referencedList", CL_ReferencedPK3List_f );
|
||||
Cmd_AddCommand ("model", CL_SetModel_f );
|
||||
Cmd_AddCommand ("video", CL_Video_f );
|
||||
Cmd_AddCommand ("stopvideo", CL_StopVideo_f );
|
||||
CL_InitConsoleCommands();
|
||||
@@ -3292,10 +3257,9 @@ void CL_Shutdown( void ) {
|
||||
|
||||
recursive = qfalse;
|
||||
|
||||
Com_Memset( &cls, 0, sizeof( cls ) );
|
||||
Key_SetCatcher( 0 );
|
||||
|
||||
Com_Printf( "-----------------------\n" );
|
||||
Z_FreeTags(TAG_CLIENT);
|
||||
cl_bCLSystemStarted = qfalse;
|
||||
|
||||
}
|
||||
|
||||
@@ -3353,7 +3317,7 @@ CL_ServerInfoPacket
|
||||
void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
|
||||
int i, type;
|
||||
char info[MAX_INFO_STRING];
|
||||
char* str;
|
||||
const char* str;
|
||||
char *infoString;
|
||||
int prot;
|
||||
|
||||
@@ -3549,10 +3513,10 @@ CL_ServerStatusResponse
|
||||
===================
|
||||
*/
|
||||
void CL_ServerStatusResponse( netadr_t from, msg_t *msg ) {
|
||||
char *s;
|
||||
const char *s;
|
||||
char info[MAX_INFO_STRING];
|
||||
int i, l, score, ping;
|
||||
int len;
|
||||
size_t len;
|
||||
serverStatus_t *serverStatus;
|
||||
|
||||
serverStatus = NULL;
|
||||
@@ -3642,7 +3606,7 @@ CL_LocalServers_f
|
||||
==================
|
||||
*/
|
||||
void CL_LocalServers_f( void ) {
|
||||
char *message;
|
||||
const char *message;
|
||||
int i, j;
|
||||
netadr_t to;
|
||||
|
||||
@@ -3688,6 +3652,8 @@ CL_GamespyServers_f
|
||||
#define MAX_GAMESPYSERVERS 16
|
||||
|
||||
void CL_GamespyServers_f( void ) {
|
||||
// FIXME: unimplemented
|
||||
#if 0
|
||||
char buffer[10240];
|
||||
int bytesRead;
|
||||
|
||||
@@ -3793,6 +3759,7 @@ void CL_GamespyServers_f( void ) {
|
||||
Com_Printf("%d servers parsed (total %d)\n", numservers, total);
|
||||
Cvar_Set( "dm_serverstatus", "Server List Received.");
|
||||
Cvar_SetValue( "dm_servercount", total );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -4308,7 +4275,8 @@ qboolean CL_CDKeyValidate( const char *key, const char *checksum ) {
|
||||
char ch;
|
||||
byte sum;
|
||||
char chs[3];
|
||||
int i, len;
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
len = strlen(key);
|
||||
if( len != CDKEY_LEN ) {
|
||||
@@ -4363,4 +4331,12 @@ qboolean CL_CDKeyValidate( const char *key, const char *checksum ) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
void TIKI_CG_Command_ProcessFile(char* filename, qboolean quiet, dtiki_t* curTiki)
|
||||
{
|
||||
if (cge) {
|
||||
cge->CG_Command_ProcessFile(filename, quiet, curTiki);
|
||||
return;
|
||||
}
|
||||
|
||||
Com_Printf("NO CGE \n");
|
||||
}
|
||||
+53
-21
@@ -22,8 +22,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
// cl_parse.c -- parse a message received from the server
|
||||
|
||||
#include "client.h"
|
||||
#include "cl_ui.h"
|
||||
|
||||
char *svc_strings[256] = {
|
||||
const char *svc_strings[256] = {
|
||||
"svc_bad",
|
||||
|
||||
"svc_nop",
|
||||
@@ -40,7 +41,7 @@ char *svc_strings[256] = {
|
||||
|
||||
msg_t *cl_currentMSG;
|
||||
|
||||
void SHOWNET( msg_t *msg, char *s) {
|
||||
void SHOWNET( msg_t *msg, const char *s) {
|
||||
if ( cl_shownet->integer >= 2) {
|
||||
Com_Printf ("%3i:%s\n", msg->readcount-1, s);
|
||||
}
|
||||
@@ -74,7 +75,7 @@ void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t
|
||||
if ( unchanged ) {
|
||||
*state = *old;
|
||||
} else {
|
||||
MSG_ReadDeltaEntity( msg, old, state, newnum );
|
||||
MSG_ReadDeltaEntity( msg, old, state, newnum, cls.serverFrameTime);
|
||||
}
|
||||
|
||||
if ( state->number == (MAX_GENTITIES-1) ) {
|
||||
@@ -115,7 +116,7 @@ void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *n
|
||||
|
||||
while ( 1 ) {
|
||||
// read the entity index number
|
||||
newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
|
||||
newnum = MSG_ReadEntityNum(msg);
|
||||
|
||||
if ( newnum == (MAX_GENTITIES-1) ) {
|
||||
break;
|
||||
@@ -271,11 +272,11 @@ void CL_ParseSnapshot( msg_t *msg ) {
|
||||
MSG_ReadData( msg, &newSnap.areamask, len);
|
||||
|
||||
// read playerinfo
|
||||
SHOWNET( msg, "playerstate" );
|
||||
SHOWNET(msg, "playerstate");
|
||||
if ( old ) {
|
||||
MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
|
||||
MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps, cls.serverFrameTime );
|
||||
} else {
|
||||
MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
|
||||
MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps, cls.serverFrameTime);
|
||||
}
|
||||
|
||||
// read packet entities
|
||||
@@ -443,6 +444,28 @@ static void CL_ParseServerInfo(void)
|
||||
sizeof(clc.sv_dlURL));
|
||||
}
|
||||
|
||||
#if TARGET_GAME_PROTOCOL >= 15
|
||||
|
||||
char* MSG_ReadGameStateChar(msg_t* msg) {
|
||||
return MSG_ReadScrambledBigString(msg);
|
||||
}
|
||||
|
||||
float MSG_ReadServerFrameTime(msg_t* msg) {
|
||||
return MSG_ReadFloat(msg);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char* MSG_ReadGameStateChar(msg_t* msg) {
|
||||
return MSG_ReadString(msg);
|
||||
}
|
||||
|
||||
float MSG_ReadServerFrameTime(msg_t* msg) {
|
||||
return 1.f / atof(Info_ValueForKey(cl.gameState.stringData + cl.gameState.stringOffsets[CS_SYSTEMINFO], "sv_fps"));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
==================
|
||||
CL_ParseGamestate
|
||||
@@ -456,9 +479,12 @@ void CL_ParseGamestate( msg_t *msg ) {
|
||||
int cmd;
|
||||
char *s;
|
||||
|
||||
Con_Close();
|
||||
UI_CloseConsole();
|
||||
|
||||
clc.connectPacketCount = 0;
|
||||
if (cls.cgameStarted) {
|
||||
CL_FlushMemory();
|
||||
}
|
||||
|
||||
// wipe local client state
|
||||
CL_ClearState();
|
||||
@@ -482,7 +508,7 @@ void CL_ParseGamestate( msg_t *msg ) {
|
||||
if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
|
||||
Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
|
||||
}
|
||||
s = MSG_ReadString( msg );
|
||||
s = MSG_ReadGameStateChar( msg );
|
||||
len = strlen( s );
|
||||
|
||||
if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
|
||||
@@ -493,14 +519,15 @@ void CL_ParseGamestate( msg_t *msg ) {
|
||||
Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
|
||||
cl.gameState.dataCount += len + 1;
|
||||
} else if ( cmd == svc_baseline ) {
|
||||
newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
|
||||
newnum = MSG_ReadEntityNum(msg);
|
||||
if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
|
||||
Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
|
||||
}
|
||||
//Com_Memset (&nullstate, 0, sizeof(nullstate));
|
||||
MSG_GetNullEntityState(&nullstate);
|
||||
es = &cl.entityBaselines[ newnum ];
|
||||
MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
|
||||
// FIXME: frametime
|
||||
MSG_ReadDeltaEntity( msg, &nullstate, es, newnum, 0.0);
|
||||
} else {
|
||||
Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte %i", cmd );
|
||||
}
|
||||
@@ -509,9 +536,7 @@ void CL_ParseGamestate( msg_t *msg ) {
|
||||
clc.clientNum = MSG_ReadLong(msg);
|
||||
// read the checksum feed
|
||||
clc.checksumFeed = MSG_ReadLong( msg );
|
||||
|
||||
// parse useful values out of CS_SERVERINFO
|
||||
CL_ParseServerInfo();
|
||||
cls.serverFrameTime = MSG_ReadServerFrameTime(msg);
|
||||
|
||||
// parse serverId and other cvars
|
||||
CL_SystemInfoChanged();
|
||||
@@ -523,6 +548,14 @@ void CL_ParseGamestate( msg_t *msg ) {
|
||||
// reinitialize the filesystem if the game directory has changed
|
||||
FS_ConditionalRestart( clc.checksumFeed );
|
||||
|
||||
cls.state = CA_LOADING;
|
||||
if (!com_sv_running->integer)
|
||||
{
|
||||
const char *info = cl.gameState.stringData + cl.gameState.stringOffsets[CS_SERVERINFO];
|
||||
UI_ClearState();
|
||||
UI_BeginLoad(Info_ValueForKey(info, "mapname"));
|
||||
}
|
||||
|
||||
// This used to call CL_StartHunkUsers, but now we enter the download state before loading the
|
||||
// cgame
|
||||
CL_InitDownloads();
|
||||
@@ -715,7 +748,7 @@ void CL_ParseCommandString( msg_t *msg ) {
|
||||
int index;
|
||||
|
||||
seq = MSG_ReadLong( msg );
|
||||
s = MSG_ReadString( msg );
|
||||
s = MSG_ReadScrambledString( msg );
|
||||
|
||||
// see if we have already executed stored it off
|
||||
if ( clc.serverCommandSequence >= seq ) {
|
||||
@@ -752,10 +785,9 @@ void CL_ParseLocationprint( msg_t *msg ) {
|
||||
|
||||
x = MSG_ReadShort( msg );
|
||||
y = MSG_ReadShort( msg );
|
||||
string = MSG_ReadString(msg);
|
||||
string = MSG_ReadScrambledString(msg);
|
||||
|
||||
// FIXME
|
||||
//UI_UpdateLocationPrint( x, y, string, 1.0 );
|
||||
UI_UpdateLocationPrint( x, y, string, 1.0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -766,10 +798,10 @@ CL_ParseCenterprint
|
||||
void CL_ParseCenterprint( msg_t *msg ) {
|
||||
char *string;
|
||||
|
||||
string = MSG_ReadString( msg );
|
||||
string = MSG_ReadScrambledString( msg );
|
||||
|
||||
// FIXME
|
||||
//UI_UpdateCenterPrintf( string, 1.0 );
|
||||
UI_UpdateCenterPrint( string, 1.0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -781,7 +813,7 @@ void CL_ParseServerMessage( msg_t *msg ) {
|
||||
int cmd;
|
||||
//Com_Printf( "ParseServerMessage: %i\n", msg->cursize );
|
||||
if ( cl_shownet->integer == 1 ) {
|
||||
Com_Printf ("%i ",msg->cursize);
|
||||
Com_Printf ("%zu ",msg->cursize);
|
||||
} else if ( cl_shownet->integer >= 2 ) {
|
||||
Com_Printf ("------------------\n");
|
||||
}
|
||||
|
||||
@@ -535,7 +535,7 @@ void SCR_UpdateScreen( void ) {
|
||||
return;
|
||||
}
|
||||
recursive = 1;
|
||||
|
||||
|
||||
CL_StartHunkUsers();
|
||||
SCR_SimpleUpdateScreen();
|
||||
|
||||
|
||||
-1212
File diff suppressed because it is too large.
Load diff
+778
-745
File diff suppressed because it is too large.
Load diff
+4
-2
@@ -42,11 +42,12 @@ void CL_ShutdownUI( void );
|
||||
//
|
||||
extern inventory_t client_inv;
|
||||
extern bind_t client_bind;
|
||||
extern cvar_t* cl_greenfps;
|
||||
|
||||
const char *CvarGetForUI( const char *name, const char *defval );
|
||||
void UI_ClearState( void );
|
||||
void CL_BeginRegistration( void );
|
||||
void CL_EndRegistration( void );
|
||||
void CL_EndRegistration(void);
|
||||
|
||||
//
|
||||
// menu
|
||||
@@ -72,7 +73,7 @@ void UI_HideScoreboard_f( void );
|
||||
void UI_SetScoreBoardItem( int iItemNumber,
|
||||
const char *pszData1, const char *pszData2, const char *pszData3, const char *pszData4,
|
||||
const char *pszData5, const char *pszData6, const char *pszData7, const char *pszData8,
|
||||
vec4_t pTextColor, vec4_t pBackColor, qboolean bIsHeader );
|
||||
const vec4_t pTextColor, const vec4_t pBackColor, qboolean bIsHeader );
|
||||
void UI_DeleteScoreBoardItems( int iMaxIndex );
|
||||
|
||||
//
|
||||
@@ -107,6 +108,7 @@ void UI_CloseDMConsole( void );
|
||||
void UI_ToggleDMConsole( int iMode );
|
||||
void UI_OpenDeveloperConsole( void );
|
||||
void UI_CloseDeveloperConsole( void );
|
||||
void UI_PrintConsole(const char* msg);
|
||||
|
||||
//
|
||||
// callbacks
|
||||
|
||||
+318
-21
@@ -22,100 +22,397 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#include "cl_ui.h"
|
||||
|
||||
Event EV_DMBox_Goin
|
||||
(
|
||||
"_dmbox_goin",
|
||||
EV_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
"Event to make the dmbox disappear"
|
||||
);
|
||||
|
||||
Event EV_DMBox_Decay
|
||||
(
|
||||
"_dmbox_decay",
|
||||
EV_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
"Event to make the dmbox console line decay"
|
||||
);
|
||||
|
||||
static float s_dmboxWidth = 384.0;
|
||||
|
||||
CLASS_DECLARATION( UIWidget, UIDMBox, NULL )
|
||||
{
|
||||
{ &W_SizeChanged, &UIDMBox::OnSizeChanged },
|
||||
{ &EV_DMBox_Goin, &UIDMBox::MoveInEvent },
|
||||
{ &EV_DMBox_Decay, &UIDMBox::DecayEvent },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
UIDMBox::UIDMBox()
|
||||
{
|
||||
m_numitems = 0;
|
||||
m_reallyshown = true;
|
||||
m_fontbold = NULL;
|
||||
m_boxstate = boxstate_t::box_out;
|
||||
m_iBeginDecay = 0;
|
||||
m_boxtime = uid.time;
|
||||
m_movespeed = 500;
|
||||
}
|
||||
|
||||
void UIDMBox::VerifyBoxOut( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
PostMoveinEvent();
|
||||
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_out)
|
||||
{
|
||||
ChangeBoxState(boxstate_t::box_moving_out);
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::ChangeBoxState( boxstate_t state )
|
||||
{
|
||||
// FIXME: stub
|
||||
m_boxstate = state;
|
||||
m_boxtime = uid.time;
|
||||
setShowState();
|
||||
|
||||
if (state == box_out) {
|
||||
PostMoveinEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::HandleBoxMoving( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
int delta;
|
||||
UIRect2D newRect;
|
||||
|
||||
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_moving_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
delta = m_movespeed * (uid.time - m_boxtime) / 1000;
|
||||
m_boxtime = 1000 * delta / m_movespeed + m_boxtime;
|
||||
if (m_boxstate == boxstate_t::box_moving_out)
|
||||
{
|
||||
newRect.size.width = m_frame.size.width;
|
||||
newRect.size.height = m_frame.size.height;
|
||||
newRect.pos.x = m_frame.pos.x;
|
||||
newRect.pos.y = delta + m_frame.pos.y;
|
||||
|
||||
if (newRect.pos.y <= 0.0)
|
||||
{
|
||||
newRect.pos.y = 0.0;
|
||||
ChangeBoxState(boxstate_t::box_out);
|
||||
}
|
||||
}
|
||||
else if (m_boxstate == boxstate_t::box_moving_in)
|
||||
{
|
||||
newRect.size.width = m_frame.size.width;
|
||||
newRect.size.height = m_frame.size.height;
|
||||
newRect.pos.x = m_frame.pos.x;
|
||||
newRect.pos.y = delta - m_frame.pos.y;
|
||||
|
||||
if (newRect.pos.y <= -newRect.size.height)
|
||||
{
|
||||
newRect.pos.y = -newRect.size.height;
|
||||
ChangeBoxState(boxstate_t::box_in);
|
||||
}
|
||||
}
|
||||
else {
|
||||
newRect = m_frame;
|
||||
}
|
||||
|
||||
setFrame(newRect);
|
||||
}
|
||||
|
||||
void UIDMBox::PostMoveinEvent( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
if (m_boxstate != boxstate_t::box_out) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EventPending(EV_DMBox_Goin)) {
|
||||
PostEvent(EV_DMBox_Goin, 10.0);
|
||||
}
|
||||
else {
|
||||
PostponeEvent(EV_DMBox_Goin, 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::PostDecayEvent( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
if (!EventPending(EV_DMBox_Decay))
|
||||
{
|
||||
float fDelayTime;
|
||||
int iNumLines;
|
||||
int i;
|
||||
const char* pszString = m_items[0].string.c_str();
|
||||
|
||||
//
|
||||
// Calculate the number of lines
|
||||
//
|
||||
iNumLines = 1;
|
||||
for (i = 0; pszString[i]; i++)
|
||||
{
|
||||
if (pszString[i] == '\n') {
|
||||
iNumLines++;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Bold as twice more decay
|
||||
//
|
||||
if (m_items[0].flags & DMBOX_ITEM_FLAG_BOLD) {
|
||||
fDelayTime = iNumLines * 6.0;
|
||||
}
|
||||
else {
|
||||
fDelayTime = iNumLines * 5.0;
|
||||
}
|
||||
|
||||
m_iBeginDecay = cls.realtime;
|
||||
m_iEndDecay = (int)(fDelayTime * 1000.0);
|
||||
|
||||
PostEvent(EV_DMBox_Decay, fDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::setShowState( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
if (m_reallyshown) {
|
||||
setShow(m_boxstate != box_in);
|
||||
} else {
|
||||
setShow(false);
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::RemoveTopItem( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
int i;
|
||||
|
||||
if (m_numitems > 0) {
|
||||
for (i = 0; i < m_numitems - 1; i++) {
|
||||
m_items[i] = m_items[i + 1];
|
||||
}
|
||||
|
||||
m_numitems--;
|
||||
}
|
||||
}
|
||||
|
||||
str UIDMBox::CalculateBreaks( UIFont *font, str text, float max_width )
|
||||
{
|
||||
// FIXME: stub
|
||||
return "";
|
||||
str newText, sTmp;
|
||||
int i;
|
||||
float fX;
|
||||
float fwX, fsX;
|
||||
|
||||
Cmd_TokenizeString(text.c_str());
|
||||
if (Cmd_Argc())
|
||||
{
|
||||
fX = 0.0;
|
||||
fsX = font->getCharWidth(' ');
|
||||
|
||||
for (i = 0; i < Cmd_Argc(); i++)
|
||||
{
|
||||
sTmp = Cmd_Argv(i);
|
||||
|
||||
fwX = font->getWidth(sTmp.c_str(), -1);
|
||||
if (fwX + i <= max_width)
|
||||
{
|
||||
if (fwX + i + fX <= max_width)
|
||||
{
|
||||
newText += sTmp + " ";
|
||||
} else {
|
||||
newText += "\n" + sTmp + " ";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sTmp += "\n";
|
||||
fX = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newText = "";
|
||||
}
|
||||
|
||||
return newText;
|
||||
}
|
||||
|
||||
float UIDMBox::PrintWrap( UIFont *font, float x, float y, str text )
|
||||
{
|
||||
// FIXME: stub
|
||||
return 0.0f;
|
||||
const char* p1, * p2;
|
||||
size_t n, l;
|
||||
float fY;
|
||||
|
||||
fY = y;
|
||||
p1 = text.c_str();
|
||||
l = text.length();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
p2 = strchr(p1, '\n');
|
||||
if (!p2) {
|
||||
break;
|
||||
}
|
||||
|
||||
n = p2 - p1;
|
||||
if (n >= l) {
|
||||
break;
|
||||
}
|
||||
|
||||
font->Print(x, fY, p1, p2 - p1, qfalse);
|
||||
p1 = p2 + 1;
|
||||
l -= n;
|
||||
fY += font->getHeight(qfalse);
|
||||
}
|
||||
|
||||
font->Print(x, fY, p1, l, qfalse);
|
||||
|
||||
return font->getHeight(qfalse) + (fY - y);
|
||||
}
|
||||
|
||||
float UIDMBox::DrawItem( item_t *in, float x, float y, float alpha )
|
||||
{
|
||||
// FIXME: stub
|
||||
return 0.0f;
|
||||
in->font->setColor(in->color);
|
||||
in->font->setAlpha(alpha);
|
||||
|
||||
return PrintWrap(in->font, x, y, in->string);
|
||||
}
|
||||
|
||||
void UIDMBox::Print( const char *text )
|
||||
{
|
||||
// FIXME: stub
|
||||
const char* text1 = text;
|
||||
|
||||
if (m_numitems > 4)
|
||||
{
|
||||
//
|
||||
// Overwrite an item
|
||||
//
|
||||
RemoveTopItem();
|
||||
}
|
||||
|
||||
m_items[m_numitems].flags = 0;
|
||||
|
||||
if (*text == 2)
|
||||
{
|
||||
m_items[m_numitems].color = UGrey;
|
||||
m_items[m_numitems].font = m_fontbold;
|
||||
m_items[m_numitems].flags |= GMBOX_ITEM_FLAG_BOLD;
|
||||
|
||||
text1 = text + 1;
|
||||
}
|
||||
else if (*text == 4)
|
||||
{
|
||||
m_items[m_numitems].color = ULightRed;
|
||||
m_items[m_numitems].font = m_fontbold;
|
||||
m_items[m_numitems].flags |= GMBOX_ITEM_FLAG_BOLD;
|
||||
|
||||
text1 = text + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_items[m_numitems].color = m_foreground_color;
|
||||
m_items[m_numitems].font = m_font;
|
||||
}
|
||||
|
||||
m_items[m_numitems].string = CalculateBreaks(m_items[m_numitems].font, text1, s_dmboxWidth);
|
||||
|
||||
m_numitems++;
|
||||
VerifyBoxOut();
|
||||
PostDecayEvent();
|
||||
}
|
||||
|
||||
void UIDMBox::OnSizeChanged( Event *ev )
|
||||
{
|
||||
// FIXME: stub
|
||||
s_dmboxWidth = m_frame.size.width;
|
||||
}
|
||||
|
||||
void UIDMBox::Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha )
|
||||
{
|
||||
// FIXME: stub
|
||||
InitFrame(NULL, rect, 0, "facfont-20");
|
||||
|
||||
if (!m_fontbold) {
|
||||
m_fontbold = new UIFont("facfont-20");
|
||||
}
|
||||
|
||||
m_fontbold->setColor(URed);
|
||||
setBackgroundColor(back, true);
|
||||
setForegroundColor(fore);
|
||||
setBackgroundAlpha(alpha);
|
||||
|
||||
Connect(this, W_SizeChanged, W_SizeChanged);
|
||||
OnSizeChanged(NULL);
|
||||
|
||||
m_movespeed = rect.size.height * 3.0;
|
||||
|
||||
setShowState();
|
||||
}
|
||||
|
||||
void UIDMBox::MoveInEvent( Event *ev )
|
||||
{
|
||||
// FIXME: stub
|
||||
}
|
||||
|
||||
void UIDMBox::DecayEvent( Event *ev )
|
||||
{
|
||||
// FIXME: stub
|
||||
RemoveTopItem();
|
||||
if (m_numitems) {
|
||||
PostDecayEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::Draw( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
float fsY;
|
||||
int i;
|
||||
float alpha;
|
||||
float alphaScale;
|
||||
|
||||
alphaScale = 0.8;
|
||||
HandleBoxMoving();
|
||||
|
||||
if (!m_numitems) {
|
||||
//
|
||||
// Nothing to show
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
m_font->setColor(m_foreground_color);
|
||||
alpha = (float)(cls.realtime - m_iBeginDecay) / (float)m_iEndDecay;
|
||||
if (alpha > 1.0) alpha = 1.0;
|
||||
|
||||
alpha = (1.0 - alpha) * 4.0;
|
||||
if (alpha > 1.0) alpha = 1.0;
|
||||
|
||||
if (cge) {
|
||||
alphaScale = 1.0 - cge->CG_GetObjectiveAlpha();
|
||||
}
|
||||
|
||||
fsY = DrawItem(m_items, 0.0, 8.0, alpha * alphaScale);
|
||||
fsY = alpha <= 0.2 ? 8.0 : fsY + 8.0;
|
||||
|
||||
for (i = 1; i < m_numitems; i++)
|
||||
{
|
||||
fsY += DrawItem(&m_items[i], 0.0, fsY, alphaScale);
|
||||
if (fsY > m_frame.size.height)
|
||||
{
|
||||
if (EventPending(EV_DMBox_Decay)) {
|
||||
CancelEventsOfType(EV_DMBox_Decay);
|
||||
}
|
||||
|
||||
PostEvent(EV_DMBox_Decay, 0.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIDMBox::setRealShow( bool b )
|
||||
{
|
||||
// FIXME: stub
|
||||
this->m_reallyshown = b;
|
||||
setShowState();
|
||||
}
|
||||
|
||||
void UIDMBox::Clear( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
m_numitems = 0;
|
||||
}
|
||||
@@ -23,9 +23,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#ifndef __CL_UIDMBOX_H__
|
||||
#define __CL_UIDMBOX_H__
|
||||
|
||||
static constexpr unsigned int DMBOX_ITEM_FLAG_BOLD = 1u;
|
||||
|
||||
typedef enum { box_moving_out, box_moving_in, box_out, box_in } boxstate_t;
|
||||
|
||||
class UIDMBox : public UIWidget {
|
||||
struct item_t {
|
||||
str string;
|
||||
UColor color;
|
||||
UIFont* font;
|
||||
int flags;
|
||||
};
|
||||
|
||||
protected:
|
||||
item_t m_items[ 10 ];
|
||||
int m_numitems;
|
||||
@@ -54,12 +63,14 @@ protected:
|
||||
float DrawItem( item_t *in, float x, float y, float alpha );
|
||||
|
||||
public:
|
||||
UIDMBox();
|
||||
|
||||
void Print( const char *text );
|
||||
void OnSizeChanged( Event *ev );
|
||||
void Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha );
|
||||
void MoveInEvent( Event *ev );
|
||||
void DecayEvent( Event *ev );
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void setRealShow( bool b );
|
||||
void Clear( void );
|
||||
};
|
||||
|
||||
+303
-22
@@ -22,106 +22,387 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#include "cl_ui.h"
|
||||
|
||||
Event EV_GMBox_Goin
|
||||
(
|
||||
"_gmbox_goin",
|
||||
EV_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
"Event to make the gmbox disappear"
|
||||
);
|
||||
|
||||
Event EV_GMBox_Decay
|
||||
(
|
||||
"_gmbox_decay",
|
||||
EV_DEFAULT,
|
||||
NULL,
|
||||
NULL,
|
||||
"Event to make the gmbox console line decay"
|
||||
);
|
||||
|
||||
static float s_gmboxWidth = 640.0;
|
||||
|
||||
CLASS_DECLARATION( UIWidget, UIGMBox, NULL )
|
||||
{
|
||||
{ &W_SizeChanged, &UIGMBox::OnSizeChanged },
|
||||
{ &EV_GMBox_Goin, &UIGMBox::MoveInEvent },
|
||||
{ &EV_GMBox_Decay, &UIGMBox::DecayEvent },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
UIGMBox::UIGMBox()
|
||||
{
|
||||
// FIXME: stub
|
||||
m_numitems = 0;
|
||||
m_reallyshown = true;
|
||||
m_fontbold = NULL;
|
||||
m_boxstate = boxstate_t::box_out;
|
||||
m_iBeginDecay = 0;
|
||||
m_boxtime = uid.time;
|
||||
m_movespeed = 500;
|
||||
}
|
||||
|
||||
void UIGMBox::VerifyBoxOut( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
PostMoveinEvent();
|
||||
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_out)
|
||||
{
|
||||
ChangeBoxState(boxstate_t::box_moving_out);
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::ChangeBoxState( boxstate_t state )
|
||||
{
|
||||
// FIXME: stub
|
||||
m_boxstate = state;
|
||||
m_boxtime = uid.time;
|
||||
setShowState();
|
||||
|
||||
if (state == box_out) {
|
||||
PostMoveinEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::HandleBoxMoving( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
int delta;
|
||||
UIRect2D newRect;
|
||||
|
||||
if (m_boxstate != boxstate_t::box_moving_out && m_boxstate != boxstate_t::box_moving_in) {
|
||||
return;
|
||||
}
|
||||
|
||||
delta = m_movespeed * (uid.time - m_boxtime) / 1000;
|
||||
m_boxtime = 1000 * delta / m_movespeed + m_boxtime;
|
||||
if (m_boxstate == boxstate_t::box_moving_out)
|
||||
{
|
||||
newRect.size.width = m_frame.size.width;
|
||||
newRect.size.height = m_frame.size.height;
|
||||
newRect.pos.x = m_frame.pos.x;
|
||||
newRect.pos.y = delta + m_frame.pos.y;
|
||||
|
||||
if (newRect.pos.y <= 0.0)
|
||||
{
|
||||
newRect.pos.y = 0.0;
|
||||
ChangeBoxState(boxstate_t::box_out);
|
||||
}
|
||||
}
|
||||
else if (m_boxstate == boxstate_t::box_moving_in)
|
||||
{
|
||||
newRect.size.width = m_frame.size.width;
|
||||
newRect.size.height = m_frame.size.height;
|
||||
newRect.pos.x = m_frame.pos.x;
|
||||
newRect.pos.y = delta - m_frame.pos.y;
|
||||
|
||||
if (newRect.pos.y <= -newRect.size.height)
|
||||
{
|
||||
newRect.pos.y = -newRect.size.height;
|
||||
ChangeBoxState(boxstate_t::box_in);
|
||||
}
|
||||
} else {
|
||||
newRect = m_frame;
|
||||
}
|
||||
|
||||
setFrame(newRect);
|
||||
}
|
||||
|
||||
void UIGMBox::PostMoveinEvent( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
if (m_boxstate != boxstate_t::box_out) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EventPending(EV_GMBox_Goin)) {
|
||||
PostEvent(EV_GMBox_Goin, 10.0);
|
||||
} else {
|
||||
PostponeEvent(EV_GMBox_Goin, 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::PostDecayEvent( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
if (!EventPending(EV_GMBox_Decay))
|
||||
{
|
||||
float fDelayTime;
|
||||
int iNumLines;
|
||||
int i;
|
||||
const char* pszString = m_items[0].string.c_str();
|
||||
|
||||
//
|
||||
// Calculate the number of lines
|
||||
//
|
||||
iNumLines = 1;
|
||||
for (i = 0; pszString[i]; i++)
|
||||
{
|
||||
if (pszString[i] == '\n') {
|
||||
iNumLines++;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Bold as twice more decay
|
||||
//
|
||||
if (m_items[0].flags & GMBOX_ITEM_FLAG_BOLD) {
|
||||
fDelayTime = iNumLines * 10.0;
|
||||
} else {
|
||||
fDelayTime = iNumLines * 5.0;
|
||||
}
|
||||
|
||||
m_iBeginDecay = cls.realtime;
|
||||
m_iEndDecay = (int)(fDelayTime * 1000.0);
|
||||
|
||||
PostEvent(EV_GMBox_Decay, fDelayTime);
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::setShowState( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
if (m_reallyshown) {
|
||||
setShow(m_boxstate != box_in);
|
||||
} else {
|
||||
setShow(false);
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::RemoveTopItem( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
int i;
|
||||
|
||||
if (m_numitems > 0) {
|
||||
for (i = 0; i < m_numitems - 1; i++) {
|
||||
m_items[i] = m_items[i + 1];
|
||||
}
|
||||
|
||||
m_numitems--;
|
||||
}
|
||||
}
|
||||
|
||||
str UIGMBox::CalculateBreaks( UIFont *font, str text, float max_width )
|
||||
{
|
||||
// FIXME: stub
|
||||
return "";
|
||||
str newText, sTmp;
|
||||
int i;
|
||||
float fX;
|
||||
float fwX, fsX;
|
||||
|
||||
Cmd_TokenizeString(text.c_str());
|
||||
if (Cmd_Argc())
|
||||
{
|
||||
fX = 0.0;
|
||||
fsX = font->getCharWidth(' ');
|
||||
|
||||
for (i = 0; i < Cmd_Argc(); i++)
|
||||
{
|
||||
sTmp = Cmd_Argv(i);
|
||||
|
||||
fwX = font->getWidth(sTmp.c_str(), -1);
|
||||
if (fwX + i <= max_width)
|
||||
{
|
||||
if (fwX + i + fX <= max_width)
|
||||
{
|
||||
newText += sTmp + " ";
|
||||
} else {
|
||||
newText += "\n" + sTmp + " ";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sTmp += "\n";
|
||||
fX = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newText = "";
|
||||
}
|
||||
|
||||
return newText;
|
||||
}
|
||||
|
||||
float UIGMBox::PrintWrap( UIFont *font, float x, float y, str text )
|
||||
{
|
||||
// FIXME: stub
|
||||
return 0.0f;
|
||||
const char* p1, * p2;
|
||||
size_t n, l;
|
||||
float fY;
|
||||
|
||||
fY = y;
|
||||
p1 = text.c_str();
|
||||
l = text.length();
|
||||
|
||||
for (;;)
|
||||
{
|
||||
p2 = strchr(p1, '\n');
|
||||
if (!p2) {
|
||||
break;
|
||||
}
|
||||
|
||||
n = p2 - p1;
|
||||
if (n >= l) {
|
||||
break;
|
||||
}
|
||||
|
||||
font->Print(x, fY, p1, p2 - p1, qfalse);
|
||||
p1 = p2 + 1;
|
||||
l -= n;
|
||||
fY += font->getHeight(qfalse);
|
||||
}
|
||||
|
||||
font->Print(x, fY, p1, l, qfalse);
|
||||
|
||||
return font->getHeight(qfalse) + (fY - y);
|
||||
}
|
||||
|
||||
float UIGMBox::DrawItem( item_t *in, float x, float y, float alpha )
|
||||
{
|
||||
// FIXME: stub
|
||||
return 0.0f;
|
||||
in->font->setColor(in->color);
|
||||
in->font->setAlpha(alpha);
|
||||
|
||||
return PrintWrap(in->font, x, y, in->string);
|
||||
}
|
||||
|
||||
void UIGMBox::Print( const char *text )
|
||||
{
|
||||
// FIXME: stub
|
||||
const char* text1 = text;
|
||||
|
||||
if (m_numitems > 4)
|
||||
{
|
||||
//
|
||||
// Overwrite an item
|
||||
//
|
||||
RemoveTopItem();
|
||||
}
|
||||
|
||||
m_items[m_numitems].flags = 0;
|
||||
|
||||
if (*text == 3)
|
||||
{
|
||||
m_items[m_numitems].color = UWhite;
|
||||
m_items[m_numitems].font = m_fontbold;
|
||||
m_items[m_numitems].flags |= GMBOX_ITEM_FLAG_BOLD;
|
||||
|
||||
text1 = text + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_items[m_numitems].color = m_foreground_color;
|
||||
m_items[m_numitems].font = m_font;
|
||||
}
|
||||
|
||||
m_items[m_numitems].string = CalculateBreaks(m_items[m_numitems].font, text1, s_gmboxWidth);
|
||||
|
||||
m_numitems++;
|
||||
VerifyBoxOut();
|
||||
PostDecayEvent();
|
||||
}
|
||||
|
||||
void UIGMBox::OnSizeChanged( Event *ev )
|
||||
{
|
||||
// FIXME: stub
|
||||
s_gmboxWidth = m_frame.size.width;
|
||||
}
|
||||
|
||||
void UIGMBox::Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha )
|
||||
{
|
||||
// FIXME: stub
|
||||
InitFrame(NULL, rect, 0, "facfont-20");
|
||||
|
||||
if (!m_fontbold) {
|
||||
m_fontbold = new UIFont("facfont-20");
|
||||
}
|
||||
|
||||
m_fontbold->setColor(URed);
|
||||
setBackgroundColor(back, true);
|
||||
setForegroundColor(fore);
|
||||
setBackgroundAlpha(alpha);
|
||||
|
||||
Connect(this, W_SizeChanged, W_SizeChanged);
|
||||
OnSizeChanged(NULL);
|
||||
|
||||
m_movespeed = rect.size.height * 3.0;
|
||||
|
||||
setShowState();
|
||||
}
|
||||
|
||||
void UIGMBox::MoveInEvent( Event *ev )
|
||||
{
|
||||
// FIXME: stub
|
||||
}
|
||||
|
||||
void UIGMBox::DecayEvent( Event *ev )
|
||||
{
|
||||
// FIXME: stub
|
||||
RemoveTopItem();
|
||||
if (m_numitems) {
|
||||
PostDecayEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::Draw( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
float fsY;
|
||||
int i;
|
||||
float alpha;
|
||||
float alphaScale;
|
||||
|
||||
alphaScale = 1.0;
|
||||
HandleBoxMoving();
|
||||
|
||||
if (!m_numitems) {
|
||||
//
|
||||
// Nothing to show
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
m_font->setColor(m_foreground_color);
|
||||
alpha = (float)(cls.realtime - m_iBeginDecay) / (float)m_iEndDecay;
|
||||
if (alpha > 1.0) alpha = 1.0;
|
||||
|
||||
alpha = (1.0 - alpha) * 4.0;
|
||||
if (alpha > 1.0) alpha = 1.0;
|
||||
|
||||
if (cge) {
|
||||
alphaScale = 1.0 - cge->CG_GetObjectiveAlpha();
|
||||
}
|
||||
|
||||
fsY = DrawItem(m_items, 0.0, 120.0, alpha * alphaScale);
|
||||
fsY = alpha <= 0.2 ? 120.0 : fsY + 120.0;
|
||||
|
||||
for (i = 1; i < m_numitems; i++)
|
||||
{
|
||||
fsY += DrawItem(&m_items[i], 0.0, fsY, alphaScale);
|
||||
if (fsY > m_frame.size.height)
|
||||
{
|
||||
if (EventPending(EV_GMBox_Decay)) {
|
||||
CancelEventsOfType(EV_GMBox_Decay);
|
||||
}
|
||||
|
||||
PostEvent(EV_GMBox_Decay, 0.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIGMBox::setRealShow( bool b )
|
||||
{
|
||||
// FIXME: stub
|
||||
this->m_reallyshown = b;
|
||||
setShowState();
|
||||
}
|
||||
|
||||
void UIGMBox::Clear( void )
|
||||
{
|
||||
// FIXME: stub
|
||||
m_numitems = 0;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#ifndef __CL_UIGMBOX_H__
|
||||
#define __CL_UIGMBOX_H__
|
||||
|
||||
static constexpr unsigned int GMBOX_ITEM_FLAG_BOLD = 1u;
|
||||
|
||||
class UIGMBox : public UIWidget {
|
||||
struct item_t {
|
||||
str string;
|
||||
UColor color;
|
||||
UIFont* font;
|
||||
int flags;
|
||||
};
|
||||
|
||||
protected:
|
||||
item_t m_items[ 5 ];
|
||||
int m_numitems;
|
||||
@@ -59,7 +68,7 @@ public:
|
||||
void Create( const UIRect2D& rect, const UColor& fore, const UColor& back, float alpha );
|
||||
void MoveInEvent( Event *ev );
|
||||
void DecayEvent( Event *ev );
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void setRealShow( bool b );
|
||||
void Clear( void );
|
||||
};
|
||||
|
||||
@@ -35,11 +35,11 @@ private:
|
||||
void SetupServers( void );
|
||||
|
||||
protected:
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void SelectServer( Event *ev );
|
||||
void JoinServer( Event *ev );
|
||||
qboolean KeyEvent( int key, unsigned int time );
|
||||
void UpdateUIElement( void );
|
||||
qboolean KeyEvent( int key, unsigned int time ) override;
|
||||
void UpdateUIElement( void ) override;
|
||||
|
||||
public:
|
||||
UILANGameClass();
|
||||
|
||||
@@ -36,8 +36,8 @@ protected:
|
||||
void RemoveGame( Event *ev );
|
||||
void DeleteGame( Event *ev );
|
||||
void NoDeleteGame( Event *ev );
|
||||
qboolean KeyEvent( int key, unsigned int time );
|
||||
void UpdateUIElement( void );
|
||||
qboolean KeyEvent( int key, unsigned int time ) override;
|
||||
void UpdateUIElement( void ) override;
|
||||
public:
|
||||
UIFAKKLoadGameClass();
|
||||
|
||||
|
||||
@@ -27,21 +27,21 @@ class MapRunnerClass : public FilePickerClass {
|
||||
public:
|
||||
CLASS_PROTOTYPE( MapRunnerClass );
|
||||
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname );
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname ) override;
|
||||
};
|
||||
|
||||
class ViewSpawnerClass : public FilePickerClass {
|
||||
public:
|
||||
CLASS_PROTOTYPE( ViewSpawnerClass );
|
||||
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname );
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname ) override;
|
||||
};
|
||||
|
||||
class LODSpawnerClass : public FilePickerClass {
|
||||
public:
|
||||
CLASS_PROTOTYPE( LODSpawnerClass );
|
||||
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname );
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname ) override;
|
||||
};
|
||||
|
||||
class UIPickFileClass : public FilePickerClass {
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
|
||||
CLASS_PROTOTYPE( UIPickFileClass );
|
||||
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname );
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname ) override;
|
||||
};
|
||||
|
||||
void PickFile( const char *name, Listener *obj, Event& event );
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
void Print( const char *text );
|
||||
void Create( const UISize2D& size, const UColor& fore, const UColor& back, float alpha );
|
||||
void MoveInEvent( Event *ev );
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void setRealShow( bool b );
|
||||
};
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ public:
|
||||
protected:
|
||||
void SelectServer( Event *ev );
|
||||
void ConnectServer( Event *ev );
|
||||
qboolean KeyEvent( int key, unsigned int time );
|
||||
void UpdateUIElement( void );
|
||||
qboolean KeyEvent( int key, unsigned int time ) override;
|
||||
void UpdateUIElement( void ) override;
|
||||
void RefreshServerList( Event *ev );
|
||||
void RefreshLANServerList( Event *ev );
|
||||
void CancelRefresh( Event *ev );
|
||||
@@ -51,8 +51,8 @@ protected:
|
||||
public:
|
||||
UIFAKKServerList();
|
||||
|
||||
void Draw( void );
|
||||
void SortByColumn( int column );
|
||||
void Draw( void ) override;
|
||||
void SortByColumn( int column ) override;
|
||||
};
|
||||
|
||||
#endif /* __CL_UISERVERLIST_H__ */
|
||||
@@ -29,8 +29,8 @@ public:
|
||||
|
||||
SoundPickerClass();
|
||||
|
||||
void FileSelected( str ¤tDirectory, str &partialName, str &fullname );
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname );
|
||||
void FileSelected( str ¤tDirectory, str &partialName, str &fullname ) override;
|
||||
void FileChosen( str ¤tDirectory, str &partialName, str &fullname ) override;
|
||||
};
|
||||
|
||||
#endif /* __CL_UISOUNDPICKER_H__ */
|
||||
+398
-25
@@ -271,7 +271,7 @@ void UIFakkLabel::ClearInvItemReference( Event *ev )
|
||||
|
||||
void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
{
|
||||
str or = ev->GetString( 1 );
|
||||
str _or = ev->GetString( 1 );
|
||||
|
||||
if( ev->NumArgs() > 1 )
|
||||
{
|
||||
@@ -279,27 +279,27 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
m_statbar_max = ev->GetFloat( 3 );
|
||||
}
|
||||
|
||||
if( !str::icmp( or, "horizontal" ) )
|
||||
if( !str::icmp( _or, "horizontal" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_HORIZONTAL;
|
||||
}
|
||||
else if( !str::icmp( or, "vertical_stagger_even" ) )
|
||||
else if( !str::icmp( _or, "vertical_stagger_even" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_VERTICAL_STAGGER_EVEN;
|
||||
}
|
||||
else if( !str::icmp( or, "vertical_stagger_odd" ) )
|
||||
else if( !str::icmp( _or, "vertical_stagger_odd" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_VERTICAL_STAGGER_ODD;
|
||||
}
|
||||
else if( !str::icmp( or, "vertical" ) )
|
||||
else if( !str::icmp( _or, "vertical" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_VERTICAL;
|
||||
}
|
||||
else if( !str::icmp( or, "vertical_reverse" ) )
|
||||
else if( !str::icmp( _or, "vertical_reverse" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_VERTICAL_REVERSE;
|
||||
}
|
||||
else if( !str::icmp( or, "circular" ) )
|
||||
else if( !str::icmp( _or, "circular" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_CIRCULAR;
|
||||
|
||||
@@ -308,7 +308,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
m_statbar_material = uWinMan.RegisterShader( "blank" );
|
||||
}
|
||||
}
|
||||
else if( !str::icmp( or, "needle" ) )
|
||||
else if( !str::icmp( _or, "needle" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_NEEDLE;
|
||||
|
||||
@@ -317,7 +317,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
m_statbar_material = uWinMan.RegisterShader( "blank" );
|
||||
}
|
||||
}
|
||||
else if( !str::icmp( or, "rotator" ) )
|
||||
else if( !str::icmp( _or, "rotator" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_ROTATOR;
|
||||
|
||||
@@ -326,7 +326,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
m_statbar_material = uWinMan.RegisterShader( "blank" );
|
||||
}
|
||||
}
|
||||
else if( !str::icmp( or, "compass" ) )
|
||||
else if( !str::icmp( _or, "compass" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_COMPASS;
|
||||
|
||||
@@ -335,7 +335,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
m_statbar_material = uWinMan.RegisterShader( "blank" );
|
||||
}
|
||||
}
|
||||
else if( !str::icmp( or, "spinner" ) )
|
||||
else if( !str::icmp( _or, "spinner" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_SPINNER;
|
||||
|
||||
@@ -344,7 +344,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
m_statbar_material = uWinMan.RegisterShader( "blank" );
|
||||
}
|
||||
}
|
||||
else if( !str::icmp( or, "headingspinner" ) )
|
||||
else if( !str::icmp( _or, "headingspinner" ) )
|
||||
{
|
||||
m_statbar_or = L_STATBAR_HEADING_SPINNER;
|
||||
|
||||
@@ -355,7 +355,7 @@ void UIFakkLabel::LayoutStatbar( Event *ev )
|
||||
}
|
||||
else
|
||||
{
|
||||
warning( "LayoutPlayerStat", "Invalid statbar orientation: \"%s\"", or.c_str() );
|
||||
warning( "LayoutPlayerStat", "Invalid statbar orientation: \"%s\"", _or.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,7 +438,178 @@ void UIFakkLabel::LayoutRenderModelAnim( Event *ev )
|
||||
|
||||
void UIFakkLabel::DrawStatbar( float frac )
|
||||
{
|
||||
// FIXME: stub
|
||||
vec4_t col;
|
||||
float alpha;
|
||||
|
||||
col[0] = col[1] = col[2] = col[3] = 1.0;
|
||||
|
||||
switch (m_statbar_or)
|
||||
{
|
||||
case L_STATBAR_CIRCULAR:
|
||||
DrawStatCircle(frac);
|
||||
return;
|
||||
case L_STATBAR_NEEDLE:
|
||||
DrawStatNeedle(frac);
|
||||
return;
|
||||
case L_STATBAR_ROTATOR:
|
||||
DrawStatRotator(frac);
|
||||
return;
|
||||
case L_STATBAR_COMPASS:
|
||||
DrawStatCompass(frac);
|
||||
return;
|
||||
case L_STATBAR_SPINNER:
|
||||
case L_STATBAR_HEADING_SPINNER:
|
||||
DrawStatSpinner(frac);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!frac) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frac != m_lastfrac) {
|
||||
m_flashtime = uid.time;
|
||||
}
|
||||
m_lastfrac = frac;
|
||||
|
||||
alpha = 1.0 - ((float)uid.time - m_flashtime) / 1500.0;
|
||||
if (alpha < 0.0) alpha = 0.0;
|
||||
else if (alpha > 1.0) alpha = 1.0;
|
||||
|
||||
col[3] = alpha;
|
||||
|
||||
if (m_statbar_material)
|
||||
{
|
||||
if (m_flags & WF_TILESHADER)
|
||||
{
|
||||
switch (m_statbar_or)
|
||||
{
|
||||
case L_STATBAR_HORIZONTAL:
|
||||
{
|
||||
float width = frac * m_frame.size.width;
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawTilePic(0.0, 0.0, width, m_frame.size.height, m_statbar_material->GetMaterial());
|
||||
|
||||
if (alpha != 0.0 && m_statbar_material_flash)
|
||||
{
|
||||
re.SetColor(col);
|
||||
m_statbar_material_flash->ReregisterMaterial();
|
||||
re.DrawTilePic(0.0, 0.0, width, m_frame.size.height, m_statbar_material_flash->GetMaterial());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L_STATBAR_VERTICAL:
|
||||
case L_STATBAR_VERTICAL_REVERSE:
|
||||
case L_STATBAR_VERTICAL_STAGGER_EVEN:
|
||||
case L_STATBAR_VERTICAL_STAGGER_ODD:
|
||||
{
|
||||
float y = m_frame.size.height * (1.0 - frac);
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawTilePic(0.0, y, m_frame.size.width, m_frame.size.height, m_statbar_material->GetMaterial());
|
||||
|
||||
if (alpha != 0.0 && m_statbar_material_flash)
|
||||
{
|
||||
re.SetColor(col);
|
||||
m_statbar_material_flash->ReregisterMaterial();
|
||||
re.DrawTilePic(0.0, y, m_frame.size.width, m_frame.size.height, m_statbar_material_flash->GetMaterial());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_statbar_or)
|
||||
{
|
||||
case L_STATBAR_HORIZONTAL:
|
||||
{
|
||||
float width = frac * m_frame.size.width;
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawStretchPic(0.0, 0.0, width, m_frame.size.height, 0.0, 0.0, 1.0, 1.0, m_statbar_material->GetMaterial());
|
||||
|
||||
if(alpha != 0.0 && m_statbar_material_flash)
|
||||
{
|
||||
re.SetColor(col);
|
||||
m_statbar_material_flash->ReregisterMaterial();
|
||||
re.DrawStretchPic(0.0, 0.0, width, m_frame.size.height, 0.0, 0.0, 1.0, 1.0, m_statbar_material_flash->GetMaterial());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L_STATBAR_VERTICAL:
|
||||
case L_STATBAR_VERTICAL_STAGGER_EVEN:
|
||||
case L_STATBAR_VERTICAL_STAGGER_ODD:
|
||||
{
|
||||
float y = m_frame.size.height * (1.0 - frac);
|
||||
float height = m_frame.size.height * frac;
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawStretchPic(0.0, y, m_frame.size.width, height, 0.0, 1.0 - frac, 1.0, 1.0, m_statbar_material->GetMaterial());
|
||||
|
||||
if (alpha != 0.0 && m_statbar_material_flash)
|
||||
{
|
||||
re.SetColor(col);
|
||||
m_statbar_material_flash->ReregisterMaterial();
|
||||
re.DrawStretchPic(0.0, y, m_frame.size.width, height, 0.0, 1.0 - frac, 1.0, 1.0, m_statbar_material_flash->GetMaterial());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case L_STATBAR_VERTICAL_REVERSE:
|
||||
{
|
||||
float height = m_frame.size.height * frac;
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawStretchPic(0.0, 0.0, m_frame.size.width, height, 0.0, 0.0, 1.0, frac, m_statbar_material->GetMaterial());
|
||||
|
||||
if (alpha != 0.0 && m_statbar_material_flash)
|
||||
{
|
||||
re.SetColor(col);
|
||||
m_statbar_material_flash->ReregisterMaterial();
|
||||
re.DrawStretchPic(0.0, 0.0, m_frame.size.width, height, 0.0, 0.0, 1.0, frac, m_statbar_material_flash->GetMaterial());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_statbar_or)
|
||||
{
|
||||
case L_STATBAR_VERTICAL:
|
||||
case L_STATBAR_VERTICAL_STAGGER_EVEN:
|
||||
case L_STATBAR_VERTICAL_STAGGER_ODD:
|
||||
DrawBox(
|
||||
0.0,
|
||||
m_frame.size.height * (1.0 - frac),
|
||||
m_frame.size.width,
|
||||
m_frame.size.height,
|
||||
m_foreground_color,
|
||||
1.0
|
||||
);
|
||||
break;
|
||||
case L_STATBAR_HORIZONTAL:
|
||||
DrawBox(
|
||||
0.0,
|
||||
0.0,
|
||||
frac * m_frame.size.width,
|
||||
m_frame.size.height,
|
||||
m_foreground_color,
|
||||
1.0
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UIFakkLabel::DrawStatCircle( float frac )
|
||||
@@ -458,7 +629,212 @@ void UIFakkLabel::DrawStatRotator( float frac )
|
||||
|
||||
void UIFakkLabel::DrawStatCompass( float frac )
|
||||
{
|
||||
// FIXME: stub
|
||||
vec4_t col;
|
||||
float fTargAng;
|
||||
float fSinVal, fCosVal;
|
||||
vec2_t vCenter;
|
||||
vec2_t vVerts[3];
|
||||
vec2_t vTexCoords[3];
|
||||
vec2_t vCompassDir;
|
||||
vec2_t vSideDir;
|
||||
|
||||
col[0] = col[1] = col[2] = col[3] = 1.0;
|
||||
|
||||
if (!cge) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int iLastCompassTime = -9999, iLastTimeDelta = 0;
|
||||
static float fLastPitch = 0, fLastYaw = 0, fLastYawDelta = 0;
|
||||
static float fYawOffset = 0, fYawSpeed = 0;
|
||||
static float fNeedleOffset = 0, fNeedleSpeed = 0;
|
||||
int iTimeCount, iTimeDelta;
|
||||
float fYawDelta, fYawDeltaDiff;
|
||||
vec3_t vViewAngles;
|
||||
|
||||
cge->CG_EyeAngles(&vViewAngles);
|
||||
|
||||
vViewAngles[1] -= cl.snap.ps.stats[STAT_COMPASSNORTH] / 182.0f;
|
||||
|
||||
iTimeCount = uid.time - iLastCompassTime;
|
||||
if (iTimeCount <= 1000)
|
||||
{
|
||||
fYawDelta = AngleSubtract(vViewAngles[1], fLastYaw);
|
||||
if (fYawDelta > 0.1)
|
||||
{
|
||||
if ((fYawDelta > 0.0 && fLastYawDelta < fYawDelta)
|
||||
|| (fYawDelta < 0.0 && fLastYawDelta > fYawDelta))
|
||||
{
|
||||
|
||||
fYawSpeed += (fYawDelta - fLastYawDelta) * 0.75;
|
||||
fYawOffset += (fYawDelta - fLastYawDelta) * 0.75;
|
||||
}
|
||||
|
||||
if (fYawSpeed > 90.0) {
|
||||
fYawSpeed = 90.0;
|
||||
}
|
||||
else if (fYawSpeed < 0.05) {
|
||||
fYawSpeed = 0.05;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
while (iTimeCount > 0)
|
||||
{
|
||||
iTimeDelta = iTimeCount;
|
||||
if (iTimeCount > 15) {
|
||||
iTimeDelta = 15;
|
||||
}
|
||||
iTimeCount -= iTimeDelta;
|
||||
|
||||
if (fabs(fYawOffset) >= 0.1 || fabs(fYawSpeed) >= 0.01)
|
||||
{
|
||||
fYawOffset += fYawSpeed * iTimeDelta;
|
||||
if (fYawOffset > 0.0) {
|
||||
fYawSpeed -= iTimeDelta * 0.00175;
|
||||
}
|
||||
else if (fYawOffset < 0.0) {
|
||||
fYawSpeed += iTimeDelta * 0.00175;
|
||||
}
|
||||
|
||||
if (fYawOffset > 40.0) {
|
||||
fYawOffset = 40.0;
|
||||
fYawSpeed = 0.0;
|
||||
}
|
||||
else if (fYawOffset < -40.0) {
|
||||
fYawOffset = -40.0;
|
||||
fYawSpeed = 0.0;
|
||||
}
|
||||
|
||||
fYawSpeed -= iTimeDelta * 0.003;
|
||||
if (fYawSpeed > 0.0) {
|
||||
fYawSpeed -= iTimeDelta * 0.0004;
|
||||
}
|
||||
else {
|
||||
fYawSpeed += iTimeDelta * 0.0004;
|
||||
if (fYawSpeed > 0.0) {
|
||||
fYawSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
iTimeCount = 0;
|
||||
fYawOffset = 0.0;
|
||||
fYawSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
fLastYawDelta = fYawDelta;
|
||||
iLastTimeDelta = uid.time - iLastCompassTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
fLastYawDelta = 0;
|
||||
fYawOffset = 0;
|
||||
fYawSpeed = 0;
|
||||
iLastTimeDelta = 0;
|
||||
}
|
||||
|
||||
fLastPitch = vViewAngles[0];
|
||||
fLastYaw = vViewAngles[1];
|
||||
iLastCompassTime = uid.time;
|
||||
|
||||
if (iLastTimeDelta)
|
||||
{
|
||||
if (fabs(fLastYawDelta) > 0.1) {
|
||||
fNeedleOffset -= fLastYawDelta;
|
||||
}
|
||||
|
||||
iTimeCount = iLastTimeDelta;
|
||||
while (iTimeCount > 0)
|
||||
{
|
||||
iTimeDelta = iTimeCount;
|
||||
if (iTimeCount > 15) {
|
||||
iTimeDelta = 15;
|
||||
}
|
||||
iTimeCount -= iTimeDelta;
|
||||
|
||||
if (fabs(fNeedleOffset) >= 0.1 || fabs(fNeedleSpeed) >= 0.01) {
|
||||
|
||||
fNeedleOffset += iTimeDelta * fNeedleSpeed;
|
||||
if (fNeedleOffset > 180.0) {
|
||||
fNeedleOffset -= 360.0;
|
||||
}
|
||||
else if (fNeedleOffset < -180.0) {
|
||||
fNeedleOffset += 360.0;
|
||||
}
|
||||
|
||||
if (fNeedleOffset > 0.0) {
|
||||
fNeedleSpeed -= iTimeDelta * 0.00175;
|
||||
}
|
||||
else if (fNeedleOffset < 0.0) {
|
||||
fNeedleSpeed += iTimeDelta * 0.00175;
|
||||
}
|
||||
|
||||
fNeedleSpeed -= fNeedleSpeed * 0.0025 * iTimeDelta;
|
||||
if (fNeedleSpeed > 0.0) {
|
||||
fNeedleSpeed -= iTimeDelta * 0.00035;
|
||||
if (fNeedleSpeed < 0.0) {
|
||||
fNeedleSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fNeedleSpeed += iTimeDelta * 0.00035;
|
||||
if (fNeedleSpeed > 0.0) {
|
||||
fNeedleSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
iTimeCount = 0;
|
||||
fNeedleOffset = 0.0;
|
||||
fNeedleSpeed = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fNeedleOffset = 0.0;
|
||||
fNeedleSpeed = 0.0;
|
||||
}
|
||||
|
||||
fSinVal = sin(anglemod(fNeedleOffset + fLastYaw) / (180 / M_PI));
|
||||
fCosVal = cos(anglemod(fNeedleOffset + fLastYaw) / (180 / M_PI));
|
||||
|
||||
vCompassDir[0] = fSinVal;
|
||||
vCompassDir[1] = -fCosVal;
|
||||
|
||||
vCenter[0] = m_frame.size.width * 0.5;
|
||||
vCenter[1] = m_frame.size.height * 0.5;
|
||||
vTexCoords[0][0] = 0.0;
|
||||
vTexCoords[0][1] = 0.0;
|
||||
vTexCoords[1][0] = 1.0;
|
||||
vTexCoords[1][1] = 0.0;
|
||||
vTexCoords[2][0] = 0.0;
|
||||
vTexCoords[2][1] = 1.0;
|
||||
|
||||
vVerts[0][0] = vCenter[0] + vCompassDir[0] * vCenter[0] - fCosVal * vCenter[1];
|
||||
vVerts[1][0] = vCenter[0] + vCompassDir[0] * vCenter[0] + fCosVal * vCenter[1];
|
||||
vVerts[2][0] = vCenter[0] - vCompassDir[0] * vCenter[0] - fCosVal * vCenter[1];
|
||||
vVerts[0][1] = vCenter[1] + vCompassDir[1] * vCenter[1] - fSinVal * vCenter[0];
|
||||
vVerts[1][1] = vCenter[1] + vCompassDir[1] * vCenter[1] + fSinVal * vCenter[0];
|
||||
vVerts[2][1] = vCenter[1] - vCompassDir[1] * vCenter[1] - fSinVal * vCenter[0];
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial());
|
||||
|
||||
vVerts[0][0] = vVerts[2][0];
|
||||
vVerts[0][1] = vVerts[2][1];
|
||||
vTexCoords[0][0] = vTexCoords[2][0];
|
||||
vTexCoords[0][1] = vTexCoords[2][1];
|
||||
vTexCoords[2][0] = 1.0;
|
||||
vTexCoords[2][1] = 1.0;
|
||||
|
||||
vVerts[2][0] = vCenter[0] + fCosVal * vCenter[1] - vCompassDir[0] * vCenter[0];
|
||||
vVerts[2][1] = vCenter[1] * fSinVal + vCenter[0] - vCompassDir[1] * vCenter[1];
|
||||
|
||||
m_statbar_material->ReregisterMaterial();
|
||||
re.DrawTrianglePic(vVerts, vTexCoords, m_statbar_material->GetMaterial());
|
||||
}
|
||||
|
||||
void UIFakkLabel::DrawStatSpinner( float frac )
|
||||
@@ -506,7 +882,7 @@ void UIFakkLabel::Draw( void )
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_stat != -1 )
|
||||
if( m_stat == -1 )
|
||||
{
|
||||
float scale;
|
||||
qhandle_t handle;
|
||||
@@ -516,7 +892,7 @@ void UIFakkLabel::Draw( void )
|
||||
vec3_t angles;
|
||||
vec3_t offset;
|
||||
vec3_t rotateoffset;
|
||||
vec3_t color;
|
||||
vec4_t color;
|
||||
str sAnimName;
|
||||
float height;
|
||||
|
||||
@@ -686,23 +1062,20 @@ _shitlabel01:
|
||||
|
||||
float frac;
|
||||
|
||||
if( m_maxstat )
|
||||
if( m_maxstat >= 0 )
|
||||
{
|
||||
frac = delta / ( m_statbar_max - m_statbar_min );
|
||||
frac = (float)delta / (float)cl.snap.ps.stats[m_maxstat];
|
||||
}
|
||||
else
|
||||
{
|
||||
frac = delta / cl.snap.ps.stats[ m_maxstat ];
|
||||
frac = (float)delta / (float)(m_statbar_max - m_statbar_min);
|
||||
}
|
||||
|
||||
if( frac > 1.0 )
|
||||
frac = 1.0;
|
||||
if( frac < 0.0 )
|
||||
frac = 0.0;
|
||||
if( frac > 1.0 ) frac = 1.0;
|
||||
else if( frac < 0.0 ) frac = 0.0;
|
||||
|
||||
DrawStatbar( frac );
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
void DrawStatSpinner( float frac );
|
||||
void StatCircleTexCoord( float fAng, vec3_t vTexCoord );
|
||||
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
+140
-13
@@ -21,16 +21,26 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "cl_ui.h"
|
||||
#include "cl_screen.h"
|
||||
|
||||
CLASS_DECLARATION( UIWidget, View3D, NULL )
|
||||
{
|
||||
{ &W_Activated, &View3D::OnActivate },
|
||||
{ &W_Deactivated, &View3D::OnDeactivate },
|
||||
{ &W_LeftMouseDown, &View3D::Pressed },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
View3D::View3D()
|
||||
{
|
||||
// FIXME: stub
|
||||
// set as transparent
|
||||
setBackgroundColor(UClear, true);
|
||||
// no border
|
||||
setBorderStyle(border_none);
|
||||
AllowActivate(true);
|
||||
|
||||
m_printfadetime = 0.0;
|
||||
m_print_mat = NULL;
|
||||
m_locationprint = qfalse;
|
||||
}
|
||||
|
||||
void View3D::Draw
|
||||
@@ -39,15 +49,14 @@ void View3D::Draw
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
if (cls.state != CA_DISCONNECTED)
|
||||
{
|
||||
if (cls.state != CA_DISCONNECTED) {
|
||||
SCR_DrawScreenField();
|
||||
}
|
||||
|
||||
//dword_893691C(v1, v2, v3, v4);
|
||||
|
||||
set2D();
|
||||
|
||||
re.SavePerformanceCounters();
|
||||
|
||||
Draw2D();
|
||||
}
|
||||
|
||||
@@ -75,7 +84,40 @@ void View3D::Draw2D
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
if (!cls.no_menus) {
|
||||
DrawFades();
|
||||
}
|
||||
|
||||
DrawLetterbox();
|
||||
|
||||
if ((cl_debuggraph->integer || cl_timegraph->integer) && !cls.no_menus)
|
||||
{
|
||||
SCR_DrawDebugGraph();
|
||||
}
|
||||
else if (!cls.no_menus)
|
||||
{
|
||||
if (cge) {
|
||||
cge->CG_Draw2D();
|
||||
}
|
||||
|
||||
if (m_locationprint) {
|
||||
LocationPrint();
|
||||
} else {
|
||||
CenterPrint();
|
||||
}
|
||||
|
||||
if (!cls.no_menus)
|
||||
{
|
||||
DrawSoundOverlay();
|
||||
DrawSubtitleOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
if (fps->integer && !cls.no_menus)
|
||||
{
|
||||
DrawFPS();
|
||||
DrawProf();
|
||||
}
|
||||
}
|
||||
|
||||
void View3D::DrawFPS
|
||||
@@ -84,7 +126,72 @@ void View3D::DrawFPS
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
char string[128];
|
||||
|
||||
setFont("verdana-14");
|
||||
if (fps->integer == 2)
|
||||
{
|
||||
re.SetColor(UBlack);
|
||||
re.DrawBox(
|
||||
0.0,
|
||||
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse) * 4.0,
|
||||
m_frame.pos.x + m_frame.size.width,
|
||||
m_font->getHeight(qfalse) * 4.0
|
||||
);
|
||||
}
|
||||
|
||||
sprintf(string, "FPS %4.1f", currentfps);
|
||||
if (currentfps > 23.94) {
|
||||
if (cl_greenfps->integer) {
|
||||
m_font->setColor(UGreen);
|
||||
} else {
|
||||
m_font->setColor(UWhite);
|
||||
}
|
||||
} else if (currentfps > 18.0) {
|
||||
m_font->setColor(UYellow);
|
||||
} else {
|
||||
// low fps
|
||||
m_font->setColor(URed);
|
||||
}
|
||||
|
||||
m_font->Print(
|
||||
m_font->getHeight(qfalse) * 10.0,
|
||||
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse) * 3.0,
|
||||
string,
|
||||
-1,
|
||||
qfalse
|
||||
);
|
||||
|
||||
// Draw elements count
|
||||
if (cl_greenfps->integer) {
|
||||
m_font->setColor(UGreen);
|
||||
}
|
||||
else {
|
||||
m_font->setColor(UWhite);
|
||||
}
|
||||
|
||||
sprintf(string, "wt%5d wv%5d cl%d", cls.world_tris, cls.world_verts, cls.character_lights);
|
||||
|
||||
m_font->Print(
|
||||
m_font->getHeight(qfalse) * 10.0,
|
||||
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse) * 2.0,
|
||||
string,
|
||||
-1,
|
||||
qfalse
|
||||
);
|
||||
|
||||
sprintf(string, "t%5d v%5d Mtex%5.2f", cls.total_tris, cls.total_verts, (float)cls.total_texels * 0.00000095367432);
|
||||
|
||||
|
||||
m_font->Print(
|
||||
m_font->getHeight(qfalse) * 10.0,
|
||||
m_frame.pos.y + m_frame.size.height - m_font->getHeight(qfalse),
|
||||
string,
|
||||
-1,
|
||||
qfalse
|
||||
);
|
||||
|
||||
m_font->setColor(UBlack);
|
||||
}
|
||||
|
||||
void View3D::DrawProf
|
||||
@@ -144,7 +251,25 @@ void View3D::OnActivate
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
UIWidget* wid;
|
||||
UList<UIWidget*> widgets;
|
||||
|
||||
UI_CloseInventory();
|
||||
cls.keyCatchers &= ~KEYCATCH_UI;
|
||||
|
||||
for (wid = getParent()->getFirstChild(); wid; wid = getParent()->getNextChild(wid))
|
||||
{
|
||||
if (wid->getAlwaysOnBottom() && wid != this) {
|
||||
widgets.AddTail(wid);
|
||||
}
|
||||
}
|
||||
|
||||
widgets.IterateFromHead();
|
||||
while (widgets.IsCurrentValid())
|
||||
{
|
||||
widgets.getCurrent()->BringToFrontPropogated();
|
||||
widgets.IterateNext();
|
||||
}
|
||||
}
|
||||
|
||||
void View3D::OnDeactivate
|
||||
@@ -153,7 +278,7 @@ void View3D::OnDeactivate
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
cls.keyCatchers |= KEYCATCH_UI;
|
||||
}
|
||||
|
||||
void View3D::DrawSubtitleOverlay
|
||||
@@ -220,7 +345,8 @@ void View3D::FrameInitialized
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
Connect(this, W_Activated, W_Activated);
|
||||
Connect(this, W_Deactivated, W_Deactivated);
|
||||
}
|
||||
|
||||
void View3D::Pressed
|
||||
@@ -229,7 +355,8 @@ void View3D::Pressed
|
||||
)
|
||||
|
||||
{
|
||||
// FIXME: stub
|
||||
IN_MouseOff();
|
||||
OnActivate(ev);
|
||||
}
|
||||
|
||||
CLASS_DECLARATION( UIWidget, ConsoleView, NULL )
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
CLASS_PROTOTYPE( View3D );
|
||||
|
||||
protected:
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
void DrawLetterbox( void );
|
||||
void DrawFades( void );
|
||||
void Draw2D( void );
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
void UpdateLocationPrint( int x, int y, const char *s, float alpha );
|
||||
qboolean LetterboxActive( void );
|
||||
void InitSubtitle( void );
|
||||
void FrameInitialized( void );
|
||||
void FrameInitialized( void ) override;
|
||||
virtual void Pressed( Event *ev );
|
||||
};
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
CLASS_PROTOTYPE( ConsoleView );
|
||||
|
||||
protected:
|
||||
void Draw( void );
|
||||
void Draw( void ) override;
|
||||
};
|
||||
|
||||
#endif /* __CL_UIVIEW3D__ */
|
||||
+28
-15
@@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "../renderercommon/tr_public.h"
|
||||
#include "../renderer/tr_public.h"
|
||||
#include "keys.h"
|
||||
#include "snd_public.h"
|
||||
#include "../cgame/cg_public.h"
|
||||
@@ -126,10 +126,6 @@ typedef struct {
|
||||
|
||||
int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
|
||||
|
||||
// cgame communicates a few values to the client system
|
||||
int cgameUserCmdValue; // current weapon to add to usercmd_t
|
||||
float cgameSensitivity;
|
||||
|
||||
// cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last
|
||||
// properly generated command
|
||||
usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
|
||||
@@ -145,9 +141,6 @@ typedef struct {
|
||||
// and teleport direction changes
|
||||
vec3_t viewangles;
|
||||
|
||||
vec3_t eyeAngles;
|
||||
vec3_t eyeOrigin;
|
||||
|
||||
int serverId; // included in each client message so the server
|
||||
// can tell if it is for a prior map_restart
|
||||
// big stuff at end of structure so most offsets are 15 bits or less
|
||||
@@ -182,6 +175,7 @@ typedef struct {
|
||||
|
||||
netadr_t serverAddress;
|
||||
int connectTime; // for connection retransmits
|
||||
int connectStartTime;
|
||||
int connectPacketCount; // for display on connection dialog
|
||||
char serverMessage[MAX_STRING_TOKENS]; // for display on connection dialog
|
||||
|
||||
@@ -246,6 +240,9 @@ typedef struct {
|
||||
|
||||
// big stuff at end of structure so most offsets are 15 bits or less
|
||||
netchan_t netchan;
|
||||
|
||||
float aviVideoFrameRemainder;
|
||||
float aviSoundFrameRemainder;
|
||||
} clientConnection_t;
|
||||
|
||||
extern clientConnection_t clc;
|
||||
@@ -306,6 +303,7 @@ typedef struct {
|
||||
|
||||
int framecount;
|
||||
int frametime; // msec since last frame
|
||||
float serverFrameTime;
|
||||
|
||||
int realtime; // ignores pause
|
||||
int realFrametime; // ignoring pause, so console always works
|
||||
@@ -347,7 +345,12 @@ typedef struct {
|
||||
int character_lights;
|
||||
hdelement_t HudDrawElements[ MAX_HUDDRAW_ELEMENTS ];
|
||||
clientAnim_t anim;
|
||||
stopwatch_t stopwatch;
|
||||
stopWatch_t stopwatch;
|
||||
void* savedCgameState;
|
||||
int savedCgameStateSize;
|
||||
char gcdResponse[73];
|
||||
int unknown3_0;
|
||||
int currentRate;
|
||||
qhandle_t charSetShader;
|
||||
qhandle_t whiteShader;
|
||||
qhandle_t consoleShader;
|
||||
@@ -363,6 +366,8 @@ extern clientGameExport_t *cge;
|
||||
extern refexport_t re; // interface to refresh .dll
|
||||
|
||||
|
||||
extern qboolean scr_initialized;
|
||||
|
||||
//
|
||||
// cvars
|
||||
//
|
||||
@@ -370,6 +375,7 @@ extern cvar_t *cl_nodelta;
|
||||
extern cvar_t *cl_debugMove;
|
||||
extern cvar_t *cl_noprint;
|
||||
extern cvar_t *cl_timegraph;
|
||||
extern cvar_t *cl_debuggraph;
|
||||
extern cvar_t *cl_timeout;
|
||||
extern cvar_t *cl_connect_timeout;
|
||||
extern cvar_t *cl_maxpackets;
|
||||
@@ -422,6 +428,17 @@ extern cvar_t *cl_consoleKeys;
|
||||
|
||||
extern cvar_t *cg_gametype;
|
||||
|
||||
extern cvar_t* j_pitch;
|
||||
extern cvar_t* j_yaw;
|
||||
extern cvar_t* j_forward;
|
||||
extern cvar_t* j_side;
|
||||
extern cvar_t* j_up;
|
||||
extern cvar_t* j_pitch_axis;
|
||||
extern cvar_t* j_yaw_axis;
|
||||
extern cvar_t* j_forward_axis;
|
||||
extern cvar_t* j_side_axis;
|
||||
extern cvar_t* j_up_axis;
|
||||
|
||||
//=================================================
|
||||
|
||||
//
|
||||
@@ -503,8 +520,7 @@ void Key_GetKeysForCommand( const char *command, int *key1, int *key2 );
|
||||
int Key_GetCatcher( void );
|
||||
void Key_SetCatcher( int catcher );
|
||||
|
||||
void CL_GetEyeInfo(usereyes_t *info); //su44
|
||||
void CL_SetEyeInfo(vec3_t origin, vec3_t angles); //su44
|
||||
void CL_EyeInfo(usereyes_t *info);
|
||||
|
||||
//
|
||||
// cl_parse.c
|
||||
@@ -560,15 +576,12 @@ void Con_PageUp( void );
|
||||
void Con_PageDown( void );
|
||||
void Con_Top( void );
|
||||
void Con_Bottom( void );
|
||||
void Con_Close( void );
|
||||
|
||||
void CL_LoadConsoleHistory( void );
|
||||
void CL_SaveConsoleHistory( void );
|
||||
|
||||
//
|
||||
// cl_scrn.c
|
||||
//
|
||||
void SCR_Init (void);
|
||||
void SCR_DrawDebugGraph(void);
|
||||
void SCR_DrawScreenField(void);
|
||||
void SCR_UpdateScreen (void);
|
||||
|
||||
|
||||
+10
-115
@@ -47,9 +47,12 @@ typedef enum {
|
||||
K_LEFTARROW,
|
||||
K_RIGHTARROW,
|
||||
|
||||
K_ALT,
|
||||
K_CTRL,
|
||||
K_SHIFT,
|
||||
K_LALT,
|
||||
K_LCTRL,
|
||||
K_LSHIFT,
|
||||
K_RALT,
|
||||
K_RCTRL,
|
||||
K_RSHIFT,
|
||||
K_INS,
|
||||
K_DEL,
|
||||
K_PGDN,
|
||||
@@ -151,119 +154,11 @@ typedef enum {
|
||||
K_AUX15,
|
||||
K_AUX16,
|
||||
|
||||
K_WORLD_0,
|
||||
K_WORLD_1,
|
||||
K_WORLD_2,
|
||||
K_WORLD_3,
|
||||
K_WORLD_4,
|
||||
K_WORLD_5,
|
||||
K_WORLD_6,
|
||||
K_WORLD_7,
|
||||
K_WORLD_8,
|
||||
K_WORLD_9,
|
||||
K_WORLD_10,
|
||||
K_WORLD_11,
|
||||
K_WORLD_12,
|
||||
K_WORLD_13,
|
||||
K_WORLD_14,
|
||||
K_WORLD_15,
|
||||
K_WORLD_16,
|
||||
K_WORLD_17,
|
||||
K_WORLD_18,
|
||||
K_WORLD_19,
|
||||
K_WORLD_20,
|
||||
K_WORLD_21,
|
||||
K_WORLD_22,
|
||||
K_WORLD_23,
|
||||
K_WORLD_24,
|
||||
K_WORLD_25,
|
||||
K_WORLD_26,
|
||||
K_WORLD_27,
|
||||
K_WORLD_28,
|
||||
K_WORLD_29,
|
||||
K_WORLD_30,
|
||||
K_WORLD_31,
|
||||
K_WORLD_32,
|
||||
K_WORLD_33,
|
||||
K_WORLD_34,
|
||||
K_WORLD_35,
|
||||
K_WORLD_36,
|
||||
K_WORLD_37,
|
||||
K_WORLD_38,
|
||||
K_WORLD_39,
|
||||
K_WORLD_40,
|
||||
K_WORLD_41,
|
||||
K_WORLD_42,
|
||||
K_WORLD_43,
|
||||
K_WORLD_44,
|
||||
K_WORLD_45,
|
||||
K_WORLD_46,
|
||||
K_WORLD_47,
|
||||
K_WORLD_48,
|
||||
K_WORLD_49,
|
||||
K_WORLD_50,
|
||||
K_WORLD_51,
|
||||
K_WORLD_52,
|
||||
K_WORLD_53,
|
||||
K_WORLD_54,
|
||||
K_WORLD_55,
|
||||
K_WORLD_56,
|
||||
K_WORLD_57,
|
||||
K_WORLD_58,
|
||||
K_WORLD_59,
|
||||
K_WORLD_60,
|
||||
K_WORLD_61,
|
||||
K_WORLD_62,
|
||||
K_WORLD_63,
|
||||
K_WORLD_64,
|
||||
K_WORLD_65,
|
||||
K_WORLD_66,
|
||||
K_WORLD_67,
|
||||
K_WORLD_68,
|
||||
K_WORLD_69,
|
||||
K_WORLD_70,
|
||||
K_WORLD_71,
|
||||
K_WORLD_72,
|
||||
K_WORLD_73,
|
||||
K_WORLD_74,
|
||||
K_WORLD_75,
|
||||
K_WORLD_76,
|
||||
K_WORLD_77,
|
||||
K_WORLD_78,
|
||||
K_WORLD_79,
|
||||
K_WORLD_80,
|
||||
K_WORLD_81,
|
||||
K_WORLD_82,
|
||||
K_WORLD_83,
|
||||
K_WORLD_84,
|
||||
K_WORLD_85,
|
||||
K_WORLD_86,
|
||||
K_WORLD_87,
|
||||
K_WORLD_88,
|
||||
K_WORLD_89,
|
||||
K_WORLD_90,
|
||||
K_WORLD_91,
|
||||
K_WORLD_92,
|
||||
K_WORLD_93,
|
||||
K_WORLD_94,
|
||||
K_WORLD_95,
|
||||
K_LWINKEY,
|
||||
K_RWINKEY,
|
||||
K_MENUKEY,
|
||||
|
||||
K_SUPER,
|
||||
K_COMPOSE,
|
||||
K_MODE,
|
||||
K_HELP,
|
||||
K_PRINT,
|
||||
K_SYSREQ,
|
||||
K_SCROLLOCK,
|
||||
K_BREAK,
|
||||
K_MENU,
|
||||
K_EURO,
|
||||
K_UNDO,
|
||||
|
||||
// Pseudo-key that brings the console down
|
||||
K_CONSOLE,
|
||||
|
||||
MAX_KEYS
|
||||
K_LASTKEY
|
||||
} keyNum_t;
|
||||
|
||||
// MAX_KEYS replaces K_LAST_KEY, however some mods may have used K_LAST_KEY
|
||||
|
||||
+4
-13
@@ -32,33 +32,24 @@ typedef struct {
|
||||
} qkey_t;
|
||||
|
||||
extern qboolean key_overstrikeMode;
|
||||
extern qkey_t keys[MAX_KEYS];
|
||||
extern qkey_t keys[K_LASTKEY];
|
||||
|
||||
// NOTE TTimo the declaration of field_t and Field_Clear is now in qcommon/qcommon.h
|
||||
void Field_KeyDownEvent( field_t *edit, int key );
|
||||
void Field_CharEvent( field_t *edit, int ch );
|
||||
void Field_Draw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape );
|
||||
void Field_BigDraw(fontInfo_t *font, field_t *edit, int x, int y, int width, qboolean showCursor, qboolean noColorEscape );
|
||||
|
||||
#define COMMAND_HISTORY 32
|
||||
extern field_t historyEditLines[COMMAND_HISTORY];
|
||||
|
||||
extern field_t g_consoleField;
|
||||
extern field_t chatField;
|
||||
extern int anykeydown;
|
||||
extern qboolean chat_team;
|
||||
extern int chat_playerNum;
|
||||
|
||||
#if defined(APP_MODULE)
|
||||
int Key_StringToKeynum( const char *str );
|
||||
void Key_WriteBindings( fileHandle_t f );
|
||||
void Key_SetBinding( int keynum, const char *binding );
|
||||
char *Key_GetBinding( int keynum );
|
||||
const char *Key_GetBinding( int keynum );
|
||||
qboolean Key_IsDown( int keynum );
|
||||
qboolean Key_GetOverstrikeMode( void );
|
||||
void Key_SetOverstrikeMode( qboolean state );
|
||||
void Key_ClearStates( void );
|
||||
int Key_GetKey(const char *binding);
|
||||
const char *Key_GetKeynameForCommand( const char *command );
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+2
-1
@@ -37,8 +37,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#include "../AL/al.h"
|
||||
#include "../AL/alc.h"
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) || defined(__APPLE__)
|
||||
// MSVC users must install the OpenAL SDK which doesn't use the AL/*.h scheme.
|
||||
// OSX framework also needs this
|
||||
#include <al.h>
|
||||
#include <alc.h>
|
||||
#else
|
||||
|
||||
+121
-124
@@ -2,12 +2,12 @@
|
||||
Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The
|
||||
Netherlands.
|
||||
|
||||
All Rights Reserved
|
||||
All Rights Reserved
|
||||
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
Permission to use, copy, modify, and distribute this software and its
|
||||
documentation for any purpose and without fee is hereby granted,
|
||||
provided that the above copyright notice appear in all copies and that
|
||||
both that copyright notice and this permission notice appear in
|
||||
both that copyright notice and this permission notice appear in
|
||||
supporting documentation, and that the names of Stichting Mathematisch
|
||||
Centrum or CWI not be used in advertising or publicity pertaining to
|
||||
distribution of the software without specific, written prior permission.
|
||||
@@ -35,55 +35,55 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
/* Intel ADPCM step variation table */
|
||||
static int indexTable[ 16 ] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
static int indexTable[16] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
};
|
||||
|
||||
static int stepsizeTable[ 89 ] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
static int stepsizeTable[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
|
||||
|
||||
void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state *state ) {
|
||||
short *inp; /* Input buffer pointer */
|
||||
signed char *outp; /* output buffer pointer */
|
||||
int val; /* Current input sample value */
|
||||
int sign; /* Current adpcm sign bit */
|
||||
int delta; /* Current adpcm output value */
|
||||
int diff; /* Difference between val and sample */
|
||||
int step; /* Stepsize */
|
||||
int valpred; /* Predicted output value */
|
||||
int vpdiff; /* Current change to valpred */
|
||||
int index; /* Current step change index */
|
||||
int outputbuffer; /* place to keep previous 4-bit value */
|
||||
int bufferstep; /* toggle between outputbuffer/output */
|
||||
short *inp; /* Input buffer pointer */
|
||||
signed char *outp; /* output buffer pointer */
|
||||
int val; /* Current input sample value */
|
||||
int sign; /* Current adpcm sign bit */
|
||||
int delta; /* Current adpcm output value */
|
||||
int diff; /* Difference between val and sample */
|
||||
int step; /* Stepsize */
|
||||
int valpred; /* Predicted output value */
|
||||
int vpdiff; /* Current change to valpred */
|
||||
int index; /* Current step change index */
|
||||
int outputbuffer; /* place to keep previous 4-bit value */
|
||||
int bufferstep; /* toggle between outputbuffer/output */
|
||||
|
||||
outp = ( signed char * )outdata;
|
||||
inp = indata;
|
||||
|
||||
valpred = state->sample;
|
||||
index = state->index;
|
||||
step = stepsizeTable[ index ];
|
||||
outp = (signed char *)outdata;
|
||||
inp = indata;
|
||||
|
||||
valpred = state->sample;
|
||||
index = state->index;
|
||||
step = stepsizeTable[index];
|
||||
|
||||
outputbuffer = 0; // quiet a compiler warning
|
||||
bufferstep = 1;
|
||||
bufferstep = 1;
|
||||
|
||||
for( ; len > 0; len-- ) {
|
||||
for ( ; len > 0 ; len-- ) {
|
||||
val = *inp++;
|
||||
|
||||
/* Step 1 - compute difference with previous value */
|
||||
diff = val - valpred;
|
||||
sign = ( diff < 0 ) ? 8 : 0;
|
||||
if( sign ) diff = ( -diff );
|
||||
sign = (diff < 0) ? 8 : 0;
|
||||
if ( sign ) diff = (-diff);
|
||||
|
||||
/* Step 2 - Divide and clamp */
|
||||
/* Note:
|
||||
@@ -95,101 +95,99 @@ void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state
|
||||
** good use since the fixup would be too expensive.
|
||||
*/
|
||||
delta = 0;
|
||||
vpdiff = ( step >> 3 );
|
||||
|
||||
if( diff >= step ) {
|
||||
vpdiff = (step >> 3);
|
||||
|
||||
if ( diff >= step ) {
|
||||
delta = 4;
|
||||
diff -= step;
|
||||
vpdiff += step;
|
||||
}
|
||||
step >>= 1;
|
||||
if( diff >= step ) {
|
||||
if ( diff >= step ) {
|
||||
delta |= 2;
|
||||
diff -= step;
|
||||
vpdiff += step;
|
||||
}
|
||||
step >>= 1;
|
||||
if( diff >= step ) {
|
||||
if ( diff >= step ) {
|
||||
delta |= 1;
|
||||
vpdiff += step;
|
||||
}
|
||||
|
||||
/* Step 3 - Update previous value */
|
||||
if( sign )
|
||||
valpred -= vpdiff;
|
||||
if ( sign )
|
||||
valpred -= vpdiff;
|
||||
else
|
||||
valpred += vpdiff;
|
||||
valpred += vpdiff;
|
||||
|
||||
/* Step 4 - Clamp previous value to 16 bits */
|
||||
if( valpred > 32767 )
|
||||
valpred = 32767;
|
||||
else if( valpred < -32768 )
|
||||
valpred = -32768;
|
||||
if ( valpred > 32767 )
|
||||
valpred = 32767;
|
||||
else if ( valpred < -32768 )
|
||||
valpred = -32768;
|
||||
|
||||
/* Step 5 - Assemble value, update index and step values */
|
||||
delta |= sign;
|
||||
|
||||
index += indexTable[ delta ];
|
||||
if( index < 0 ) index = 0;
|
||||
if( index > 88 ) index = 88;
|
||||
step = stepsizeTable[ index ];
|
||||
|
||||
index += indexTable[delta];
|
||||
if ( index < 0 ) index = 0;
|
||||
if ( index > 88 ) index = 88;
|
||||
step = stepsizeTable[index];
|
||||
|
||||
/* Step 6 - Output value */
|
||||
if( bufferstep ) {
|
||||
outputbuffer = ( delta << 4 ) & 0xf0;
|
||||
}
|
||||
else {
|
||||
*outp++ = ( delta & 0x0f ) | outputbuffer;
|
||||
if ( bufferstep ) {
|
||||
outputbuffer = (delta << 4) & 0xf0;
|
||||
} else {
|
||||
*outp++ = (delta & 0x0f) | outputbuffer;
|
||||
}
|
||||
bufferstep = !bufferstep;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output last step, if needed */
|
||||
if( !bufferstep )
|
||||
*outp++ = outputbuffer;
|
||||
|
||||
state->sample = valpred;
|
||||
state->index = index;
|
||||
/* Output last step, if needed */
|
||||
if ( !bufferstep )
|
||||
*outp++ = outputbuffer;
|
||||
|
||||
state->sample = valpred;
|
||||
state->index = index;
|
||||
}
|
||||
|
||||
|
||||
/* static */ void S_AdpcmDecode( const char indata[], short *outdata, int len, struct adpcm_state *state ) {
|
||||
signed char *inp; /* Input buffer pointer */
|
||||
int outp; /* output buffer pointer */
|
||||
int sign; /* Current adpcm sign bit */
|
||||
int delta; /* Current adpcm output value */
|
||||
int step; /* Stepsize */
|
||||
int valpred; /* Predicted value */
|
||||
int vpdiff; /* Current change to valpred */
|
||||
int index; /* Current step change index */
|
||||
int inputbuffer; /* place to keep next 4-bit value */
|
||||
int bufferstep; /* toggle between inputbuffer/input */
|
||||
signed char *inp; /* Input buffer pointer */
|
||||
int outp; /* output buffer pointer */
|
||||
int sign; /* Current adpcm sign bit */
|
||||
int delta; /* Current adpcm output value */
|
||||
int step; /* Stepsize */
|
||||
int valpred; /* Predicted value */
|
||||
int vpdiff; /* Current change to valpred */
|
||||
int index; /* Current step change index */
|
||||
int inputbuffer; /* place to keep next 4-bit value */
|
||||
int bufferstep; /* toggle between inputbuffer/input */
|
||||
|
||||
outp = 0;
|
||||
inp = ( signed char * )indata;
|
||||
outp = 0;
|
||||
inp = (signed char *)indata;
|
||||
|
||||
valpred = state->sample;
|
||||
index = state->index;
|
||||
step = stepsizeTable[ index ];
|
||||
|
||||
bufferstep = 0;
|
||||
inputbuffer = 0; // quiet a compiler warning
|
||||
for( ; len > 0; len-- ) {
|
||||
valpred = state->sample;
|
||||
index = state->index;
|
||||
step = stepsizeTable[index];
|
||||
|
||||
bufferstep = 0;
|
||||
inputbuffer = 0; // quiet a compiler warning
|
||||
for ( ; len > 0 ; len-- ) {
|
||||
|
||||
/* Step 1 - get the delta value */
|
||||
if( bufferstep ) {
|
||||
if ( bufferstep ) {
|
||||
delta = inputbuffer & 0xf;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
inputbuffer = *inp++;
|
||||
delta = ( inputbuffer >> 4 ) & 0xf;
|
||||
delta = (inputbuffer >> 4) & 0xf;
|
||||
}
|
||||
bufferstep = !bufferstep;
|
||||
|
||||
/* Step 2 - Find new index value (for later) */
|
||||
index += indexTable[ delta ];
|
||||
if( index < 0 ) index = 0;
|
||||
if( index > 88 ) index = 88;
|
||||
index += indexTable[delta];
|
||||
if ( index < 0 ) index = 0;
|
||||
if ( index > 88 ) index = 88;
|
||||
|
||||
/* Step 3 - Separate sign and magnitude */
|
||||
sign = delta & 8;
|
||||
@@ -201,31 +199,31 @@ void S_AdpcmEncode( short indata[], char outdata[], int len, struct adpcm_state
|
||||
** in adpcm_coder.
|
||||
*/
|
||||
vpdiff = step >> 3;
|
||||
if( delta & 4 ) vpdiff += step;
|
||||
if( delta & 2 ) vpdiff += step >> 1;
|
||||
if( delta & 1 ) vpdiff += step >> 2;
|
||||
if ( delta & 4 ) vpdiff += step;
|
||||
if ( delta & 2 ) vpdiff += step>>1;
|
||||
if ( delta & 1 ) vpdiff += step>>2;
|
||||
|
||||
if( sign )
|
||||
valpred -= vpdiff;
|
||||
if ( sign )
|
||||
valpred -= vpdiff;
|
||||
else
|
||||
valpred += vpdiff;
|
||||
valpred += vpdiff;
|
||||
|
||||
/* Step 5 - clamp output value */
|
||||
if( valpred > 32767 )
|
||||
valpred = 32767;
|
||||
else if( valpred < -32768 )
|
||||
valpred = -32768;
|
||||
if ( valpred > 32767 )
|
||||
valpred = 32767;
|
||||
else if ( valpred < -32768 )
|
||||
valpred = -32768;
|
||||
|
||||
/* Step 6 - Update step value */
|
||||
step = stepsizeTable[ index ];
|
||||
step = stepsizeTable[index];
|
||||
|
||||
/* Step 7 - Output value */
|
||||
outdata[ outp ] = valpred;
|
||||
outdata[outp] = valpred;
|
||||
outp++;
|
||||
}
|
||||
}
|
||||
|
||||
state->sample = valpred;
|
||||
state->index = index;
|
||||
state->sample = valpred;
|
||||
state->index = index;
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +242,7 @@ int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
|
||||
int headerMemory;
|
||||
|
||||
// determine scale to convert from input sampling rate to desired sampling rate
|
||||
scale = ( float )info->rate / dma.speed;
|
||||
scale = (float)info->rate / dma.speed;
|
||||
|
||||
// calc number of samples at playback sampling rate
|
||||
scaledSampleCount = info->samples / scale;
|
||||
@@ -259,7 +257,7 @@ int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
|
||||
}
|
||||
|
||||
// calc memory needed to store the block headers
|
||||
headerMemory = blockCount * sizeof( adpcm_state_t );
|
||||
headerMemory = blockCount * sizeof(adpcm_state_t);
|
||||
|
||||
return sampleMemory + headerMemory;
|
||||
}
|
||||
@@ -270,7 +268,7 @@ int S_AdpcmMemoryNeeded( const wavinfo_t *info ) {
|
||||
S_AdpcmGetSamples
|
||||
====================
|
||||
*/
|
||||
void S_AdpcmGetSamples( sndBuffer *chunk, short *to ) {
|
||||
void S_AdpcmGetSamples(sndBuffer *chunk, short *to) {
|
||||
adpcm_state_t state;
|
||||
byte *out;
|
||||
|
||||
@@ -278,9 +276,9 @@ void S_AdpcmGetSamples( sndBuffer *chunk, short *to ) {
|
||||
state.index = chunk->adpcm.index;
|
||||
state.sample = chunk->adpcm.sample;
|
||||
|
||||
out = ( byte * )chunk->sndChunk;
|
||||
out = (byte *)chunk->sndChunk;
|
||||
// get samples
|
||||
S_AdpcmDecode( ( char * )out, to, SND_CHUNK_SIZE_BYTE * 2, &state );
|
||||
S_AdpcmDecode( out, to, SND_CHUNK_SIZE_BYTE*2, &state );
|
||||
}
|
||||
|
||||
|
||||
@@ -300,32 +298,31 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) {
|
||||
inOffset = 0;
|
||||
count = sfx->soundLength;
|
||||
state.index = 0;
|
||||
state.sample = samples[ 0 ];
|
||||
state.sample = samples[0];
|
||||
|
||||
chunk = NULL;
|
||||
while( count ) {
|
||||
n = count;
|
||||
if( n > SND_CHUNK_SIZE_BYTE * 2 ) {
|
||||
n = SND_CHUNK_SIZE_BYTE * 2;
|
||||
if( n > SND_CHUNK_SIZE_BYTE*2 ) {
|
||||
n = SND_CHUNK_SIZE_BYTE*2;
|
||||
}
|
||||
|
||||
newchunk = SND_malloc();
|
||||
if( sfx->soundData == NULL ) {
|
||||
if (sfx->soundData == NULL) {
|
||||
sfx->soundData = newchunk;
|
||||
}
|
||||
else if( chunk != NULL ) {
|
||||
} else {
|
||||
chunk->next = newchunk;
|
||||
}
|
||||
chunk = newchunk;
|
||||
|
||||
// output the header
|
||||
chunk->adpcm.index = state.index;
|
||||
chunk->adpcm.index = state.index;
|
||||
chunk->adpcm.sample = state.sample;
|
||||
|
||||
out = ( byte * )chunk->sndChunk;
|
||||
out = (byte *)chunk->sndChunk;
|
||||
|
||||
// encode the samples
|
||||
S_AdpcmEncode( samples + inOffset, ( char * )out, n, &state );
|
||||
S_AdpcmEncode( samples + inOffset, out, n, &state );
|
||||
|
||||
inOffset += n;
|
||||
count -= n;
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
static snd_codec_t *codecs;
|
||||
|
||||
/*
|
||||
=================
|
||||
S_FileExtension
|
||||
=================
|
||||
*/
|
||||
static char *S_FileExtension(const char *fni)
|
||||
{
|
||||
// we should search from the ending to the last '/'
|
||||
|
||||
char *fn = (char *) fni + strlen(fni) - 1;
|
||||
char *eptr = NULL;
|
||||
|
||||
while(*fn != '/' && fn != fni)
|
||||
{
|
||||
if(*fn == '.')
|
||||
{
|
||||
eptr = fn;
|
||||
break;
|
||||
}
|
||||
fn--;
|
||||
}
|
||||
|
||||
return eptr;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_FindCodecForFile
|
||||
|
||||
Select an appropriate codec for a file based on its extension
|
||||
=================
|
||||
*/
|
||||
static snd_codec_t *S_FindCodecForFile(const char *filename)
|
||||
{
|
||||
char *ext = S_FileExtension(filename);
|
||||
snd_codec_t *codec = codecs;
|
||||
|
||||
if(!ext)
|
||||
{
|
||||
// No extension - auto-detect
|
||||
while(codec)
|
||||
{
|
||||
char fn[MAX_QPATH];
|
||||
|
||||
// there is no extension so we do not need to subtract 4 chars
|
||||
Q_strncpyz(fn, filename, MAX_QPATH);
|
||||
COM_DefaultExtension(fn, MAX_QPATH, codec->ext);
|
||||
|
||||
// Check it exists
|
||||
if( FS_ReadFile( fn, NULL ) != -1 )
|
||||
return codec;
|
||||
|
||||
// Nope. Next!
|
||||
codec = codec->next;
|
||||
}
|
||||
|
||||
// Nothin'
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while(codec)
|
||||
{
|
||||
if(!Q_stricmp(ext, codec->ext))
|
||||
return codec;
|
||||
codec = codec->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecInit
|
||||
=================
|
||||
*/
|
||||
void S_CodecInit()
|
||||
{
|
||||
codecs = NULL;
|
||||
S_CodecRegister(&wav_codec);
|
||||
#ifdef USE_CODEC_VORBIS
|
||||
S_CodecRegister(&ogg_codec);
|
||||
#endif
|
||||
#if USE_CODEC_MP3
|
||||
S_CodecRegister(&mp3_codec);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecShutdown
|
||||
=================
|
||||
*/
|
||||
void S_CodecShutdown()
|
||||
{
|
||||
codecs = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecRegister
|
||||
=================
|
||||
*/
|
||||
void S_CodecRegister(snd_codec_t *codec)
|
||||
{
|
||||
codec->next = codecs;
|
||||
codecs = codec;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecLoad
|
||||
=================
|
||||
*/
|
||||
void *S_CodecLoad(const char *filename, snd_info_t *info)
|
||||
{
|
||||
snd_codec_t *codec;
|
||||
char fn[MAX_QPATH];
|
||||
|
||||
codec = S_FindCodecForFile(filename);
|
||||
if(!codec)
|
||||
{
|
||||
Com_Printf("Unknown extension for %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(fn, filename, sizeof(fn));
|
||||
COM_DefaultExtension(fn, sizeof(fn), codec->ext);
|
||||
|
||||
return codec->load(fn, info);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecOpenStream
|
||||
=================
|
||||
*/
|
||||
snd_stream_t *S_CodecOpenStream(const char *filename)
|
||||
{
|
||||
snd_codec_t *codec;
|
||||
char fn[MAX_QPATH];
|
||||
|
||||
codec = S_FindCodecForFile(filename);
|
||||
if(!codec)
|
||||
{
|
||||
Com_Printf("Unknown extension for %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy(fn, filename, sizeof(fn));
|
||||
COM_DefaultExtension(fn, sizeof(fn), codec->ext);
|
||||
|
||||
return codec->open(fn);
|
||||
}
|
||||
|
||||
void S_CodecCloseStream(snd_stream_t *stream)
|
||||
{
|
||||
stream->codec->close(stream);
|
||||
}
|
||||
|
||||
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
|
||||
{
|
||||
return stream->codec->read(stream, bytes, buffer);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Util functions (used by codecs)
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecUtilOpen
|
||||
=================
|
||||
*/
|
||||
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
fileHandle_t hnd;
|
||||
int length;
|
||||
|
||||
// Try to open the file
|
||||
length = FS_FOpenFileRead(filename, &hnd, qtrue, qtrue);
|
||||
if(!hnd)
|
||||
{
|
||||
Com_Printf("Can't read sound file %s\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate a stream
|
||||
stream = Z_Malloc(sizeof(snd_stream_t));
|
||||
if(!stream)
|
||||
{
|
||||
FS_FCloseFile(hnd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy over, return
|
||||
stream->codec = codec;
|
||||
stream->file = hnd;
|
||||
stream->length = length;
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_CodecUtilClose
|
||||
=================
|
||||
*/
|
||||
void S_CodecUtilClose(snd_stream_t **stream)
|
||||
{
|
||||
FS_FCloseFile((*stream)->file);
|
||||
Z_Free(*stream);
|
||||
*stream = NULL;
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef _SND_CODEC_H_
|
||||
#define _SND_CODEC_H_
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct snd_info_s
|
||||
{
|
||||
int rate;
|
||||
int width;
|
||||
int channels;
|
||||
int samples;
|
||||
int size;
|
||||
int dataofs;
|
||||
} snd_info_t;
|
||||
|
||||
typedef struct snd_codec_s snd_codec_t;
|
||||
|
||||
typedef struct snd_stream_s
|
||||
{
|
||||
snd_codec_t *codec;
|
||||
fileHandle_t file;
|
||||
snd_info_t info;
|
||||
int length;
|
||||
int pos;
|
||||
void *ptr;
|
||||
} snd_stream_t;
|
||||
|
||||
// Codec functions
|
||||
typedef void *(*CODEC_LOAD)(const char *filename, snd_info_t *info);
|
||||
typedef snd_stream_t *(*CODEC_OPEN)(const char *filename);
|
||||
typedef int (*CODEC_READ)(snd_stream_t *stream, int bytes, void *buffer);
|
||||
typedef void (*CODEC_CLOSE)(snd_stream_t *stream);
|
||||
|
||||
// Codec data structure
|
||||
struct snd_codec_s
|
||||
{
|
||||
char *ext;
|
||||
CODEC_LOAD load;
|
||||
CODEC_OPEN open;
|
||||
CODEC_READ read;
|
||||
CODEC_CLOSE close;
|
||||
snd_codec_t *next;
|
||||
};
|
||||
|
||||
// Codec management
|
||||
void S_CodecInit( void );
|
||||
void S_CodecShutdown( void );
|
||||
void S_CodecRegister(snd_codec_t *codec);
|
||||
void *S_CodecLoad(const char *filename, snd_info_t *info);
|
||||
snd_stream_t *S_CodecOpenStream(const char *filename);
|
||||
void S_CodecCloseStream(snd_stream_t *stream);
|
||||
int S_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
|
||||
|
||||
// Util functions (used by codecs)
|
||||
snd_stream_t *S_CodecUtilOpen(const char *filename, snd_codec_t *codec);
|
||||
void S_CodecUtilClose(snd_stream_t **stream);
|
||||
|
||||
// WAV Codec
|
||||
extern snd_codec_t wav_codec;
|
||||
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info);
|
||||
snd_stream_t *S_WAV_CodecOpenStream(const char *filename);
|
||||
void S_WAV_CodecCloseStream(snd_stream_t *stream);
|
||||
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
|
||||
|
||||
// Ogg Vorbis codec
|
||||
#ifdef USE_CODEC_VORBIS
|
||||
extern snd_codec_t ogg_codec;
|
||||
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info);
|
||||
snd_stream_t *S_OGG_CodecOpenStream(const char *filename);
|
||||
void S_OGG_CodecCloseStream(snd_stream_t *stream);
|
||||
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
|
||||
#endif // USE_CODEC_VORBIS
|
||||
|
||||
#if USE_CODEC_MP3
|
||||
// MP3 codec
|
||||
extern snd_codec_t mp3_codec;
|
||||
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info);
|
||||
snd_stream_t *S_MP3_CodecOpenStream(const char *filename);
|
||||
void S_MP3_CodecCloseStream(snd_stream_t *stream);
|
||||
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !_SND_CODEC_H_
|
||||
@@ -1,717 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
|
||||
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
|
||||
Copyright (C) 2006 Thilo Schulz <arny@ats.s.bawue.de>
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#if USE_CODEC_MP3
|
||||
|
||||
// includes for the Q3 sound system
|
||||
#include "client.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
// includes for the MP3 codec
|
||||
#include <mad.h>
|
||||
|
||||
#define MP3_SAMPLE_WIDTH 2
|
||||
#define MP3_PCMSAMPLES_PERSLICE 32
|
||||
|
||||
// buffer size used when reading through the mp3
|
||||
#define MP3_DATA_BUFSIZ 128*1024
|
||||
|
||||
// undefine this if you don't want any dithering.
|
||||
#define MP3_DITHERING
|
||||
|
||||
// Q3 MP3 codec
|
||||
snd_codec_t mp3_codec =
|
||||
{
|
||||
".mp3",
|
||||
S_MP3_CodecLoad,
|
||||
S_MP3_CodecOpenStream,
|
||||
S_MP3_CodecReadStream,
|
||||
S_MP3_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
// structure used for info purposes
|
||||
struct snd_codec_mp3_info
|
||||
{
|
||||
byte encbuf[MP3_DATA_BUFSIZ]; // left over bytes not consumed
|
||||
// by the decoder.
|
||||
struct mad_stream madstream; // uses encbuf as buffer.
|
||||
struct mad_frame madframe; // control structures for libmad.
|
||||
struct mad_synth madsynth;
|
||||
|
||||
byte *pcmbuf; // buffer for not-used samples.
|
||||
int buflen; // length of buffer data.
|
||||
int pcmbufsize; // amount of allocated memory for
|
||||
// pcmbuf. This should have at least
|
||||
// the size of a decoded mp3 frame.
|
||||
|
||||
byte *dest; // copy decoded data here.
|
||||
int destlen; // amount of already copied data.
|
||||
int destsize; // amount of bytes we must decode.
|
||||
};
|
||||
|
||||
/*************** MP3 utility functions ***************/
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_ReadData
|
||||
=================
|
||||
*/
|
||||
|
||||
// feed libmad with data
|
||||
int S_MP3_ReadData(snd_stream_t *stream, struct mad_stream *madstream, byte *encbuf, int encbufsize)
|
||||
{
|
||||
int retval;
|
||||
int leftover;
|
||||
|
||||
if(!stream)
|
||||
return -1;
|
||||
|
||||
leftover = madstream->bufend - madstream->next_frame;
|
||||
if(leftover > 0)
|
||||
memmove(encbuf, madstream->this_frame, leftover);
|
||||
|
||||
|
||||
// Fill the buffer right to the end
|
||||
|
||||
retval = FS_Read(&encbuf[leftover], encbufsize - leftover, stream->file);
|
||||
|
||||
if(retval <= 0)
|
||||
{
|
||||
// EOF reached, that's ok.
|
||||
return 0;
|
||||
}
|
||||
|
||||
mad_stream_buffer(madstream, encbuf, retval + leftover);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_Scanfile
|
||||
|
||||
to determine the samplecount, we apparently must get *all* headers :(
|
||||
I basically used the xmms-mad plugin source to see how this stuff works.
|
||||
|
||||
returns a value < 0 on error.
|
||||
=================
|
||||
*/
|
||||
|
||||
int S_MP3_Scanfile(snd_stream_t *stream)
|
||||
{
|
||||
struct mad_stream madstream;
|
||||
struct mad_header madheader;
|
||||
int retval;
|
||||
int samplecount;
|
||||
byte encbuf[MP3_DATA_BUFSIZ];
|
||||
|
||||
// error out on invalid input.
|
||||
if(!stream)
|
||||
return -1;
|
||||
|
||||
mad_stream_init(&madstream);
|
||||
mad_header_init(&madheader);
|
||||
|
||||
while(1)
|
||||
{
|
||||
retval = S_MP3_ReadData(stream, &madstream, encbuf, sizeof(encbuf));
|
||||
if(retval < 0)
|
||||
return -1;
|
||||
else if(retval == 0)
|
||||
break;
|
||||
|
||||
// Start decoding the headers.
|
||||
while(1)
|
||||
{
|
||||
if((retval = mad_header_decode(&madheader, &madstream)) < 0)
|
||||
{
|
||||
if(madstream.error == MAD_ERROR_BUFLEN)
|
||||
{
|
||||
// We need to read more data
|
||||
break;
|
||||
}
|
||||
|
||||
if(!MAD_RECOVERABLE (madstream.error))
|
||||
{
|
||||
// unrecoverable error... we must bail out.
|
||||
return retval;
|
||||
}
|
||||
|
||||
mad_stream_skip(&madstream, madstream.skiplen);
|
||||
continue;
|
||||
}
|
||||
|
||||
// we got a valid header.
|
||||
|
||||
if(madheader.layer != MAD_LAYER_III)
|
||||
{
|
||||
// we don't support non-mp3s
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!stream->info.samples)
|
||||
{
|
||||
// This here is the very first frame. Set initial values now,
|
||||
// that we expect to stay constant throughout the whole mp3.
|
||||
|
||||
stream->info.rate = madheader.samplerate;
|
||||
stream->info.width = MP3_SAMPLE_WIDTH;
|
||||
stream->info.channels = MAD_NCHANNELS(&madheader);
|
||||
stream->info.samples = 0;
|
||||
stream->info.size = 0; // same here.
|
||||
stream->info.dataofs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check whether something changed that shouldn't.
|
||||
|
||||
if(stream->info.rate != madheader.samplerate ||
|
||||
stream->info.channels != MAD_NCHANNELS(&madheader))
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Update the counters
|
||||
samplecount = MAD_NSBSAMPLES(&madheader) * MP3_PCMSAMPLES_PERSLICE;
|
||||
stream->info.samples += samplecount;
|
||||
stream->info.size += samplecount * stream->info.channels * stream->info.width;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the file pointer so we can do the real decoding.
|
||||
FS_Seek(stream->file, 0, FS_SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************ dithering functions ***************************/
|
||||
|
||||
#ifdef MP3_DITHERING
|
||||
|
||||
// All dithering done here is taken from the GPL'ed xmms-mad plugin.
|
||||
|
||||
/* Copyright (C) 1997 Makoto Matsumoto and Takuji Nishimura. */
|
||||
/* Any feedback is very welcome. For any question, comments, */
|
||||
/* see http://www.math.keio.ac.jp/matumoto/emt.html or email */
|
||||
/* matumoto@math.keio.ac.jp */
|
||||
|
||||
/* Period parameters */
|
||||
#define MP3_DITH_N 624
|
||||
#define MP3_DITH_M 397
|
||||
#define MATRIX_A 0x9908b0df /* constant vector a */
|
||||
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffff /* least significant r bits */
|
||||
|
||||
/* Tempering parameters */
|
||||
#define TEMPERING_MASK_B 0x9d2c5680
|
||||
#define TEMPERING_MASK_C 0xefc60000
|
||||
#define TEMPERING_SHIFT_U(y) (y >> 11)
|
||||
#define TEMPERING_SHIFT_S(y) (y << 7)
|
||||
#define TEMPERING_SHIFT_T(y) (y << 15)
|
||||
#define TEMPERING_SHIFT_L(y) (y >> 18)
|
||||
|
||||
static unsigned long mt[MP3_DITH_N]; /* the array for the state vector */
|
||||
static int mti=MP3_DITH_N+1; /* mti==MP3_DITH_N+1 means mt[MP3_DITH_N] is not initialized */
|
||||
|
||||
/* initializing the array with a NONZERO seed */
|
||||
void sgenrand(unsigned long seed)
|
||||
{
|
||||
/* setting initial seeds to mt[MP3_DITH_N] using */
|
||||
/* the generator Line 25 of Table 1 in */
|
||||
/* [KNUTH 1981, The Art of Computer Programming */
|
||||
/* Vol. 2 (2nd Ed.), pp102] */
|
||||
mt[0]= seed & 0xffffffff;
|
||||
for (mti=1; mti<MP3_DITH_N; mti++)
|
||||
mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
|
||||
}
|
||||
|
||||
unsigned long genrand(void)
|
||||
{
|
||||
unsigned long y;
|
||||
static unsigned long mag01[2]={0x0, MATRIX_A};
|
||||
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||||
|
||||
if (mti >= MP3_DITH_N) { /* generate MP3_DITH_N words at one time */
|
||||
int kk;
|
||||
|
||||
if (mti == MP3_DITH_N+1) /* if sgenrand() has not been called, */
|
||||
sgenrand(4357); /* a default initial seed is used */
|
||||
|
||||
for (kk=0;kk<MP3_DITH_N-MP3_DITH_M;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+MP3_DITH_M] ^ (y >> 1) ^ mag01[y & 0x1];
|
||||
}
|
||||
for (;kk<MP3_DITH_N-1;kk++) {
|
||||
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||||
mt[kk] = mt[kk+(MP3_DITH_M-MP3_DITH_N)] ^ (y >> 1) ^ mag01[y & 0x1];
|
||||
}
|
||||
y = (mt[MP3_DITH_N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||||
mt[MP3_DITH_N-1] = mt[MP3_DITH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];
|
||||
|
||||
mti = 0;
|
||||
}
|
||||
|
||||
y = mt[mti++];
|
||||
y ^= TEMPERING_SHIFT_U(y);
|
||||
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
|
||||
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
|
||||
y ^= TEMPERING_SHIFT_L(y);
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
long triangular_dither_noise(int nbits) {
|
||||
// parameter nbits : the peak-to-peak amplitude desired (in bits)
|
||||
// use with nbits set to 2 + nber of bits to be trimmed.
|
||||
// (because triangular is made from two uniformly distributed processes,
|
||||
// it starts at 2 bits peak-to-peak amplitude)
|
||||
// see The Theory of Dithered Quantization by Robert Alexander Wannamaker
|
||||
// for complete proof of why that's optimal
|
||||
|
||||
long v = (genrand()/2 - genrand()/2); // in ]-2^31, 2^31[
|
||||
//int signe = (v>0) ? 1 : -1;
|
||||
long P = 1 << (32 - nbits); // the power of 2
|
||||
v /= P;
|
||||
// now v in ]-2^(nbits-1), 2^(nbits-1) [
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
#endif // MP3_DITHERING
|
||||
|
||||
/************************ decoder functions ***************************/
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_Scale
|
||||
|
||||
Converts the signal to 16 bit LE-PCM data and does dithering.
|
||||
|
||||
- borrowed from xmms-mad plugin source.
|
||||
=================
|
||||
*/
|
||||
|
||||
/*
|
||||
* xmms-mad - mp3 plugin for xmms
|
||||
* Copyright (C) 2001-2002 Sam Clegg
|
||||
*/
|
||||
|
||||
signed int S_MP3_Scale(mad_fixed_t sample)
|
||||
{
|
||||
int n_bits_to_loose = MAD_F_FRACBITS + 1 - 16;
|
||||
#ifdef MP3_DITHERING
|
||||
int dither;
|
||||
#endif
|
||||
|
||||
// round
|
||||
sample += (1L << (n_bits_to_loose - 1));
|
||||
|
||||
#ifdef MP3_DITHERING
|
||||
dither = triangular_dither_noise(n_bits_to_loose + 1);
|
||||
sample += dither;
|
||||
#endif
|
||||
|
||||
/* clip */
|
||||
if (sample >= MAD_F_ONE)
|
||||
sample = MAD_F_ONE - 1;
|
||||
else if (sample < -MAD_F_ONE)
|
||||
sample = -MAD_F_ONE;
|
||||
|
||||
/* quantize */
|
||||
return sample >> n_bits_to_loose;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_PCMCopy
|
||||
|
||||
Copy and convert pcm data until bytecount bytes have been written.
|
||||
return the position in pcm->samples.
|
||||
indicate the amount of actually written bytes in wrotecnt.
|
||||
=================
|
||||
*/
|
||||
|
||||
int S_MP3_PCMCopy(byte *buf, struct mad_pcm *pcm, int bufofs,
|
||||
int sampleofs, int bytecount, int *wrotecnt)
|
||||
{
|
||||
int written = 0;
|
||||
signed int sample;
|
||||
int framesize = pcm->channels * MP3_SAMPLE_WIDTH;
|
||||
|
||||
// add new pcm data.
|
||||
while(written < bytecount && sampleofs < pcm->length)
|
||||
{
|
||||
sample = S_MP3_Scale(pcm->samples[0][sampleofs]);
|
||||
|
||||
#ifdef Q3_BIG_ENDIAN
|
||||
// output to 16 bit big endian PCM
|
||||
buf[bufofs++] = (sample >> 8) & 0xff;
|
||||
buf[bufofs++] = sample & 0xff;
|
||||
#else
|
||||
// output to 16 bit little endian PCM
|
||||
buf[bufofs++] = sample & 0xff;
|
||||
buf[bufofs++] = (sample >> 8) & 0xff;
|
||||
#endif
|
||||
|
||||
if(pcm->channels == 2)
|
||||
{
|
||||
sample = S_MP3_Scale(pcm->samples[1][sampleofs]);
|
||||
|
||||
#ifdef Q3_BIG_ENDIAN
|
||||
buf[bufofs++] = (sample >> 8) & 0xff;
|
||||
buf[bufofs++] = sample & 0xff;
|
||||
#else
|
||||
buf[bufofs++] = sample & 0xff;
|
||||
buf[bufofs++] = (sample >> 8) & 0xff;
|
||||
#endif
|
||||
}
|
||||
|
||||
sampleofs++;
|
||||
written += framesize;
|
||||
}
|
||||
|
||||
if(wrotecnt)
|
||||
*wrotecnt = written;
|
||||
|
||||
return sampleofs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_Decode
|
||||
=================
|
||||
*/
|
||||
|
||||
// gets executed for every decoded frame.
|
||||
int S_MP3_Decode(snd_stream_t *stream)
|
||||
{
|
||||
struct snd_codec_mp3_info *mp3info;
|
||||
struct mad_stream *madstream;
|
||||
struct mad_frame *madframe;
|
||||
struct mad_synth *madsynth;
|
||||
struct mad_pcm *pcm;
|
||||
int cursize;
|
||||
int samplecount;
|
||||
int needcount;
|
||||
int wrote;
|
||||
int retval;
|
||||
|
||||
if(!stream)
|
||||
return -1;
|
||||
|
||||
mp3info = stream->ptr;
|
||||
madstream = &mp3info->madstream;
|
||||
madframe = &mp3info->madframe;
|
||||
|
||||
if(mad_frame_decode(madframe, madstream))
|
||||
{
|
||||
if(madstream->error == MAD_ERROR_BUFLEN)
|
||||
{
|
||||
// we need more data. Read another chunk.
|
||||
retval = S_MP3_ReadData(stream, madstream, mp3info->encbuf, sizeof(mp3info->encbuf));
|
||||
|
||||
// call myself again now that buffer is full.
|
||||
if(retval > 0)
|
||||
retval = S_MP3_Decode(stream);
|
||||
}
|
||||
else if(MAD_RECOVERABLE(madstream->error))
|
||||
{
|
||||
mad_stream_skip(madstream, madstream->skiplen);
|
||||
return S_MP3_Decode(stream);
|
||||
}
|
||||
else
|
||||
retval = -1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// check whether this really is an mp3
|
||||
if(madframe->header.layer != MAD_LAYER_III)
|
||||
return -1;
|
||||
|
||||
// generate pcm data
|
||||
madsynth = &mp3info->madsynth;
|
||||
mad_synth_frame(madsynth, madframe);
|
||||
|
||||
pcm = &madsynth->pcm;
|
||||
|
||||
// perform a few checks to see whether something changed that shouldn't.
|
||||
|
||||
if(stream->info.rate != pcm->samplerate ||
|
||||
stream->info.channels != pcm->channels)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
// see whether we have got enough data now.
|
||||
cursize = pcm->length * pcm->channels * stream->info.width;
|
||||
needcount = mp3info->destsize - mp3info->destlen;
|
||||
|
||||
// Copy exactly as many samples as required.
|
||||
samplecount = S_MP3_PCMCopy(mp3info->dest, pcm,
|
||||
mp3info->destlen, 0, needcount, &wrote);
|
||||
mp3info->destlen += wrote;
|
||||
|
||||
if(samplecount < pcm->length)
|
||||
{
|
||||
// Not all samples got copied. Copy the rest into the pcm buffer.
|
||||
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
|
||||
mp3info->buflen,
|
||||
samplecount,
|
||||
mp3info->pcmbufsize - mp3info->buflen,
|
||||
&wrote);
|
||||
mp3info->buflen += wrote;
|
||||
|
||||
|
||||
if(samplecount < pcm->length)
|
||||
{
|
||||
// The pcm buffer was not large enough. Make it bigger.
|
||||
byte *newbuf = Z_Malloc(cursize);
|
||||
|
||||
if(mp3info->pcmbuf)
|
||||
{
|
||||
memcpy(newbuf, mp3info->pcmbuf, mp3info->buflen);
|
||||
Z_Free(mp3info->pcmbuf);
|
||||
}
|
||||
|
||||
mp3info->pcmbuf = newbuf;
|
||||
mp3info->pcmbufsize = cursize;
|
||||
|
||||
samplecount = S_MP3_PCMCopy(mp3info->pcmbuf, pcm,
|
||||
mp3info->buflen,
|
||||
samplecount,
|
||||
mp3info->pcmbufsize - mp3info->buflen,
|
||||
&wrote);
|
||||
mp3info->buflen += wrote;
|
||||
}
|
||||
|
||||
// we're definitely done.
|
||||
retval = 0;
|
||||
}
|
||||
else if(mp3info->destlen >= mp3info->destsize)
|
||||
retval = 0;
|
||||
else
|
||||
retval = 1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*************** Callback functions for quake3 ***************/
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_CodecOpenStream
|
||||
=================
|
||||
*/
|
||||
|
||||
snd_stream_t *S_MP3_CodecOpenStream(const char *filename)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
struct snd_codec_mp3_info *mp3info;
|
||||
|
||||
// Open the stream
|
||||
stream = S_CodecUtilOpen(filename, &mp3_codec);
|
||||
if(!stream || stream->length <= 0)
|
||||
return NULL;
|
||||
|
||||
// We have to scan through the MP3 to determine the important mp3 info.
|
||||
if(S_MP3_Scanfile(stream) < 0)
|
||||
{
|
||||
// scanning didn't work out...
|
||||
S_CodecUtilClose(&stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Initialize the mp3 info structure we need for streaming
|
||||
mp3info = Z_Malloc(sizeof(*mp3info));
|
||||
if(!mp3info)
|
||||
{
|
||||
S_CodecUtilClose(&stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream->ptr = mp3info;
|
||||
|
||||
// initialize the libmad control structures.
|
||||
mad_stream_init(&mp3info->madstream);
|
||||
mad_frame_init(&mp3info->madframe);
|
||||
mad_synth_init(&mp3info->madsynth);
|
||||
|
||||
if(S_MP3_ReadData(stream, &mp3info->madstream, mp3info->encbuf, sizeof(mp3info->encbuf)) <= 0)
|
||||
{
|
||||
// we didnt read anything, that's bad.
|
||||
S_MP3_CodecCloseStream(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_CodecCloseStream
|
||||
=================
|
||||
*/
|
||||
|
||||
// free all memory we allocated.
|
||||
void S_MP3_CodecCloseStream(snd_stream_t *stream)
|
||||
{
|
||||
struct snd_codec_mp3_info *mp3info;
|
||||
|
||||
if(!stream)
|
||||
return;
|
||||
|
||||
// free all data in our mp3info tree
|
||||
|
||||
if(stream->ptr)
|
||||
{
|
||||
mp3info = stream->ptr;
|
||||
|
||||
if(mp3info->pcmbuf)
|
||||
Z_Free(mp3info->pcmbuf);
|
||||
|
||||
mad_synth_finish(&mp3info->madsynth);
|
||||
mad_frame_finish(&mp3info->madframe);
|
||||
mad_stream_finish(&mp3info->madstream);
|
||||
|
||||
Z_Free(stream->ptr);
|
||||
}
|
||||
|
||||
S_CodecUtilClose(&stream);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_MP3_CodecReadStream
|
||||
=================
|
||||
*/
|
||||
int S_MP3_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
|
||||
{
|
||||
struct snd_codec_mp3_info *mp3info;
|
||||
int retval;
|
||||
|
||||
if(!stream)
|
||||
return -1;
|
||||
|
||||
mp3info = stream->ptr;
|
||||
|
||||
// Make sure we get complete frames all the way through.
|
||||
bytes -= bytes % (stream->info.channels * stream->info.width);
|
||||
|
||||
if(mp3info->buflen)
|
||||
{
|
||||
if(bytes < mp3info->buflen)
|
||||
{
|
||||
// we still have enough bytes in our decoded pcm buffer
|
||||
memcpy(buffer, mp3info->pcmbuf, bytes);
|
||||
|
||||
// remove the portion from our buffer.
|
||||
mp3info->buflen -= bytes;
|
||||
memmove(mp3info->pcmbuf, &mp3info->pcmbuf[bytes], mp3info->buflen);
|
||||
return bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy over the samples we already have.
|
||||
memcpy(buffer, mp3info->pcmbuf, mp3info->buflen);
|
||||
mp3info->destlen = mp3info->buflen;
|
||||
mp3info->buflen = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
mp3info->destlen = 0;
|
||||
|
||||
mp3info->dest = buffer;
|
||||
mp3info->destsize = bytes;
|
||||
|
||||
do
|
||||
{
|
||||
retval = S_MP3_Decode(stream);
|
||||
} while(retval > 0);
|
||||
|
||||
// if there was an error return nothing.
|
||||
if(retval < 0)
|
||||
return 0;
|
||||
|
||||
return mp3info->destlen;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
S_MP3_CodecLoad
|
||||
|
||||
We handle S_MP3_CodecLoad as a special case of the streaming functions
|
||||
where we read the whole stream at once.
|
||||
======================================================================
|
||||
*/
|
||||
void *S_MP3_CodecLoad(const char *filename, snd_info_t *info)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
byte *pcmbuffer;
|
||||
|
||||
// check if input is valid
|
||||
if(!filename)
|
||||
return NULL;
|
||||
|
||||
stream = S_MP3_CodecOpenStream(filename);
|
||||
|
||||
if(!stream)
|
||||
return NULL;
|
||||
|
||||
// copy over the info
|
||||
info->rate = stream->info.rate;
|
||||
info->width = stream->info.width;
|
||||
info->channels = stream->info.channels;
|
||||
info->samples = stream->info.samples;
|
||||
info->dataofs = stream->info.dataofs;
|
||||
|
||||
// allocate enough buffer for all pcm data
|
||||
// pcmbuffer = Z_Malloc(stream->info.size);
|
||||
pcmbuffer = Hunk_AllocateTempMemory(stream->info.size);
|
||||
|
||||
if(!pcmbuffer)
|
||||
{
|
||||
S_MP3_CodecCloseStream(stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info->size = S_MP3_CodecReadStream(stream, stream->info.size, pcmbuffer);
|
||||
|
||||
if(info->size <= 0)
|
||||
{
|
||||
// we didn't read anything at all. darn.
|
||||
// Z_Free(pcmbuffer);
|
||||
Hunk_FreeTempMemory(pcmbuffer);
|
||||
pcmbuffer = NULL;
|
||||
}
|
||||
|
||||
S_MP3_CodecCloseStream(stream);
|
||||
|
||||
return pcmbuffer;
|
||||
}
|
||||
#endif
|
||||
@@ -1,474 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
|
||||
Copyright (C) 2005-2006 Joerg Dietrich <dietrich_joerg@gmx.de>
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
// OGG support is enabled by this define
|
||||
#ifdef USE_CODEC_VORBIS
|
||||
|
||||
// includes for the Q3 sound system
|
||||
#include "client.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
// includes for the OGG codec
|
||||
#include <errno.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
// The OGG codec can return the samples in a number of different formats,
|
||||
// we use the standard signed short format.
|
||||
#define OGG_SAMPLEWIDTH 2
|
||||
|
||||
// Q3 OGG codec
|
||||
snd_codec_t ogg_codec =
|
||||
{
|
||||
".ogg",
|
||||
S_OGG_CodecLoad,
|
||||
S_OGG_CodecOpenStream,
|
||||
S_OGG_CodecReadStream,
|
||||
S_OGG_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
// callbacks for vobisfile
|
||||
|
||||
// fread() replacement
|
||||
size_t S_OGG_Callback_read(void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
int byteSize = 0;
|
||||
int bytesRead = 0;
|
||||
size_t nMembRead = 0;
|
||||
|
||||
// check if input is valid
|
||||
if(!ptr)
|
||||
{
|
||||
errno = EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!(size && nmemb))
|
||||
{
|
||||
// It's not an error, caller just wants zero bytes!
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!datasource)
|
||||
{
|
||||
errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// we use a snd_stream_t in the generic pointer to pass around
|
||||
stream = (snd_stream_t *) datasource;
|
||||
|
||||
// FS_Read does not support multi-byte elements
|
||||
byteSize = nmemb * size;
|
||||
|
||||
// read it with the Q3 function FS_Read()
|
||||
bytesRead = FS_Read(ptr, byteSize, stream->file);
|
||||
|
||||
// update the file position
|
||||
stream->pos += bytesRead;
|
||||
|
||||
// this function returns the number of elements read not the number of bytes
|
||||
nMembRead = bytesRead / size;
|
||||
|
||||
// even if the last member is only read partially
|
||||
// it is counted as a whole in the return value
|
||||
if(bytesRead % size)
|
||||
{
|
||||
nMembRead++;
|
||||
}
|
||||
|
||||
return nMembRead;
|
||||
}
|
||||
|
||||
// fseek() replacement
|
||||
int S_OGG_Callback_seek(void *datasource, ogg_int64_t offset, int whence)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
int retVal = 0;
|
||||
|
||||
// check if input is valid
|
||||
if(!datasource)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// snd_stream_t in the generic pointer
|
||||
stream = (snd_stream_t *) datasource;
|
||||
|
||||
// we must map the whence to its Q3 counterpart
|
||||
switch(whence)
|
||||
{
|
||||
case SEEK_SET :
|
||||
{
|
||||
// set the file position in the actual file with the Q3 function
|
||||
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET);
|
||||
|
||||
// something has gone wrong, so we return here
|
||||
if(!(retVal == 0))
|
||||
{
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// keep track of file position
|
||||
stream->pos = (int) offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEK_CUR :
|
||||
{
|
||||
// set the file position in the actual file with the Q3 function
|
||||
retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR);
|
||||
|
||||
// something has gone wrong, so we return here
|
||||
if(!(retVal == 0))
|
||||
{
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// keep track of file position
|
||||
stream->pos += (int) offset;
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEK_END :
|
||||
{
|
||||
// Quake 3 seems to have trouble with FS_SEEK_END
|
||||
// so we use the file length and FS_SEEK_SET
|
||||
|
||||
// set the file position in the actual file with the Q3 function
|
||||
retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET);
|
||||
|
||||
// something has gone wrong, so we return here
|
||||
if(!(retVal == 0))
|
||||
{
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// keep track of file position
|
||||
stream->pos = stream->length + (int) offset;
|
||||
break;
|
||||
}
|
||||
|
||||
default :
|
||||
{
|
||||
// unknown whence, so we return an error
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// stream->pos shouldn't be smaller than zero or bigger than the filesize
|
||||
stream->pos = (stream->pos < 0) ? 0 : stream->pos;
|
||||
stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fclose() replacement
|
||||
int S_OGG_Callback_close(void *datasource)
|
||||
{
|
||||
// we do nothing here and close all things manually in S_OGG_CodecCloseStream()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ftell() replacement
|
||||
long S_OGG_Callback_tell(void *datasource)
|
||||
{
|
||||
// check if input is valid
|
||||
if(!datasource)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// we keep track of the file position in stream->pos
|
||||
return (long) (((snd_stream_t *) datasource) -> pos);
|
||||
}
|
||||
|
||||
// the callback structure
|
||||
const ov_callbacks S_OGG_Callbacks =
|
||||
{
|
||||
&S_OGG_Callback_read,
|
||||
&S_OGG_Callback_seek,
|
||||
&S_OGG_Callback_close,
|
||||
&S_OGG_Callback_tell
|
||||
};
|
||||
|
||||
/*
|
||||
=================
|
||||
S_OGG_CodecOpenStream
|
||||
=================
|
||||
*/
|
||||
snd_stream_t *S_OGG_CodecOpenStream(const char *filename)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
|
||||
// OGG codec control structure
|
||||
OggVorbis_File *vf;
|
||||
|
||||
// some variables used to get informations about the OGG
|
||||
vorbis_info *OGGInfo;
|
||||
ogg_int64_t numSamples;
|
||||
|
||||
// check if input is valid
|
||||
if(!filename)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Open the stream
|
||||
stream = S_CodecUtilOpen(filename, &ogg_codec);
|
||||
if(!stream)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// alloctate the OggVorbis_File
|
||||
vf = Z_Malloc(sizeof(OggVorbis_File));
|
||||
if(!vf)
|
||||
{
|
||||
S_CodecUtilClose(&stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// open the codec with our callbacks and stream as the generic pointer
|
||||
if(ov_open_callbacks(stream, vf, NULL, 0, S_OGG_Callbacks) != 0)
|
||||
{
|
||||
Z_Free(vf);
|
||||
|
||||
S_CodecUtilClose(&stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// the stream must be seekable
|
||||
if(!ov_seekable(vf))
|
||||
{
|
||||
ov_clear(vf);
|
||||
|
||||
Z_Free(vf);
|
||||
|
||||
S_CodecUtilClose(&stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// we only support OGGs with one substream
|
||||
if(ov_streams(vf) != 1)
|
||||
{
|
||||
ov_clear(vf);
|
||||
|
||||
Z_Free(vf);
|
||||
|
||||
S_CodecUtilClose(&stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get the info about channels and rate
|
||||
OGGInfo = ov_info(vf, 0);
|
||||
if(!OGGInfo)
|
||||
{
|
||||
ov_clear(vf);
|
||||
|
||||
Z_Free(vf);
|
||||
|
||||
S_CodecUtilClose(&stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get the number of sample-frames in the OGG
|
||||
numSamples = ov_pcm_total(vf, 0);
|
||||
|
||||
// fill in the info-structure in the stream
|
||||
stream->info.rate = OGGInfo->rate;
|
||||
stream->info.width = OGG_SAMPLEWIDTH;
|
||||
stream->info.channels = OGGInfo->channels;
|
||||
stream->info.samples = numSamples;
|
||||
stream->info.size = stream->info.samples * stream->info.channels * stream->info.width;
|
||||
stream->info.dataofs = 0;
|
||||
|
||||
// We use stream->pos for the file pointer in the compressed ogg file
|
||||
stream->pos = 0;
|
||||
|
||||
// We use the generic pointer in stream for the OGG codec control structure
|
||||
stream->ptr = vf;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_OGG_CodecCloseStream
|
||||
=================
|
||||
*/
|
||||
void S_OGG_CodecCloseStream(snd_stream_t *stream)
|
||||
{
|
||||
// check if input is valid
|
||||
if(!stream)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// let the OGG codec cleanup its stuff
|
||||
ov_clear((OggVorbis_File *) stream->ptr);
|
||||
|
||||
// free the OGG codec control struct
|
||||
Z_Free(stream->ptr);
|
||||
|
||||
// close the stream
|
||||
S_CodecUtilClose(&stream);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_OGG_CodecReadStream
|
||||
=================
|
||||
*/
|
||||
int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
|
||||
{
|
||||
// buffer handling
|
||||
int bytesRead, bytesLeft, c;
|
||||
char *bufPtr;
|
||||
|
||||
// Bitstream for the decoder
|
||||
int BS = 0;
|
||||
|
||||
// big endian machines want their samples in big endian order
|
||||
int IsBigEndian = 0;
|
||||
|
||||
# ifdef Q3_BIG_ENDIAN
|
||||
IsBigEndian = 1;
|
||||
# endif // Q3_BIG_ENDIAN
|
||||
|
||||
// check if input is valid
|
||||
if(!(stream && buffer))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bytes <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bytesRead = 0;
|
||||
bytesLeft = bytes;
|
||||
bufPtr = buffer;
|
||||
|
||||
// cycle until we have the requested or all available bytes read
|
||||
while(-1)
|
||||
{
|
||||
// read some bytes from the OGG codec
|
||||
c = ov_read((OggVorbis_File *) stream->ptr, bufPtr, bytesLeft, IsBigEndian, OGG_SAMPLEWIDTH, 1, &BS);
|
||||
|
||||
// no more bytes are left
|
||||
if(c <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
bytesRead += c;
|
||||
bytesLeft -= c;
|
||||
bufPtr += c;
|
||||
|
||||
// we have enough bytes
|
||||
if(bytesLeft <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/*
|
||||
=====================================================================
|
||||
S_OGG_CodecLoad
|
||||
|
||||
We handle S_OGG_CodecLoad as a special case of the streaming functions
|
||||
where we read the whole stream at once.
|
||||
======================================================================
|
||||
*/
|
||||
void *S_OGG_CodecLoad(const char *filename, snd_info_t *info)
|
||||
{
|
||||
snd_stream_t *stream;
|
||||
byte *buffer;
|
||||
int bytesRead;
|
||||
|
||||
// check if input is valid
|
||||
if(!(filename && info))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// open the file as a stream
|
||||
stream = S_OGG_CodecOpenStream(filename);
|
||||
if(!stream)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// copy over the info
|
||||
info->rate = stream->info.rate;
|
||||
info->width = stream->info.width;
|
||||
info->channels = stream->info.channels;
|
||||
info->samples = stream->info.samples;
|
||||
info->size = stream->info.size;
|
||||
info->dataofs = stream->info.dataofs;
|
||||
|
||||
// allocate a buffer
|
||||
// this buffer must be free-ed by the caller of this function
|
||||
// buffer = Z_Malloc(info->size);
|
||||
buffer = Hunk_AllocateTempMemory(info->size);
|
||||
if(!buffer)
|
||||
{
|
||||
S_OGG_CodecCloseStream(stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// fill the buffer
|
||||
bytesRead = S_OGG_CodecReadStream(stream, info->size, buffer);
|
||||
|
||||
// we don't even have read a single byte
|
||||
if(bytesRead <= 0)
|
||||
{
|
||||
Z_Free(buffer);
|
||||
S_OGG_CodecCloseStream(stream);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
S_OGG_CodecCloseStream(stream);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endif // USE_CODEC_VORBIS
|
||||
@@ -1,296 +0,0 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1999-2005 Id Software, Inc.
|
||||
Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com)
|
||||
|
||||
This file is part of Quake III Arena source code.
|
||||
|
||||
Quake III Arena source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake III Arena source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
/*
|
||||
=================
|
||||
FGetLittleLong
|
||||
=================
|
||||
*/
|
||||
static int FGetLittleLong( fileHandle_t f ) {
|
||||
int v;
|
||||
|
||||
FS_Read( &v, sizeof(v), f );
|
||||
|
||||
return LittleLong( v);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
FGetLittleShort
|
||||
=================
|
||||
*/
|
||||
static short FGetLittleShort( fileHandle_t f ) {
|
||||
short v;
|
||||
|
||||
FS_Read( &v, sizeof(v), f );
|
||||
|
||||
return LittleShort( v);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_ReadChunkInfo
|
||||
=================
|
||||
*/
|
||||
static int S_ReadChunkInfo(fileHandle_t f, char *name)
|
||||
{
|
||||
int len, r;
|
||||
|
||||
name[4] = 0;
|
||||
|
||||
r = FS_Read(name, 4, f);
|
||||
if(r != 4)
|
||||
return -1;
|
||||
|
||||
len = FGetLittleLong(f);
|
||||
if( len < 0 ) {
|
||||
Com_Printf( S_COLOR_YELLOW "WARNING: Negative chunk length\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_FindRIFFChunk
|
||||
|
||||
Returns the length of the data in the chunk, or -1 if not found
|
||||
=================
|
||||
*/
|
||||
static int S_FindRIFFChunk( fileHandle_t f, char *chunk ) {
|
||||
char name[5];
|
||||
int len;
|
||||
|
||||
while( ( len = S_ReadChunkInfo(f, name) ) >= 0 )
|
||||
{
|
||||
// If this is the right chunk, return
|
||||
if( !Q_strncmp( name, chunk, 4 ) )
|
||||
return len;
|
||||
|
||||
len = PAD( len, 2 );
|
||||
|
||||
// Not the right chunk - skip it
|
||||
FS_Seek( f, len, FS_SEEK_CUR );
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_ByteSwapRawSamples
|
||||
=================
|
||||
*/
|
||||
static void S_ByteSwapRawSamples( int samples, int width, int s_channels, const byte *data ) {
|
||||
int i;
|
||||
|
||||
if ( width != 2 ) {
|
||||
return;
|
||||
}
|
||||
if ( LittleShort( 256 ) == 256 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( s_channels == 2 ) {
|
||||
samples <<= 1;
|
||||
}
|
||||
for ( i = 0 ; i < samples ; i++ ) {
|
||||
((short *)data)[i] = LittleShort( ((short *)data)[i] );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_ReadRIFFHeader
|
||||
=================
|
||||
*/
|
||||
static qboolean S_ReadRIFFHeader(fileHandle_t file, snd_info_t *info)
|
||||
{
|
||||
char dump[16];
|
||||
int wav_format;
|
||||
int bits;
|
||||
int fmtlen = 0;
|
||||
|
||||
// skip the riff wav header
|
||||
FS_Read(dump, 12, file);
|
||||
|
||||
// Scan for the format chunk
|
||||
if((fmtlen = S_FindRIFFChunk(file, "fmt ")) < 0)
|
||||
{
|
||||
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"fmt\" chunk\n");
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// Save the parameters
|
||||
wav_format = FGetLittleShort(file);
|
||||
info->channels = FGetLittleShort(file);
|
||||
info->rate = FGetLittleLong(file);
|
||||
FGetLittleLong(file);
|
||||
FGetLittleShort(file);
|
||||
bits = FGetLittleShort(file);
|
||||
|
||||
if( bits < 8 )
|
||||
{
|
||||
Com_Printf( S_COLOR_RED "ERROR: Less than 8 bit sound is not supported\n");
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
info->width = bits / 8;
|
||||
info->dataofs = 0;
|
||||
|
||||
// Skip the rest of the format chunk if required
|
||||
if(fmtlen > 16)
|
||||
{
|
||||
fmtlen -= 16;
|
||||
FS_Seek( file, fmtlen, FS_SEEK_CUR );
|
||||
}
|
||||
|
||||
// Scan for the data chunk
|
||||
if( (info->size = S_FindRIFFChunk(file, "data")) < 0)
|
||||
{
|
||||
Com_Printf( S_COLOR_RED "ERROR: Couldn't find \"data\" chunk\n");
|
||||
return qfalse;
|
||||
}
|
||||
info->samples = (info->size / info->width) / info->channels;
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
// WAV codec
|
||||
snd_codec_t wav_codec =
|
||||
{
|
||||
".wav",
|
||||
S_WAV_CodecLoad,
|
||||
S_WAV_CodecOpenStream,
|
||||
S_WAV_CodecReadStream,
|
||||
S_WAV_CodecCloseStream,
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
=================
|
||||
S_WAV_CodecLoad
|
||||
=================
|
||||
*/
|
||||
void *S_WAV_CodecLoad(const char *filename, snd_info_t *info)
|
||||
{
|
||||
fileHandle_t file;
|
||||
void *buffer;
|
||||
|
||||
// Try to open the file
|
||||
FS_FOpenFileRead(filename, &file, qtrue, qtrue);
|
||||
if(!file)
|
||||
{
|
||||
Com_Printf( S_COLOR_RED "ERROR: Could not open \"%s\"\n",
|
||||
filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the RIFF header
|
||||
if(!S_ReadRIFFHeader(file, info))
|
||||
{
|
||||
FS_FCloseFile(file);
|
||||
Com_Printf( S_COLOR_RED "ERROR: Incorrect/unsupported format in \"%s\"\n",
|
||||
filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate some memory
|
||||
// buffer = Z_Malloc(info->size);
|
||||
buffer = Hunk_AllocateTempMemory(info->size);
|
||||
|
||||
if(!buffer)
|
||||
{
|
||||
FS_FCloseFile(file);
|
||||
Com_Printf( S_COLOR_RED "ERROR: Out of memory reading \"%s\"\n",
|
||||
filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read, byteswap
|
||||
FS_Read(buffer, info->size, file);
|
||||
S_ByteSwapRawSamples(info->samples, info->width, info->channels, (byte *)buffer);
|
||||
|
||||
// Close and return
|
||||
FS_FCloseFile(file);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_WAV_CodecOpenStream
|
||||
=================
|
||||
*/
|
||||
snd_stream_t *S_WAV_CodecOpenStream(const char *filename)
|
||||
{
|
||||
snd_stream_t *rv;
|
||||
|
||||
// Open
|
||||
rv = S_CodecUtilOpen(filename, &wav_codec);
|
||||
if(!rv)
|
||||
return NULL;
|
||||
|
||||
// Read the RIFF header
|
||||
if(!S_ReadRIFFHeader(rv->file, &rv->info))
|
||||
{
|
||||
S_CodecUtilClose(&rv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_WAV_CodecCloseStream
|
||||
=================
|
||||
*/
|
||||
void S_WAV_CodecCloseStream(snd_stream_t *stream)
|
||||
{
|
||||
S_CodecUtilClose(&stream);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_WAV_CodecReadStream
|
||||
=================
|
||||
*/
|
||||
int S_WAV_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer)
|
||||
{
|
||||
int remaining = stream->info.size - stream->pos;
|
||||
int samples;
|
||||
|
||||
if(remaining <= 0)
|
||||
return 0;
|
||||
if(bytes > remaining)
|
||||
bytes = remaining;
|
||||
stream->pos += bytes;
|
||||
samples = (bytes / stream->info.width) / stream->info.channels;
|
||||
FS_Read(buffer, bytes, stream->file);
|
||||
S_ByteSwapRawSamples(samples, stream->info.width, stream->info.channels, buffer);
|
||||
return bytes;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+48
-169
@@ -15,14 +15,14 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with Foobar; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
// snd_local.h -- private sound definations
|
||||
|
||||
|
||||
#include "../qcommon/q_shared.h"
|
||||
#include "q_shared.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "snd_public.h"
|
||||
|
||||
@@ -36,8 +36,6 @@ extern "C" {
|
||||
#define SND_CHUNK_SIZE_FLOAT (SND_CHUNK_SIZE/2) // floats
|
||||
#define SND_CHUNK_SIZE_BYTE (SND_CHUNK_SIZE*2) // floats
|
||||
|
||||
#define SFX_FLAG_STREAMED 4
|
||||
|
||||
typedef struct {
|
||||
int left; // the final values will be clamped to +/- 0x00ffff00 and shifted down
|
||||
int right;
|
||||
@@ -55,6 +53,18 @@ typedef struct sndBuffer_s {
|
||||
adpcm_state_t adpcm;
|
||||
} sndBuffer;
|
||||
|
||||
typedef struct sfx_s {
|
||||
sndBuffer *soundData;
|
||||
qboolean defaultSound; // couldn't be loaded, so use buzz
|
||||
qboolean inMemory; // not in Memory
|
||||
qboolean soundCompressed; // not in Memory
|
||||
int soundCompressionMethod;
|
||||
int soundLength;
|
||||
char soundName[MAX_QPATH];
|
||||
int lastTimeUsed;
|
||||
struct sfx_s *next;
|
||||
} sfx_t;
|
||||
|
||||
typedef struct {
|
||||
int channels;
|
||||
int samples; // mono samples in buffer
|
||||
@@ -64,87 +74,8 @@ typedef struct {
|
||||
byte *buffer;
|
||||
} dma_t;
|
||||
|
||||
typedef struct sfx_s {
|
||||
sndBuffer *soundData;
|
||||
qboolean defaultSound; // couldn't be loaded, so use buzz
|
||||
qboolean inMemory; // not in Memory
|
||||
qboolean soundCompressed; // not in Memory
|
||||
int soundCompressionMethod;
|
||||
int soundLength;
|
||||
int soundChannels;
|
||||
char soundName[MAX_QPATH];
|
||||
int lastTimeUsed;
|
||||
int iFlags;
|
||||
struct sfx_s *next;
|
||||
} sfx_t;
|
||||
|
||||
typedef struct {
|
||||
char name[ MAX_QPATH ];
|
||||
int loop_start;
|
||||
int loop_end;
|
||||
int max_number_playing;
|
||||
float max_factor;
|
||||
} sfx_info_t;
|
||||
|
||||
typedef struct {
|
||||
vec3_t position;
|
||||
vec3_t velocity;
|
||||
int time;
|
||||
qboolean use_listener;
|
||||
} s_entity_t;
|
||||
|
||||
typedef struct {
|
||||
char alias[ 32 ];
|
||||
char path[ MAX_QPATH ];
|
||||
int mood_num;
|
||||
int flags;
|
||||
float volume;
|
||||
float fadetime;
|
||||
int current_pos;
|
||||
int current_state;
|
||||
} song_t;
|
||||
|
||||
typedef struct {
|
||||
int iFlags;
|
||||
char szName[ MAX_QPATH ];
|
||||
} sfxsavegame_t;
|
||||
|
||||
typedef struct channelbasesavegame_s {
|
||||
qboolean bPlaying;
|
||||
int iStatus;
|
||||
|
||||
sfxsavegame_t sfx;
|
||||
|
||||
int iEntNum;
|
||||
int iEntChannel;
|
||||
|
||||
vec3_t vOrigin;
|
||||
float fVolume;
|
||||
int iBaseRate;
|
||||
float fNewPitchMult;
|
||||
float fMinDist;
|
||||
float fMaxDist;
|
||||
|
||||
int iStartTime;
|
||||
int iTime;
|
||||
int iNextCheckObstructionTime;
|
||||
int iEndTime;
|
||||
|
||||
int iFlags;
|
||||
int iOffset;
|
||||
int iLoopCount;
|
||||
} channelbasesavegame_t;
|
||||
|
||||
typedef struct soundsystemsavegame_s {
|
||||
channelbasesavegame_t Channels[ 96 ];
|
||||
} soundsystemsavegame_t;
|
||||
|
||||
#define START_SAMPLE_IMMEDIATE 0x7fffffff
|
||||
|
||||
#define MAX_DOPPLER_SCALE 50.0f //arbitrary
|
||||
|
||||
#define THIRD_PERSON_THRESHOLD_SQ (48.0f*48.0f)
|
||||
|
||||
typedef struct loopSound_s {
|
||||
vec3_t origin;
|
||||
vec3_t velocity;
|
||||
@@ -158,7 +89,8 @@ typedef struct loopSound_s {
|
||||
int framenum;
|
||||
} loopSound_t;
|
||||
|
||||
typedef struct channel_s {
|
||||
typedef struct
|
||||
{
|
||||
int allocTime;
|
||||
int startSample; // START_SAMPLE_IMMEDIATE = set immediately on next mix
|
||||
int entnum; // to allow overriding a specific sound
|
||||
@@ -172,7 +104,6 @@ typedef struct channel_s {
|
||||
qboolean fixed_origin; // use origin instead of fetching entnum's origin
|
||||
sfx_t *thesfx; // sfx structure
|
||||
qboolean doppler;
|
||||
qboolean fullVolume;
|
||||
} channel_t;
|
||||
|
||||
|
||||
@@ -188,48 +119,6 @@ typedef struct {
|
||||
int dataofs; // chunk starts this many bytes from file start
|
||||
} wavinfo_t;
|
||||
|
||||
typedef struct {
|
||||
float volume;
|
||||
float minDist;
|
||||
float pitch;
|
||||
float maxDist;
|
||||
qboolean streamed;
|
||||
int flags;
|
||||
} sndparm_t;
|
||||
|
||||
// Interface between Q3 sound "api" and the sound backend
|
||||
typedef struct
|
||||
{
|
||||
void (*Shutdown)(void);
|
||||
void (*StartSound)( const vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx );
|
||||
void (*StartLocalSound)( sfxHandle_t sfx, int channelNum );
|
||||
void (*StartBackgroundTrack)( const char *intro, const char *loop );
|
||||
void (*StopBackgroundTrack)( void );
|
||||
void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume, int entityNum);
|
||||
void (*StopAllSounds)( void );
|
||||
void (*ClearLoopingSounds)( qboolean killall );
|
||||
void (*AddLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
||||
void (*AddRealLoopingSound)( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
||||
void (*StopLoopingSound)(int entityNum );
|
||||
void (*Respatialize)( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
|
||||
void (*UpdateEntity)( int entityNum, const vec3_t origin, const vec3_t velocity );
|
||||
void (*Update)( void );
|
||||
void (*DisableSounds)( void );
|
||||
void (*BeginRegistration)( void );
|
||||
sfxHandle_t (*RegisterSound)( const char *sample, qboolean compressed );
|
||||
qboolean (*IsSoundPlaying)( int channelNumber, const char *name );
|
||||
void (*ClearSoundBuffer)( void );
|
||||
void (*SoundInfo)( void );
|
||||
void (*SoundList)( void );
|
||||
#ifdef USE_VOIP
|
||||
void (*StartCapture)( void );
|
||||
int (*AvailableCaptureSamples)( void );
|
||||
void (*Capture)( int samples, byte *data );
|
||||
void (*StopCapture)( void );
|
||||
void (*MasterGain)( float gain );
|
||||
#endif
|
||||
} soundInterface_t;
|
||||
|
||||
|
||||
/*
|
||||
====================================================================
|
||||
@@ -254,86 +143,76 @@ void SNDDMA_Submit(void);
|
||||
|
||||
//====================================================================
|
||||
|
||||
#define MAX_SOUNDCHANNELS 96
|
||||
#define MAX_CHANNELS 96
|
||||
|
||||
extern channel_t s_channels[MAX_SOUNDCHANNELS];
|
||||
extern channel_t loop_channels[MAX_SOUNDCHANNELS];
|
||||
extern channel_t s_channels[MAX_CHANNELS];
|
||||
extern channel_t loop_channels[MAX_CHANNELS];
|
||||
extern int numLoopChannels;
|
||||
|
||||
extern int s_paintedtime;
|
||||
extern int s_rawend;
|
||||
extern vec3_t listener_forward;
|
||||
extern vec3_t listener_right;
|
||||
extern vec3_t listener_up;
|
||||
extern dma_t dma;
|
||||
|
||||
#define MAX_RAW_SAMPLES 16384
|
||||
#define MAX_RAW_STREAMS (MAX_CLIENTS * 2 + 1)
|
||||
extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
|
||||
extern int s_rawend[MAX_RAW_STREAMS];
|
||||
extern portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES];
|
||||
|
||||
extern cvar_t *s_volume;
|
||||
extern cvar_t *s_musicVolume;
|
||||
extern cvar_t *s_muted;
|
||||
extern cvar_t *s_doppler;
|
||||
extern cvar_t *s_volume;
|
||||
extern cvar_t *s_nosound;
|
||||
extern cvar_t *s_khz;
|
||||
extern cvar_t *s_show;
|
||||
extern cvar_t *s_mixahead;
|
||||
|
||||
extern cvar_t *s_testsound;
|
||||
|
||||
extern sndparm_t soundparm;
|
||||
extern cvar_t *s_testsound;
|
||||
extern cvar_t *s_separation;
|
||||
|
||||
qboolean S_LoadSound( sfx_t *sfx );
|
||||
|
||||
void SND_free( sndBuffer *v );
|
||||
sndBuffer* SND_malloc( void );
|
||||
void SND_setup( void );
|
||||
void SND_shutdown( void );
|
||||
void SND_free(sndBuffer *v);
|
||||
sndBuffer* SND_malloc();
|
||||
void SND_setup();
|
||||
|
||||
void S_PaintChannels( int endtime );
|
||||
void S_PaintChannels(int endtime);
|
||||
|
||||
void S_memoryLoad( sfx_t *sfx );
|
||||
void S_memoryLoad(sfx_t *sfx);
|
||||
portable_samplepair_t *S_GetRawSamplePointer();
|
||||
|
||||
// spatializes a channel
|
||||
void S_Spatialize( channel_t *ch );
|
||||
void S_Spatialize(channel_t *ch);
|
||||
|
||||
// adpcm functions
|
||||
int S_AdpcmMemoryNeeded( const wavinfo_t *info );
|
||||
void S_AdpcmEncodeSound( sfx_t *sfx, short *samples );
|
||||
void S_AdpcmGetSamples( sndBuffer *chunk, short *to );
|
||||
void S_AdpcmGetSamples(sndBuffer *chunk, short *to);
|
||||
|
||||
// wavelet function
|
||||
|
||||
#define SENTINEL_MULAW_ZERO_RUN 127
|
||||
#define SENTINEL_MULAW_FOUR_BIT_RUN 126
|
||||
|
||||
void S_FreeOldestSound( void );
|
||||
void S_FreeOldestSound();
|
||||
|
||||
#define NXStream byte
|
||||
|
||||
void encodeWavelet( sfx_t *sfx, short *packets );
|
||||
void decodeWavelet( sndBuffer *stream, short *packets );
|
||||
void encodeWavelet(sfx_t *sfx, short *packets);
|
||||
void decodeWavelet( sndBuffer *stream, short *packets);
|
||||
|
||||
void encodeMuLaw( sfx_t *sfx, short *packets );
|
||||
extern short mulawToShort[ 256 ];
|
||||
void encodeMuLaw( sfx_t *sfx, short *packets);
|
||||
extern short mulawToShort[256];
|
||||
|
||||
extern short *sfxScratchBuffer;
|
||||
extern sfx_t *sfxScratchPointer;
|
||||
extern int sfxScratchIndex;
|
||||
|
||||
qboolean S_Base_Init( soundInterface_t *si );
|
||||
|
||||
// OpenAL stuff
|
||||
typedef enum
|
||||
{
|
||||
SRCPRI_AMBIENT = 0, // Ambient sound effects
|
||||
SRCPRI_ENTITY, // Entity sound effects
|
||||
SRCPRI_ONESHOT, // One-shot sounds
|
||||
SRCPRI_LOCAL, // Local sounds
|
||||
SRCPRI_STREAM // Streams (music, cutscenes)
|
||||
} alSrcPriority_t;
|
||||
|
||||
typedef int srcHandle_t;
|
||||
|
||||
void callbackServer( int entnum, int channel_number, const char *name );
|
||||
qboolean S_AL_Init( soundInterface_t *si );
|
||||
#ifdef __linux__
|
||||
// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=371
|
||||
// custom Snd_Memset implementation for glibc memset bug workaround
|
||||
void Snd_Memset(void* dest, const int val, const size_t count);
|
||||
#else
|
||||
#define Snd_Memset Com_Memset
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+479
-572
File diff suppressed because it is too large.
Load diff
+236
-108
@@ -15,22 +15,21 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with Foobar; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* name: snd_mem.c
|
||||
*
|
||||
* desc: sound caching
|
||||
*
|
||||
* $Archive: /MissionPack/code/client/snd_mem.c $
|
||||
*
|
||||
*****************************************************************************/
|
||||
* name: snd_mem.c
|
||||
*
|
||||
* desc: sound caching
|
||||
*
|
||||
* $Archive: /MissionPack/code/client/snd_mem.c $
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "snd_local.h"
|
||||
#include "snd_codec.h"
|
||||
|
||||
#define DEF_COMSOUNDMEGS "8"
|
||||
|
||||
@@ -51,61 +50,186 @@ short *sfxScratchBuffer = NULL;
|
||||
sfx_t *sfxScratchPointer = NULL;
|
||||
int sfxScratchIndex = 0;
|
||||
|
||||
void SND_free( sndBuffer *v ) {
|
||||
*( sndBuffer ** )v = freelist;
|
||||
freelist = ( sndBuffer* )v;
|
||||
inUse += sizeof( sndBuffer );
|
||||
void SND_free(sndBuffer *v) {
|
||||
*(sndBuffer **)v = freelist;
|
||||
freelist = (sndBuffer*)v;
|
||||
inUse += sizeof(sndBuffer);
|
||||
}
|
||||
|
||||
sndBuffer* SND_malloc( void ) {
|
||||
sndBuffer* SND_malloc() {
|
||||
sndBuffer *v;
|
||||
redo:
|
||||
if( freelist == NULL ) {
|
||||
if (freelist == NULL) {
|
||||
S_FreeOldestSound();
|
||||
goto redo;
|
||||
}
|
||||
|
||||
inUse -= sizeof( sndBuffer );
|
||||
totalInUse += sizeof( sndBuffer );
|
||||
inUse -= sizeof(sndBuffer);
|
||||
totalInUse += sizeof(sndBuffer);
|
||||
|
||||
v = freelist;
|
||||
freelist = *( sndBuffer ** )freelist;
|
||||
freelist = *(sndBuffer **)freelist;
|
||||
v->next = NULL;
|
||||
return v;
|
||||
}
|
||||
|
||||
void SND_setup( void ) {
|
||||
void SND_setup() {
|
||||
sndBuffer *p, *q;
|
||||
cvar_t *cv;
|
||||
int scs;
|
||||
|
||||
cv = Cvar_Get( "com_soundMegs", DEF_COMSOUNDMEGS, CVAR_LATCH | CVAR_ARCHIVE );
|
||||
|
||||
scs = ( cv->integer * 1536 );
|
||||
scs = (cv->integer*1536);
|
||||
|
||||
buffer = malloc( scs*sizeof( sndBuffer ) );
|
||||
buffer = malloc(scs*sizeof(sndBuffer) );
|
||||
// allocate the stack based hunk allocator
|
||||
sfxScratchBuffer = malloc( SND_CHUNK_SIZE * sizeof( short ) * 4 ); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
|
||||
sfxScratchBuffer = malloc(SND_CHUNK_SIZE * sizeof(short) * 4); //Hunk_Alloc(SND_CHUNK_SIZE * sizeof(short) * 4);
|
||||
sfxScratchPointer = NULL;
|
||||
|
||||
inUse = scs*sizeof( sndBuffer );
|
||||
inUse = scs*sizeof(sndBuffer);
|
||||
p = buffer;;
|
||||
q = p + scs;
|
||||
while( --q > p )
|
||||
*( sndBuffer ** )q = q - 1;
|
||||
|
||||
*( sndBuffer ** )q = NULL;
|
||||
while (--q > p)
|
||||
*(sndBuffer **)q = q-1;
|
||||
|
||||
*(sndBuffer **)q = NULL;
|
||||
freelist = p + scs - 1;
|
||||
|
||||
Com_Printf( "Sound memory manager started\n" );
|
||||
Com_Printf("Sound memory manager started\n");
|
||||
}
|
||||
|
||||
void SND_shutdown( void )
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
WAV loading
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
static byte *data_p;
|
||||
static byte *iff_end;
|
||||
static byte *last_chunk;
|
||||
static byte *iff_data;
|
||||
static int iff_chunk_len;
|
||||
|
||||
static short GetLittleShort(void)
|
||||
{
|
||||
free( sfxScratchBuffer );
|
||||
free( buffer );
|
||||
short val = 0;
|
||||
val = *data_p;
|
||||
val = val + (*(data_p+1)<<8);
|
||||
data_p += 2;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int GetLittleLong(void)
|
||||
{
|
||||
int val = 0;
|
||||
val = *data_p;
|
||||
val = val + (*(data_p+1)<<8);
|
||||
val = val + (*(data_p+2)<<16);
|
||||
val = val + (*(data_p+3)<<24);
|
||||
data_p += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
static void FindNextChunk(char *name)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
data_p=last_chunk;
|
||||
|
||||
if (data_p >= iff_end)
|
||||
{ // didn't find the chunk
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
iff_chunk_len = GetLittleLong();
|
||||
if (iff_chunk_len < 0)
|
||||
{
|
||||
data_p = NULL;
|
||||
return;
|
||||
}
|
||||
data_p -= 8;
|
||||
last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
|
||||
if (!strncmp((char *)data_p, name, 4))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void FindChunk(char *name)
|
||||
{
|
||||
last_chunk = iff_data;
|
||||
FindNextChunk (name);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
GetWavinfo
|
||||
============
|
||||
*/
|
||||
static wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
|
||||
{
|
||||
wavinfo_t info;
|
||||
|
||||
Com_Memset (&info, 0, sizeof(info));
|
||||
|
||||
if (!wav)
|
||||
return info;
|
||||
|
||||
iff_data = wav;
|
||||
iff_end = wav + wavlength;
|
||||
|
||||
// find "RIFF" chunk
|
||||
FindChunk("RIFF");
|
||||
if (!(data_p && !strncmp((char *)data_p+8, "WAVE", 4)))
|
||||
{
|
||||
Com_Printf("Missing RIFF/WAVE chunks\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
// get "fmt " chunk
|
||||
iff_data = data_p + 12;
|
||||
// DumpChunks ();
|
||||
|
||||
FindChunk("fmt ");
|
||||
if (!data_p)
|
||||
{
|
||||
Com_Printf("Missing fmt chunk\n");
|
||||
return info;
|
||||
}
|
||||
data_p += 8;
|
||||
info.format = GetLittleShort();
|
||||
info.channels = GetLittleShort();
|
||||
info.rate = GetLittleLong();
|
||||
data_p += 4+2;
|
||||
info.width = GetLittleShort() / 8;
|
||||
|
||||
if (info.format != 1)
|
||||
{
|
||||
Com_Printf("Microsoft PCM format only\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
// find data chunk
|
||||
FindChunk("data");
|
||||
if (!data_p)
|
||||
{
|
||||
Com_Printf("Missing data chunk\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
data_p += 4;
|
||||
info.samples = GetLittleLong () / info.width;
|
||||
info.dataofs = data_p - wav;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
ResampleSfx
|
||||
@@ -113,53 +237,47 @@ ResampleSfx
|
||||
resample / decimate to the current source rate
|
||||
================
|
||||
*/
|
||||
static int ResampleSfx( sfx_t *sfx, int channels, int inrate, int inwidth, int samples, byte *data, qboolean compressed ) {
|
||||
static void ResampleSfx( sfx_t *sfx, int inrate, int inwidth, byte *data, qboolean compressed ) {
|
||||
int outcount;
|
||||
int srcsample;
|
||||
float stepscale;
|
||||
int i, j;
|
||||
int i;
|
||||
int sample, samplefrac, fracstep;
|
||||
int part;
|
||||
sndBuffer *chunk;
|
||||
|
||||
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
|
||||
|
||||
stepscale = ( float )inrate / dma.speed; // this is usually 0.5, 1, or 2
|
||||
|
||||
outcount = samples / stepscale;
|
||||
outcount = sfx->soundLength / stepscale;
|
||||
sfx->soundLength = outcount;
|
||||
|
||||
samplefrac = 0;
|
||||
fracstep = stepscale * 256 * channels;
|
||||
fracstep = stepscale * 256;
|
||||
chunk = sfx->soundData;
|
||||
|
||||
for( i = 0; i<outcount; i++ )
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
for( j = 0; j<channels; j++ )
|
||||
{
|
||||
if( inwidth == 2 ) {
|
||||
sample = ( ( ( short * )data )[ srcsample + j ] );
|
||||
if( inwidth == 2 ) {
|
||||
sample = LittleShort ( ((short *)data)[srcsample] );
|
||||
} else {
|
||||
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
|
||||
}
|
||||
part = (i&(SND_CHUNK_SIZE-1));
|
||||
if (part == 0) {
|
||||
sndBuffer *newchunk;
|
||||
newchunk = SND_malloc();
|
||||
if (chunk == NULL) {
|
||||
sfx->soundData = newchunk;
|
||||
} else {
|
||||
chunk->next = newchunk;
|
||||
}
|
||||
else {
|
||||
sample = ( int )( ( unsigned char )( data[ srcsample + j ] ) - 128 ) << 8;
|
||||
}
|
||||
part = ( i*channels + j )&( SND_CHUNK_SIZE - 1 );
|
||||
if( part == 0 ) {
|
||||
sndBuffer *newchunk;
|
||||
newchunk = SND_malloc();
|
||||
if( chunk == NULL ) {
|
||||
sfx->soundData = newchunk;
|
||||
}
|
||||
else {
|
||||
chunk->next = newchunk;
|
||||
}
|
||||
chunk = newchunk;
|
||||
}
|
||||
|
||||
chunk->sndChunk[ part ] = sample;
|
||||
chunk = newchunk;
|
||||
}
|
||||
}
|
||||
|
||||
return outcount;
|
||||
chunk->sndChunk[part] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -169,38 +287,35 @@ ResampleSfx
|
||||
resample / decimate to the current source rate
|
||||
================
|
||||
*/
|
||||
static int ResampleSfxRaw( short *sfx, int channels, int inrate, int inwidth, int samples, byte *data ) {
|
||||
static int ResampleSfxRaw( short *sfx, int inrate, int inwidth, int samples, byte *data ) {
|
||||
int outcount;
|
||||
int srcsample;
|
||||
float stepscale;
|
||||
int i, j;
|
||||
int i;
|
||||
int sample, samplefrac, fracstep;
|
||||
|
||||
stepscale = ( float )inrate / dma.speed; // this is usually 0.5, 1, or 2
|
||||
|
||||
stepscale = (float)inrate / dma.speed; // this is usually 0.5, 1, or 2
|
||||
|
||||
outcount = samples / stepscale;
|
||||
|
||||
samplefrac = 0;
|
||||
fracstep = stepscale * 256 * channels;
|
||||
fracstep = stepscale * 256;
|
||||
|
||||
for( i = 0; i<outcount; i++ )
|
||||
for (i=0 ; i<outcount ; i++)
|
||||
{
|
||||
srcsample = samplefrac >> 8;
|
||||
samplefrac += fracstep;
|
||||
for( j = 0; j<channels; j++ )
|
||||
{
|
||||
if( inwidth == 2 ) {
|
||||
sample = LittleShort( ( ( short * )data )[ srcsample + j ] );
|
||||
}
|
||||
else {
|
||||
sample = ( int )( ( unsigned char )( data[ srcsample + j ] ) - 128 ) << 8;
|
||||
}
|
||||
sfx[ i*channels + j ] = sample;
|
||||
if( inwidth == 2 ) {
|
||||
sample = LittleShort ( ((short *)data)[srcsample] );
|
||||
} else {
|
||||
sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
|
||||
}
|
||||
sfx[i] = sample;
|
||||
}
|
||||
return outcount;
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
@@ -215,25 +330,42 @@ qboolean S_LoadSound( sfx_t *sfx )
|
||||
{
|
||||
byte *data;
|
||||
short *samples;
|
||||
snd_info_t info;
|
||||
// int size;
|
||||
wavinfo_t info;
|
||||
int size;
|
||||
|
||||
// player specific sounds are never directly loaded
|
||||
if ( sfx->soundName[0] == '*') {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
// load it in
|
||||
data = S_CodecLoad( sfx->soundName, &info );
|
||||
if( !data )
|
||||
size = FS_ReadFile( sfx->soundName, (void **)&data );
|
||||
if ( !data ) {
|
||||
return qfalse;
|
||||
|
||||
if( info.width == 1 ) {
|
||||
Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is a 8 bit audio file\n", sfx->soundName );
|
||||
}
|
||||
|
||||
if( info.rate != 22050 ) {
|
||||
Com_DPrintf( S_COLOR_YELLOW "WARNING: %s is not a 22kHz audio file\n", sfx->soundName );
|
||||
info = GetWavinfo( sfx->soundName, data, size );
|
||||
if ( info.channels != 1 ) {
|
||||
Com_Printf ("%s is a stereo wav file\n", sfx->soundName);
|
||||
FS_FreeFile (data);
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
samples = Hunk_AllocateTempMemory( info.channels * info.samples * sizeof( short ) * 2 );
|
||||
if ( info.width == 1 ) {
|
||||
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is a 8 bit wav file\n", sfx->soundName);
|
||||
}
|
||||
|
||||
sfx->lastTimeUsed = Com_Milliseconds() + 1;
|
||||
if ( info.rate != 22050 ) {
|
||||
Com_DPrintf(S_COLOR_YELLOW "WARNING: %s is not a 22kHz wav file\n", sfx->soundName);
|
||||
}
|
||||
|
||||
if (!info.samples) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
samples = Hunk_AllocateTempMemory(info.samples * sizeof(short) * 2);
|
||||
|
||||
sfx->lastTimeUsed = Com_Milliseconds()+1;
|
||||
|
||||
// each of these compression schemes works just fine
|
||||
// but the 16bit quality is much nicer and with a local
|
||||
@@ -241,40 +373,36 @@ qboolean S_LoadSound( sfx_t *sfx )
|
||||
// manager to do the right thing for us and page
|
||||
// sound in as needed
|
||||
|
||||
if( info.channels == 1 && sfx->soundCompressed == qtrue ) {
|
||||
if( sfx->soundCompressed == qtrue) {
|
||||
sfx->soundCompressionMethod = 1;
|
||||
sfx->soundData = NULL;
|
||||
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, data + info.dataofs );
|
||||
S_AdpcmEncodeSound( sfx, samples );
|
||||
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
|
||||
S_AdpcmEncodeSound(sfx, samples);
|
||||
#if 0
|
||||
}
|
||||
else if( info.channels == 1 && info.samples>( SND_CHUNK_SIZE * 16 ) && info.width >1 ) {
|
||||
} else if (info.samples>(SND_CHUNK_SIZE*16) && info.width >1) {
|
||||
sfx->soundCompressionMethod = 3;
|
||||
sfx->soundData = NULL;
|
||||
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, ( data + info.dataofs ) );
|
||||
encodeMuLaw( sfx, samples );
|
||||
}
|
||||
else if( info.channels == 1 && info.samples>( SND_CHUNK_SIZE * 6400 ) && info.width >1 ) {
|
||||
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
|
||||
encodeMuLaw( sfx, samples);
|
||||
} else if (info.samples>(SND_CHUNK_SIZE*6400) && info.width >1) {
|
||||
sfx->soundCompressionMethod = 2;
|
||||
sfx->soundData = NULL;
|
||||
sfx->soundLength = ResampleSfxRaw( samples, info.channels, info.rate, info.width, info.samples, ( data + info.dataofs ) );
|
||||
encodeWavelet( sfx, samples );
|
||||
sfx->soundLength = ResampleSfxRaw( samples, info.rate, info.width, info.samples, (data + info.dataofs) );
|
||||
encodeWavelet( sfx, samples);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sfx->soundCompressionMethod = 0;
|
||||
sfx->soundLength = info.samples;
|
||||
sfx->soundData = NULL;
|
||||
sfx->soundLength = ResampleSfx( sfx, info.channels, info.rate, info.width, info.samples, data + info.dataofs, qfalse );
|
||||
ResampleSfx( sfx, info.rate, info.width, data + info.dataofs, qfalse );
|
||||
}
|
||||
|
||||
sfx->soundChannels = info.channels;
|
||||
|
||||
Hunk_FreeTempMemory( samples );
|
||||
Hunk_FreeTempMemory( data );
|
||||
|
||||
Hunk_FreeTempMemory(samples);
|
||||
FS_FreeFile( data );
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
void S_DisplayFreeMemory( void ) {
|
||||
Com_Printf( "%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse );
|
||||
void S_DisplayFreeMemory() {
|
||||
Com_Printf("%d bytes free sound buffer memory, %d total used\n", inUse, totalInUse);
|
||||
}
|
||||
+292
-410
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+44
-52
@@ -24,70 +24,53 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct soundsystemsavegame_s soundsystemsavegame_t;
|
||||
typedef struct channelbasesavegame_s channelbasesavegame_t;
|
||||
typedef struct channel_s channel_t;
|
||||
|
||||
void S_Init( void );
|
||||
void S_SaveData( soundsystemsavegame_t *pSave );
|
||||
void S_LoadData( soundsystemsavegame_t *pSave );
|
||||
void S_InitBase( channelbasesavegame_t *pBase );
|
||||
void S_StoreBase( channelbasesavegame_t *pBase, channel_t *channel );
|
||||
void S_Shutdown( void );
|
||||
|
||||
void S_FadeSound( float fTime );
|
||||
|
||||
// if origin is NULL, the sound will be dynamically sourced from the entity
|
||||
void S_StartSound( const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, qboolean streamed );
|
||||
void S_StartLocalSound( const char *sound_name, qboolean force_load );
|
||||
void S_StartSound(const vec3_t origin, int entNum, int entChannel, sfxHandle_t sfxHandle, float volume, float minDist, float pitch, float maxDist, int streamed);
|
||||
void S_StopSound(int entnum, int channel);
|
||||
void S_StartLocalSound(sfxHandle_t sfx, int channelNum);
|
||||
void S_StartLocalSoundByName(const char* sound_name, qboolean force_load);
|
||||
|
||||
void S_StartBackgroundTrack( const char *intro, const char *loop );
|
||||
void S_StopBackgroundTrack( void );
|
||||
|
||||
// cinematics and voice-over-network will send raw samples
|
||||
// 1.0 volume will be direct output of source samples
|
||||
void S_RawSamples( int stream, int samples, int rate, int width, int channels,
|
||||
const byte *data, float volume, int entityNum );
|
||||
|
||||
void S_StopSound( int entNum, int channel );
|
||||
void S_RawSamples (int samples, int rate, int width, int channels,
|
||||
const byte *data, float volume);
|
||||
|
||||
// stop all sounds and the background track
|
||||
void S_StopAllSounds( qboolean stop_music );
|
||||
void S_StopAllSounds(qboolean stop_music);
|
||||
|
||||
// all continuous looping sounds must be added before calling S_Update
|
||||
void S_ClearLoopingSounds( void );
|
||||
void S_AddLoopingSound( const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, float volume, float minDist, float maxDist, float pitch, int flags );
|
||||
void S_ClearLoopingSoundsNoParam(void);
|
||||
void S_ClearLoopingSounds( qboolean killall );
|
||||
void S_AddLoopingSound(const vec3_t origin, const vec3_t velocity, sfxHandle_t sfxHandle, float volume, float minDist, float maxDist, float pitch, int flags);
|
||||
void S_AddRealLoopingSound( int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx );
|
||||
void S_StopLoopingSound( int entityNum );
|
||||
void S_StopLoopingSound(int entityNum );
|
||||
|
||||
// recompute the reletive volumes for all running sounds
|
||||
// reletive to the given entityNum / orientation
|
||||
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[ 3 ] );
|
||||
void S_RespatializeEx( int entityNum, const vec3_t origin, vec3_t axis[ 3 ], int inwater );
|
||||
|
||||
float S_GetSoundTime( sfxHandle_t handle );
|
||||
void S_SetGlobalAmbientVolumeLevel( float volume );
|
||||
void S_SetReverb( int reverb_type, float reverb_level );
|
||||
|
||||
int S_IsSoundPlaying( int channelNumber, const char *name );
|
||||
void S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3], int inwater );
|
||||
|
||||
// let the sound system know where an entity currently is
|
||||
void S_UpdateEntity( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener );
|
||||
void S_UpdateEntityPosition( int entityNum, const vec3_t origin );
|
||||
|
||||
void S_Update( void );
|
||||
|
||||
void S_DisableSounds( void );
|
||||
|
||||
void S_BeginRegistration( void );
|
||||
void S_EndRegistration( void );
|
||||
qboolean S_IsSoundRegistered( const char *name );
|
||||
|
||||
void S_EndRegistration(void);
|
||||
qboolean S_IsSoundRegistered(const char* name);
|
||||
// RegisterSound will allways return a valid sample, even if it
|
||||
// has to create a placeholder. This prevents continuous filesystem
|
||||
// checks for missing files
|
||||
sfxHandle_t S_RegisterSound( const char *sample, qboolean compressed, qboolean force_load );
|
||||
sfxHandle_t S_RegisterSound(const char *sample, qboolean compressed, qboolean streamed);
|
||||
|
||||
void S_DisplayFreeMemory( void );
|
||||
void S_DisplayFreeMemory(void);
|
||||
|
||||
void S_ClearSoundBuffer( void );
|
||||
|
||||
@@ -99,24 +82,33 @@ void S_UpdateBackgroundTrack( void );
|
||||
|
||||
void MUSIC_Pause();
|
||||
void MUSIC_Unpause();
|
||||
qboolean MUSIC_LoadSoundtrackFile( const char *filename );
|
||||
qboolean MUSIC_SongValid( const char *mood );
|
||||
qboolean MUSIC_Loaded( void );
|
||||
void Music_Update( void );
|
||||
void MUSIC_SongEnded( void );
|
||||
void MUSIC_NewSoundtrack( const char *name );
|
||||
void MUSIC_UpdateMood( int current, int fallback );
|
||||
void MUSIC_UpdateVolume( float volume, float fade_time );
|
||||
void MUSIC_StopAllSongs( void );
|
||||
void MUSIC_FreeAllSongs( void );
|
||||
qboolean MUSIC_Playing( void );
|
||||
int MUSIC_FindSong( const char *name );
|
||||
int MUSIC_CurrentSongChannel( void );
|
||||
void MUSIC_StopChannel( int channel_number );
|
||||
qboolean MUSIC_PlaySong( const char *alias );
|
||||
void MUSIC_UpdateMusicVolumes( void );
|
||||
void MUSIC_CheckForStoppedSongs( void );
|
||||
qboolean MUSIC_LoadSoundtrackFile(const char* filename);
|
||||
qboolean MUSIC_SongValid(const char* mood);
|
||||
qboolean MUSIC_Loaded(void);
|
||||
void Music_Update(void);
|
||||
void MUSIC_SongEnded(void);
|
||||
void MUSIC_NewSoundtrack(const char* name);
|
||||
void MUSIC_UpdateMood(int current, int fallback);
|
||||
void MUSIC_UpdateVolume(float volume, float fade_time);
|
||||
void MUSIC_StopAllSongs(void);
|
||||
void MUSIC_FreeAllSongs(void);
|
||||
qboolean MUSIC_Playing(void);
|
||||
int MUSIC_FindSong(const char* name);
|
||||
int MUSIC_CurrentSongChannel(void);
|
||||
void MUSIC_StopChannel(int channel_number);
|
||||
qboolean MUSIC_PlaySong(const char* alias);
|
||||
void MUSIC_UpdateMusicVolumes(void);
|
||||
void MUSIC_CheckForStoppedSongs(void);
|
||||
|
||||
float S_GetSoundTime(sfxHandle_t handle);
|
||||
void S_SetGlobalAmbientVolumeLevel(float volume);
|
||||
void S_SetReverb(int reverb_type, float reverb_level);
|
||||
int S_IsSoundPlaying(int channelNumber, const char* name);
|
||||
|
||||
void S_RespatializeOld(int entityNum, const vec3_t origin, vec3_t axis[3]);
|
||||
void S_UpdateEntity(int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener);
|
||||
void S_FadeSound(float fTime);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+105
-108
@@ -15,155 +15,154 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake III Arena source code; if not, write to the Free Software
|
||||
along with Foobar; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "snd_local.h"
|
||||
|
||||
long myftol( float f );
|
||||
|
||||
#define C0 0.4829629131445341
|
||||
#define C1 0.8365163037378079
|
||||
#define C2 0.2241438680420134
|
||||
#define C3 -0.1294095225512604
|
||||
|
||||
void daub4( float b[], unsigned long n, int isign )
|
||||
void daub4(float b[], unsigned long n, int isign)
|
||||
{
|
||||
float wksp[ 4097 ] = { 0.0f };
|
||||
float *a = b - 1; // numerical recipies so a[1] = b[0]
|
||||
float wksp[4097];
|
||||
float *a=b-1; // numerical recipies so a[1] = b[0]
|
||||
|
||||
unsigned long nh, nh1, i, j;
|
||||
unsigned long nh,nh1,i,j;
|
||||
|
||||
if( n < 4 ) return;
|
||||
if (n < 4) return;
|
||||
|
||||
nh1 = ( nh = n >> 1 ) + 1;
|
||||
if( isign >= 0 ) {
|
||||
for( i = 1, j = 1; j <= n - 3; j += 2, i++ ) {
|
||||
wksp[ i ] = C0*a[ j ] + C1*a[ j + 1 ] + C2*a[ j + 2 ] + C3*a[ j + 3 ];
|
||||
wksp[ i + nh ] = C3*a[ j ] - C2*a[ j + 1 ] + C1*a[ j + 2 ] - C0*a[ j + 3 ];
|
||||
nh1=(nh=n >> 1)+1;
|
||||
if (isign >= 0) {
|
||||
for (i=1,j=1;j<=n-3;j+=2,i++) {
|
||||
wksp[i] = C0*a[j]+C1*a[j+1]+C2*a[j+2]+C3*a[j+3];
|
||||
wksp[i+nh] = C3*a[j]-C2*a[j+1]+C1*a[j+2]-C0*a[j+3];
|
||||
}
|
||||
wksp[ i ] = C0*a[ n - 1 ] + C1*a[ n ] + C2*a[ 1 ] + C3*a[ 2 ];
|
||||
wksp[ i + nh ] = C3*a[ n - 1 ] - C2*a[ n ] + C1*a[ 1 ] - C0*a[ 2 ];
|
||||
}
|
||||
else {
|
||||
wksp[ 1 ] = C2*a[ nh ] + C1*a[ n ] + C0*a[ 1 ] + C3*a[ nh1 ];
|
||||
wksp[ 2 ] = C3*a[ nh ] - C0*a[ n ] + C1*a[ 1 ] - C2*a[ nh1 ];
|
||||
for( i = 1, j = 3; i<nh; i++ ) {
|
||||
wksp[ j++ ] = C2*a[ i ] + C1*a[ i + nh ] + C0*a[ i + 1 ] + C3*a[ i + nh1 ];
|
||||
wksp[ j++ ] = C3*a[ i ] - C0*a[ i + nh ] + C1*a[ i + 1 ] - C2*a[ i + nh1 ];
|
||||
wksp[i ] = C0*a[n-1]+C1*a[n]+C2*a[1]+C3*a[2];
|
||||
wksp[i+nh] = C3*a[n-1]-C2*a[n]+C1*a[1]-C0*a[2];
|
||||
} else {
|
||||
wksp[1] = C2*a[nh]+C1*a[n]+C0*a[1]+C3*a[nh1];
|
||||
wksp[2] = C3*a[nh]-C0*a[n]+C1*a[1]-C2*a[nh1];
|
||||
for (i=1,j=3;i<nh;i++) {
|
||||
wksp[j++] = C2*a[i]+C1*a[i+nh]+C0*a[i+1]+C3*a[i+nh1];
|
||||
wksp[j++] = C3*a[i]-C0*a[i+nh]+C1*a[i+1]-C2*a[i+nh1];
|
||||
}
|
||||
}
|
||||
for( i = 1; i <= n; i++ ) {
|
||||
a[ i ] = wksp[ i ];
|
||||
for (i=1;i<=n;i++) {
|
||||
a[i]=wksp[i];
|
||||
}
|
||||
}
|
||||
|
||||
void wt1( float a[], unsigned long n, int isign )
|
||||
void wt1(float a[], unsigned long n, int isign)
|
||||
{
|
||||
unsigned long nn;
|
||||
int inverseStartLength = n / 4;
|
||||
if( n < inverseStartLength ) return;
|
||||
if( isign >= 0 ) {
|
||||
for( nn = n; nn >= inverseStartLength; nn >>= 1 ) daub4( a, nn, isign );
|
||||
}
|
||||
else {
|
||||
for( nn = inverseStartLength; nn <= n; nn <<= 1 ) daub4( a, nn, isign );
|
||||
int inverseStartLength = n/4;
|
||||
if (n < inverseStartLength) return;
|
||||
if (isign >= 0) {
|
||||
for (nn=n;nn>=inverseStartLength;nn>>=1) daub4(a,nn,isign);
|
||||
} else {
|
||||
for (nn=inverseStartLength;nn<=n;nn<<=1) daub4(a,nn,isign);
|
||||
}
|
||||
}
|
||||
|
||||
/* The number of bits required by each value */
|
||||
static unsigned char numBits[] = {
|
||||
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
|
||||
};
|
||||
|
||||
byte MuLawEncode( short s ) {
|
||||
byte MuLawEncode(short s) {
|
||||
unsigned long adjusted;
|
||||
byte sign, exponent, mantissa;
|
||||
|
||||
sign = ( s<0 ) ? 0 : 0x80;
|
||||
sign = (s<0)?0:0x80;
|
||||
|
||||
if( s<0 ) s = -s;
|
||||
adjusted = ( long )s << ( 16 - sizeof( short ) * 8 );
|
||||
if (s<0) s=-s;
|
||||
adjusted = (long)s << (16-sizeof(short)*8);
|
||||
adjusted += 128L + 4L;
|
||||
if( adjusted > 32767 ) adjusted = 32767;
|
||||
exponent = numBits[ ( adjusted >> 7 ) & 0xff ] - 1;
|
||||
mantissa = ( adjusted >> ( exponent + 3 ) ) & 0xf;
|
||||
return ~( sign | ( exponent << 4 ) | mantissa );
|
||||
if (adjusted > 32767) adjusted = 32767;
|
||||
exponent = numBits[(adjusted>>7)&0xff] - 1;
|
||||
mantissa = (adjusted>>(exponent+3))&0xf;
|
||||
return ~(sign | (exponent<<4) | mantissa);
|
||||
}
|
||||
|
||||
short MuLawDecode( byte uLaw ) {
|
||||
short MuLawDecode(byte uLaw) {
|
||||
signed long adjusted;
|
||||
byte exponent, mantissa;
|
||||
|
||||
uLaw = ~uLaw;
|
||||
exponent = ( uLaw >> 4 ) & 0x7;
|
||||
mantissa = ( uLaw & 0xf ) + 16;
|
||||
adjusted = ( mantissa << ( exponent + 3 ) ) - 128 - 4;
|
||||
exponent = (uLaw>>4) & 0x7;
|
||||
mantissa = (uLaw&0xf) + 16;
|
||||
adjusted = (mantissa << (exponent +3)) - 128 - 4;
|
||||
|
||||
return ( uLaw & 0x80 ) ? adjusted : -adjusted;
|
||||
return (uLaw & 0x80)? adjusted : -adjusted;
|
||||
}
|
||||
|
||||
short mulawToShort[ 256 ];
|
||||
short mulawToShort[256];
|
||||
static qboolean madeTable = qfalse;
|
||||
|
||||
static int NXStreamCount;
|
||||
|
||||
void NXPutc( NXStream *stream, char out ) {
|
||||
stream[ NXStreamCount++ ] = out;
|
||||
void NXPutc(NXStream *stream, char out) {
|
||||
stream[NXStreamCount++] = out;
|
||||
}
|
||||
|
||||
|
||||
void encodeWavelet( sfx_t *sfx, short *packets ) {
|
||||
float wksp[ 4097 ] = { 0 }, temp;
|
||||
void encodeWavelet( sfx_t *sfx, short *packets) {
|
||||
float wksp[4097], temp;
|
||||
int i, samples, size;
|
||||
sndBuffer *newchunk, *chunk;
|
||||
byte *out;
|
||||
|
||||
if( !madeTable ) {
|
||||
for( i = 0; i<256; i++ ) {
|
||||
mulawToShort[ i ] = ( float )MuLawDecode( ( byte )i );
|
||||
if (!madeTable) {
|
||||
for (i=0;i<256;i++) {
|
||||
mulawToShort[i] = (float)MuLawDecode((byte)i);
|
||||
}
|
||||
madeTable = qtrue;
|
||||
}
|
||||
chunk = NULL;
|
||||
|
||||
samples = sfx->soundLength;
|
||||
while( samples>0 ) {
|
||||
while(samples>0) {
|
||||
size = samples;
|
||||
if( size>( SND_CHUNK_SIZE * 2 ) ) {
|
||||
size = ( SND_CHUNK_SIZE * 2 );
|
||||
if (size>(SND_CHUNK_SIZE*2)) {
|
||||
size = (SND_CHUNK_SIZE*2);
|
||||
}
|
||||
|
||||
if( size<4 ) {
|
||||
if (size<4) {
|
||||
size = 4;
|
||||
}
|
||||
|
||||
newchunk = SND_malloc();
|
||||
if( sfx->soundData == NULL ) {
|
||||
if (sfx->soundData == NULL) {
|
||||
sfx->soundData = newchunk;
|
||||
}
|
||||
else if( chunk != NULL ) {
|
||||
} else {
|
||||
chunk->next = newchunk;
|
||||
}
|
||||
chunk = newchunk;
|
||||
for( i = 0; i<size; i++ ) {
|
||||
wksp[ i ] = *packets;
|
||||
for(i=0; i<size; i++) {
|
||||
wksp[i] = *packets;
|
||||
packets++;
|
||||
}
|
||||
wt1( wksp, size, 1 );
|
||||
out = ( byte * )chunk->sndChunk;
|
||||
wt1(wksp, size, 1);
|
||||
out = (byte *)chunk->sndChunk;
|
||||
|
||||
for( i = 0; i<size; i++ ) {
|
||||
temp = wksp[ i ];
|
||||
if( temp > 32767 ) temp = 32767; else if( temp<-32768 ) temp = -32768;
|
||||
out[ i ] = MuLawEncode( ( short )temp );
|
||||
for(i=0;i<size;i++) {
|
||||
temp = wksp[i];
|
||||
if (temp > 32767) temp = 32767; else if (temp<-32768) temp = -32768;
|
||||
out[i] = MuLawEncode((short)temp);
|
||||
}
|
||||
|
||||
chunk->size = size;
|
||||
@@ -171,36 +170,36 @@ void encodeWavelet( sfx_t *sfx, short *packets ) {
|
||||
}
|
||||
}
|
||||
|
||||
void decodeWavelet( sndBuffer *chunk, short *to ) {
|
||||
float wksp[ 4097 ] = { 0 };
|
||||
void decodeWavelet(sndBuffer *chunk, short *to) {
|
||||
float wksp[4097];
|
||||
int i;
|
||||
byte *out;
|
||||
|
||||
int size = chunk->size;
|
||||
|
||||
out = ( byte * )chunk->sndChunk;
|
||||
for( i = 0; i<size; i++ ) {
|
||||
wksp[ i ] = mulawToShort[ out[ i ] ];
|
||||
|
||||
out = (byte *)chunk->sndChunk;
|
||||
for(i=0;i<size;i++) {
|
||||
wksp[i] = mulawToShort[out[i]];
|
||||
}
|
||||
|
||||
wt1( wksp, size, -1 );
|
||||
wt1(wksp, size, -1);
|
||||
|
||||
if (!to) return;
|
||||
|
||||
if( !to ) return;
|
||||
|
||||
for( i = 0; i<size; i++ ) {
|
||||
to[ i ] = wksp[ i ];
|
||||
for(i=0; i<size; i++) {
|
||||
to[i] = wksp[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void encodeMuLaw( sfx_t *sfx, short *packets ) {
|
||||
void encodeMuLaw( sfx_t *sfx, short *packets) {
|
||||
int i, samples, size, grade, poop;
|
||||
sndBuffer *newchunk, *chunk;
|
||||
byte *out;
|
||||
|
||||
if( !madeTable ) {
|
||||
for( i = 0; i<256; i++ ) {
|
||||
mulawToShort[ i ] = ( float )MuLawDecode( ( byte )i );
|
||||
if (!madeTable) {
|
||||
for (i=0;i<256;i++) {
|
||||
mulawToShort[i] = (float)MuLawDecode((byte)i);
|
||||
}
|
||||
madeTable = qtrue;
|
||||
}
|
||||
@@ -209,31 +208,29 @@ void encodeMuLaw( sfx_t *sfx, short *packets ) {
|
||||
samples = sfx->soundLength;
|
||||
grade = 0;
|
||||
|
||||
while( samples>0 ) {
|
||||
while(samples>0) {
|
||||
size = samples;
|
||||
if( size>( SND_CHUNK_SIZE * 2 ) ) {
|
||||
size = ( SND_CHUNK_SIZE * 2 );
|
||||
if (size>(SND_CHUNK_SIZE*2)) {
|
||||
size = (SND_CHUNK_SIZE*2);
|
||||
}
|
||||
|
||||
newchunk = SND_malloc();
|
||||
if( sfx->soundData == NULL ) {
|
||||
if (sfx->soundData == NULL) {
|
||||
sfx->soundData = newchunk;
|
||||
}
|
||||
else if( chunk != NULL ) {
|
||||
} else {
|
||||
chunk->next = newchunk;
|
||||
}
|
||||
chunk = newchunk;
|
||||
out = ( byte * )chunk->sndChunk;
|
||||
for( i = 0; i<size; i++ ) {
|
||||
poop = packets[ 0 ] + grade;
|
||||
if( poop>32767 ) {
|
||||
out = (byte *)chunk->sndChunk;
|
||||
for(i=0; i<size; i++) {
|
||||
poop = packets[0]+grade;
|
||||
if (poop>32767) {
|
||||
poop = 32767;
|
||||
}
|
||||
else if( poop<-32768 ) {
|
||||
} else if (poop<-32768) {
|
||||
poop = -32768;
|
||||
}
|
||||
out[ i ] = MuLawEncode( ( short )poop );
|
||||
grade = poop - mulawToShort[ out[ i ] ];
|
||||
out[i] = MuLawEncode((short)poop);
|
||||
grade = poop - mulawToShort[out[i]];
|
||||
packets++;
|
||||
}
|
||||
chunk->size = size;
|
||||
@@ -241,15 +238,15 @@ void encodeMuLaw( sfx_t *sfx, short *packets ) {
|
||||
}
|
||||
}
|
||||
|
||||
void decodeMuLaw( sndBuffer *chunk, short *to ) {
|
||||
void decodeMuLaw(sndBuffer *chunk, short *to) {
|
||||
int i;
|
||||
byte *out;
|
||||
|
||||
int size = chunk->size;
|
||||
|
||||
out = ( byte * )chunk->sndChunk;
|
||||
for( i = 0; i<size; i++ ) {
|
||||
to[ i ] = mulawToShort[ out[ i ] ];
|
||||
|
||||
out = (byte *)chunk->sndChunk;
|
||||
for(i=0;i<size;i++) {
|
||||
to[i] = mulawToShort[out[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-3
@@ -22,6 +22,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
#include "ui_local.h"
|
||||
|
||||
UConnection::UConnection()
|
||||
{
|
||||
}
|
||||
|
||||
UConnection::UConnection(const Event& inevent, const Event& outevent)
|
||||
: m_inevent(inevent)
|
||||
, m_outevent(outevent)
|
||||
{
|
||||
}
|
||||
|
||||
bool UConnection::TypeIs
|
||||
(
|
||||
Event& ev
|
||||
@@ -47,12 +57,12 @@ bool UConnection::AddListener
|
||||
ptr = object;
|
||||
|
||||
// don't add the same listener
|
||||
if( m_listeners.ObjectInList( ptr ) )
|
||||
if (m_listeners.ObjectInList(ptr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_listeners.AddUniqueObject( ptr );
|
||||
m_listeners.AddObject( ptr );
|
||||
|
||||
e = new Event( ev );
|
||||
m_events.AddObject( e );
|
||||
@@ -183,7 +193,7 @@ bool USignal::Connect
|
||||
}
|
||||
}
|
||||
|
||||
c = new UConnection;
|
||||
c = new UConnection(inevent, outevent);
|
||||
m_connections.AddObject( c );
|
||||
|
||||
return c->AddListener( object, outevent );
|
||||
|
||||
@@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
// VehicleCollisionEntity.cpp : MOHAA Vehicle Collision
|
||||
|
||||
#include "VehicleCollisionEntity.h"
|
||||
#include "g_phys.h"
|
||||
|
||||
CLASS_DECLARATION( Entity, VehicleCollisionEntity, NULL )
|
||||
{
|
||||
|
||||
+9
-4
@@ -41,6 +41,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#include "bg_local.h"
|
||||
#include "weapturret.h"
|
||||
#include "sentient.h"
|
||||
#include "g_phys.h"
|
||||
#include "debuglines.h"
|
||||
#include "scriptexception.h"
|
||||
#include <parm.h>
|
||||
#include <tiki.h>
|
||||
|
||||
@@ -6632,7 +6635,7 @@ void Actor::VoiceSound
|
||||
{
|
||||
bool bFriendly;
|
||||
//FIXME: macros
|
||||
if (m_ThinkStates[THINKLEVEL_NORMAL] != THINKSTATE_IDLE && m_ThinkStates[THINKLEVEL_NORMAL] != THINKSTATE_CURIOUS || !m_bEnableEnemy)
|
||||
if ((m_ThinkStates[THINKLEVEL_NORMAL] != THINKSTATE_IDLE && m_ThinkStates[THINKLEVEL_NORMAL] != THINKSTATE_CURIOUS) || !m_bEnableEnemy)
|
||||
return;
|
||||
|
||||
bFriendly = m_Team == TEAM_GERMAN;
|
||||
@@ -9673,7 +9676,7 @@ void Actor::MovePath
|
||||
|
||||
VectorCopy2D(mm.obstacle_normal, m_PrevObstacleNormal);
|
||||
|
||||
if (m_WallDir == uint8_t(~0u))
|
||||
if (m_WallDir == char(-1))
|
||||
{
|
||||
mm.desired_dir[0] = -mm.obstacle_normal[1];
|
||||
mm.desired_dir[1] = mm.obstacle_normal[0];
|
||||
@@ -14523,7 +14526,8 @@ void Actor::ResolveVoiceType
|
||||
return;
|
||||
}
|
||||
}
|
||||
sprintf(validVoice, "");
|
||||
|
||||
validVoice[0] = '\0';
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
strcat(validVoice, gAmericanVoices[i]);
|
||||
@@ -14545,7 +14549,8 @@ void Actor::ResolveVoiceType
|
||||
return;
|
||||
}
|
||||
}
|
||||
sprintf(validVoice, "");
|
||||
|
||||
validVoice[0] = '\0';
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
strcat(validVoice, gGermanVoices[i]);
|
||||
|
||||
Loaded 100 of 566 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user