mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-07 02:18:26 +00:00
Compare commits
781 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21a7b58c82 | ||
|
|
133c4e5b12 | ||
|
|
7cbb250541 | ||
|
|
a350d7982c | ||
|
|
a5bec0403b | ||
|
|
7d3913bc3e | ||
|
|
1993c22112 | ||
|
|
71c674663f | ||
|
|
0ebfa900b9 | ||
|
|
128940ff19 | ||
|
|
00feb624c2 | ||
|
|
309cdf3acf | ||
|
|
871c67deac | ||
|
|
f924177098 | ||
|
|
b1e8e15043 | ||
|
|
f14cbf5aff | ||
|
|
d08a3078e1 | ||
|
|
16ccd0cc7c | ||
|
|
70308f3d6a | ||
|
|
378a2eae70 | ||
|
|
0b0be25c78 | ||
|
|
dce67fada9 | ||
|
|
326caccb06 | ||
|
|
4f43b628ae | ||
|
|
466bcf62df | ||
|
|
0c4a0d139d | ||
|
|
c0d5efb309 | ||
|
|
14b9674962 | ||
|
|
ee96ef9f7f | ||
|
|
69ffbc1d7f | ||
|
|
bb09568d97 | ||
|
|
877b71aa4d | ||
|
|
f0ccf6dc0a | ||
|
|
003f377319 | ||
|
|
f31c4f6ede | ||
|
|
321cdb28d9 | ||
|
|
4969429727 | ||
|
|
b29cc54d0b | ||
|
|
91ca6a7ea9 | ||
|
|
49105001d3 | ||
|
|
cd4f1c9248 | ||
|
|
0151ace718 | ||
|
|
b1a2f06432 | ||
|
|
6124d0fceb | ||
|
|
5214a2d6f7 | ||
|
|
7e1c3f0dc3 | ||
|
|
158edbe158 | ||
|
|
983a3c8e74 | ||
|
|
3d0cd96319 | ||
|
|
354c2445c2 | ||
|
|
f8833972ec | ||
|
|
2726865399 | ||
|
|
420c8e02ea | ||
|
|
d93ed28816 | ||
|
|
78f55f9a1a | ||
|
|
e072be6313 | ||
|
|
bf5ec55a6a | ||
|
|
2013968f1c | ||
|
|
90a6714beb | ||
|
|
8ecc2a7829 | ||
|
|
ad008dc00a | ||
|
|
23fa606920 | ||
|
|
f54775044c | ||
|
|
04ad339fe8 | ||
|
|
94ebb97c79 | ||
|
|
b150073754 | ||
|
|
ad48aa3345 | ||
|
|
2bbb3865f8 | ||
|
|
ab75ef4c43 | ||
|
|
e5976001cf | ||
|
|
57e3dce711 | ||
|
|
dfc9276edc | ||
|
|
3175172241 | ||
|
|
2dd385a8eb | ||
|
|
54c04a0219 | ||
|
|
17e60114a4 | ||
|
|
ef2e2bb0dc | ||
|
|
7c80025574 | ||
|
|
d4d5004615 | ||
|
|
9434dc9438 | ||
|
|
187bd2c975 | ||
|
|
e41ba9fa95 | ||
|
|
f96a57412b | ||
|
|
ee0fe65b01 | ||
|
|
1b67644197 | ||
|
|
fee7df2919 | ||
|
|
bac325cd07 | ||
|
|
c9cfbefa27 | ||
|
|
2a23c05853 | ||
|
|
da78976c56 | ||
|
|
30ae74fd9f | ||
|
|
4465e53d3b | ||
|
|
101ab536ab | ||
|
|
feeb4ae445 | ||
|
|
2751ec1f2d | ||
|
|
7aca8755a4 | ||
|
|
e35e835841 | ||
|
|
4652e36cc6 | ||
|
|
3609adf2aa | ||
|
|
44ac27a41d | ||
|
|
654f9aa239 | ||
|
|
2805cd94c6 | ||
|
|
b773e74049 | ||
|
|
6751aa323b | ||
|
|
659d70af24 | ||
|
|
1f1a897927 | ||
|
|
16a927cd91 | ||
|
|
5814a7c3d8 | ||
|
|
9876d4c3db | ||
|
|
b63e3c8f8f | ||
|
|
5421c6006a | ||
|
|
7ce6233cf4 | ||
|
|
66c730a897 | ||
|
|
1102a0971c | ||
|
|
388f561f58 | ||
|
|
c2dbf6d779 | ||
|
|
d57ec73adb | ||
|
|
64d6a1d9f3 | ||
|
|
efb659adfb | ||
|
|
835678d816 | ||
|
|
7fb0f45c2c | ||
|
|
e8ff7fe663 | ||
|
|
91a2df62af | ||
|
|
d337145b5f | ||
|
|
ce9d1e45b2 | ||
|
|
9b96f9dffd | ||
|
|
c2a9017810 | ||
|
|
c1c84e17a3 | ||
|
|
f9bb0a39f8 | ||
|
|
f6fdd7b0aa | ||
|
|
60c4f399f1 | ||
|
|
c6c38b0816 | ||
|
|
d69bd18407 | ||
|
|
cf90d110e3 | ||
|
|
d48ed993c6 | ||
|
|
309aa7a189 | ||
|
|
5a0b8c2df5 | ||
|
|
ca60971410 | ||
|
|
4bbef8aa61 | ||
|
|
31fcd7ecb5 | ||
|
|
3a1e6a60cd | ||
|
|
afdf236fe9 | ||
|
|
9423ef79ad | ||
|
|
86b36436df | ||
|
|
79c307fea8 | ||
|
|
fee8edeeda | ||
|
|
787aa8ff34 | ||
|
|
9210b84d50 | ||
|
|
3757993e50 | ||
|
|
e4c58dd952 | ||
|
|
a4c214c981 | ||
|
|
9eceb51ea6 | ||
|
|
830ebc1b73 | ||
|
|
7bd954880a | ||
|
|
888b4be951 | ||
|
|
2a254a32a1 | ||
|
|
7728c640bf | ||
|
|
afa6b07da8 | ||
|
|
b468f9d67a | ||
|
|
bb49da4d9c | ||
|
|
412812693f | ||
|
|
9400b7c7e3 | ||
|
|
6ded3770d6 | ||
|
|
e19f069a8c | ||
|
|
06bce65bcc | ||
|
|
2dbb211742 | ||
|
|
1f8461f64b | ||
|
|
f19df1ca3f | ||
|
|
cbf703bb9f | ||
|
|
e0c59404c3 | ||
|
|
62d508705f | ||
|
|
2bcd20fac7 | ||
|
|
960484585d | ||
|
|
5fec9a2fe1 | ||
|
|
12d7e5590d | ||
|
|
9cf9d7ff27 | ||
|
|
7a81b44655 | ||
|
|
f7ff341131 | ||
|
|
a7e3fe517c | ||
|
|
a6da4358de | ||
|
|
f1bea169d2 | ||
|
|
fefb0ffe6f | ||
|
|
91f05dfbf9 | ||
|
|
83293832fd | ||
|
|
0cf281f509 | ||
|
|
07727e1db0 | ||
|
|
f16b9aa7f3 | ||
|
|
d0d3c62ff5 | ||
|
|
5ac888c3a0 | ||
|
|
4fee1e4cc1 | ||
|
|
3db30bea98 | ||
|
|
783fd4f0a7 | ||
|
|
5c098bd155 | ||
|
|
0d81991083 | ||
|
|
349ba586c7 | ||
|
|
dc2c186249 | ||
|
|
f0ea0a01c1 | ||
|
|
4eb31820b1 | ||
|
|
fd687dd2d7 | ||
|
|
c631f6635b | ||
|
|
9ef34bce59 | ||
|
|
7a79fc03e8 | ||
|
|
236829cc33 | ||
|
|
09c0d228b4 | ||
|
|
5f717553d9 | ||
|
|
119e7ff4c8 | ||
|
|
b0889f77ee | ||
|
|
e196e04de6 | ||
|
|
8eefcd5b68 | ||
|
|
de9cbc8470 | ||
|
|
2b2a1fcb12 | ||
|
|
b868208520 | ||
|
|
098b7d4977 | ||
|
|
d718620aa3 | ||
|
|
a1b04e38ba | ||
|
|
23901be52d | ||
|
|
3cef031e91 | ||
|
|
e4f2d35f6c | ||
|
|
87c2b1e436 | ||
|
|
2e2db2165f | ||
|
|
894b039e4e | ||
|
|
5ccd0efd04 | ||
|
|
ea8f14fa07 | ||
|
|
7a8060a0bf | ||
|
|
2e9ba205a0 | ||
|
|
4d78090e5f | ||
|
|
b115726abb | ||
|
|
fdbbc11d2a | ||
|
|
e3aab46e01 | ||
|
|
f4cd4e9e6a | ||
|
|
a1a1c6adfa | ||
|
|
3d16f5ffa7 | ||
|
|
6a9e697ff6 | ||
|
|
bf106d9ff2 | ||
|
|
04d65d2fa5 | ||
|
|
864b46379b | ||
|
|
b78ae36a0e | ||
|
|
bdea503697 | ||
|
|
0ffdbb9b5a | ||
|
|
5fc891d6fa | ||
|
|
1ea49018e0 | ||
|
|
5ec9d0fa11 | ||
|
|
790f0a392b | ||
|
|
21c6204062 | ||
|
|
578636d528 | ||
|
|
68a57b9123 | ||
|
|
1c82605db5 | ||
|
|
cdbeb52976 | ||
|
|
e322606492 | ||
|
|
1ed7a68ab3 | ||
|
|
e76ab45a55 | ||
|
|
9c5c29c6ca | ||
|
|
f703aca4d6 | ||
|
|
cec7805047 | ||
|
|
7878784887 | ||
|
|
898c46379d | ||
|
|
bf25061444 | ||
|
|
1e7459a6c4 | ||
|
|
684ade8dd9 | ||
|
|
6ceab1283c | ||
|
|
5ba8ede632 | ||
|
|
a778908e32 | ||
|
|
4ac0b4da5d | ||
|
|
d78393f084 | ||
|
|
5c14dfcc60 | ||
|
|
27ec578c7d | ||
|
|
0f7360f374 | ||
|
|
fb42a370fe | ||
|
|
8900e4b6ff | ||
|
|
72ae96e0c8 | ||
|
|
1449b9b3d5 | ||
|
|
7e44264f13 | ||
|
|
64bd95a73b | ||
|
|
760d84e420 | ||
|
|
bdfa61e3f9 | ||
|
|
8aad5e6f00 | ||
|
|
6dc1fb66e4 | ||
|
|
7819aa1ace | ||
|
|
0360b957e4 | ||
|
|
8b4db28cfb | ||
|
|
1a86a2b643 | ||
|
|
4c21dc96f9 | ||
|
|
5056917d78 | ||
|
|
489fd3cbf1 | ||
|
|
c3f67d77f2 | ||
|
|
4486528880 | ||
|
|
178d42e2fd | ||
|
|
1a03bdac13 | ||
|
|
8237b249c5 | ||
|
|
78eeb38c12 | ||
|
|
9cbed1972b | ||
|
|
fa28502a0d | ||
|
|
2efbc4a653 | ||
|
|
3e29099ab8 | ||
|
|
d922cebf97 | ||
|
|
0f44dd1710 | ||
|
|
fa6ccdbded | ||
|
|
7c251ef81d | ||
|
|
8e0e5ec8c1 | ||
|
|
6bba2072fe | ||
|
|
4315221b86 | ||
|
|
85adfa3bb2 | ||
|
|
e3aac2d24e | ||
|
|
affac70f99 | ||
|
|
41f50505f9 | ||
|
|
bfa9aa45e4 | ||
|
|
4cf01f5ec4 | ||
|
|
22acb5b6c2 | ||
|
|
09917f91d9 | ||
|
|
8f11f9aaf1 | ||
|
|
79baadf541 | ||
|
|
6fc6ca86bc | ||
|
|
4bfa75a32c | ||
|
|
d8a9dd7d7b | ||
|
|
ed481b216c | ||
|
|
7dddfe25f3 | ||
|
|
ef3ca621c4 | ||
|
|
5b5652a34d | ||
|
|
96ef03e458 | ||
|
|
c2e50761ec | ||
|
|
e817a9ada7 | ||
|
|
53463d8fb9 | ||
|
|
22a68b491b | ||
|
|
bc62b92983 | ||
|
|
d816423eb6 | ||
|
|
a23348d843 | ||
|
|
acf47a11b1 | ||
|
|
ab73e36a15 | ||
|
|
2616712c9e | ||
|
|
487e3db9d0 | ||
|
|
1bbd4ba82e | ||
|
|
e0162afce3 | ||
|
|
7c842afdf0 | ||
|
|
9a3b80f418 | ||
|
|
c8ed191d11 | ||
|
|
a25417cc8a | ||
|
|
b2b2fe3344 | ||
|
|
b956ffb8aa | ||
|
|
e344ea2d89 | ||
|
|
158f0b8546 | ||
|
|
f1ad55fddf | ||
|
|
14e71dbbb4 | ||
|
|
c170393447 | ||
|
|
cf5bc4b7db | ||
|
|
2ac4190865 | ||
|
|
48ffd9bc71 | ||
|
|
1230bf9266 | ||
|
|
fb5c247953 | ||
|
|
9902b8adac | ||
|
|
aa1f0eb169 | ||
|
|
1802f998fc | ||
|
|
b090743bae | ||
|
|
9d771dfdba | ||
|
|
6d208a8595 | ||
|
|
c6ced66503 | ||
|
|
ad258dc047 | ||
|
|
ea3bd05124 | ||
|
|
d7785f91ce | ||
|
|
ef51513fcc | ||
|
|
76aaecdb6e | ||
|
|
ddb902e663 | ||
|
|
e0bdbfc20f | ||
|
|
d6aaa8e413 | ||
|
|
fda64ad102 | ||
|
|
8f07c1d510 | ||
|
|
3a6592cc5e | ||
|
|
554606a210 | ||
|
|
85ff178f47 | ||
|
|
361884b17d | ||
|
|
f642afe016 | ||
|
|
57326e1843 | ||
|
|
86af6ca07b | ||
|
|
ea9a962711 | ||
|
|
8f59007d1d | ||
|
|
91ec294f42 | ||
|
|
b05393cf9f | ||
|
|
bcc82992e5 | ||
|
|
0fee1862c8 | ||
|
|
d58d3ee1d5 | ||
|
|
73601ffd0a | ||
|
|
89e8f69f6a | ||
|
|
724244f3e8 | ||
|
|
70f29d3ca5 | ||
|
|
de8a82707b | ||
|
|
033179edf0 | ||
|
|
d77fa13ebe | ||
|
|
807baa13ad | ||
|
|
8c00da8a5a | ||
|
|
69445ebab5 | ||
|
|
98fcc37b7b | ||
|
|
060ce5e660 | ||
|
|
80e8480b7a | ||
|
|
4e89fb60d9 | ||
|
|
2e791a8237 | ||
|
|
840490cc54 | ||
|
|
98ee179927 | ||
|
|
525b62753b | ||
|
|
a4e2dccc12 | ||
|
|
614b16ce17 | ||
|
|
bb7cde71ec | ||
|
|
363627603b | ||
|
|
89e97dfd3d | ||
|
|
2360d71494 | ||
|
|
fc4aac0c47 | ||
|
|
9c634868cb | ||
|
|
a6ade753fe | ||
|
|
120f82eaf4 | ||
|
|
22c9e50ed7 | ||
|
|
2ef8407292 | ||
|
|
ef5ac148b3 | ||
|
|
44eb29e27c | ||
|
|
0bde3c42b6 | ||
|
|
0c459505c8 | ||
|
|
3b8ed08692 | ||
|
|
253321ced6 | ||
|
|
a0153de9f8 | ||
|
|
7aeaa1a02d | ||
|
|
987eebb3b0 | ||
|
|
9a5ff64fc5 | ||
|
|
26dfdcc927 | ||
|
|
d335ec7262 | ||
|
|
7399512f5e | ||
|
|
0000000146 | ||
|
|
0000000868 | ||
|
|
0000000fbb | ||
|
|
0000000b2b | ||
|
|
00000008fd | ||
|
|
dd0059f15f | ||
|
|
d95ddbbf8c | ||
|
|
a1d30afdbe | ||
|
|
b042a6c170 | ||
|
|
345461a838 | ||
|
|
894ecdff48 | ||
|
|
117d2d277c | ||
|
|
7a11acf2e6 | ||
|
|
b3b7de37e2 | ||
|
|
aef89e9bb4 | ||
|
|
01a62b5d6b | ||
|
|
9434e1395f | ||
|
|
37a3a63bad | ||
|
|
fda843a09f | ||
|
|
bacc5672fc | ||
|
|
c8c87347a5 | ||
|
|
d1b2ffd461 | ||
|
|
e43c011711 | ||
|
|
062efd4772 | ||
|
|
ecbc7edca2 | ||
|
|
3d40d4f809 | ||
|
|
6d296caf36 | ||
|
|
2909a38179 | ||
|
|
4167001b5c | ||
|
|
6c88f45ba0 | ||
|
|
9adc56e284 | ||
|
|
4d9f3f9a1b | ||
|
|
ac9b204ffd | ||
|
|
b4d13836ea | ||
|
|
6921f38214 | ||
|
|
cdd8c56a5e | ||
|
|
0133300a40 | ||
|
|
b4b79d2159 | ||
|
|
5d47c2dd1b | ||
|
|
150bd15b55 | ||
|
|
f474a944ae | ||
|
|
e1e404714b | ||
|
|
91241c235c | ||
|
|
573e97e9dc | ||
|
|
ec881bbae5 | ||
|
|
cf7c1d85bb | ||
|
|
0adf03b575 | ||
|
|
918cfde75d | ||
|
|
46550e7a83 | ||
|
|
7675b60567 | ||
|
|
5882e458db | ||
|
|
5b8a149343 | ||
|
|
dedbba5ec9 | ||
|
|
b11b82b286 | ||
|
|
f4d2d6d653 | ||
|
|
590d1fb290 | ||
|
|
3be3b4e3b2 | ||
|
|
3f3474f463 | ||
|
|
18a4e1e306 | ||
|
|
fbdfc7bbea | ||
|
|
0cc406c962 | ||
|
|
871f59c235 | ||
|
|
776d32b0ef | ||
|
|
85c1617658 | ||
|
|
fa58b0f7fe | ||
|
|
0286df9edd | ||
|
|
9c4f626076 | ||
|
|
3a87717250 | ||
|
|
3816aa3646 | ||
|
|
baa824e872 | ||
|
|
e8e8f71657 | ||
|
|
a115632b7b | ||
|
|
58dbd6d1c3 | ||
|
|
c089b3af9d | ||
|
|
b25afa84a3 | ||
|
|
d2763d337b | ||
|
|
ccb0caee7b | ||
|
|
4880735a71 | ||
|
|
527864b426 | ||
|
|
240caba1a2 | ||
|
|
1d841372a9 | ||
|
|
6bc371e940 | ||
|
|
3b5ed62b28 | ||
|
|
b34a4e6677 | ||
|
|
42c4550df5 | ||
|
|
c9c6a333a4 | ||
|
|
ba5ad21661 | ||
|
|
da172f07aa | ||
|
|
576c773134 | ||
|
|
8a9fe14274 | ||
|
|
1633201e16 | ||
|
|
e3ed6027ca | ||
|
|
2fa06031de | ||
|
|
1ce6acc5f4 | ||
|
|
d83b62c070 | ||
|
|
794c379bf2 | ||
|
|
578dd01e1a | ||
|
|
0c91c19ba6 | ||
|
|
168968800d | ||
|
|
0775d10d81 | ||
|
|
ae0145430a | ||
|
|
3348e54316 | ||
|
|
005f7d97f6 | ||
|
|
d37ca33ea4 | ||
|
|
b17979aad0 | ||
|
|
4ec8a620be | ||
|
|
73d21ea9d1 | ||
|
|
ee7e13579f | ||
|
|
870c62a8c9 | ||
|
|
89238b5b9b | ||
|
|
f193679a9d | ||
|
|
8e0736e3d3 | ||
|
|
bff7ace887 | ||
|
|
17d7255145 | ||
|
|
a750753a62 | ||
|
|
c00865c9ee | ||
|
|
94b3c41f41 | ||
|
|
431fd18ecb | ||
|
|
cd2a74240a | ||
|
|
900083b321 | ||
|
|
0a99f06ff4 | ||
|
|
01a2e616a6 | ||
|
|
8827864fb8 | ||
|
|
c177dfb671 | ||
|
|
43d6a31ac0 | ||
|
|
426d6af3c5 | ||
|
|
ede141d8c0 | ||
|
|
4c46975584 | ||
|
|
345d6bf28e | ||
|
|
94d8d91a82 | ||
|
|
cd91255c52 | ||
|
|
35391f36d1 | ||
|
|
62c2a26e48 | ||
|
|
53aeec31f2 | ||
|
|
aa7887ecf4 | ||
|
|
caeb35febd | ||
|
|
4aac85d3fd | ||
|
|
1509e77728 | ||
|
|
fff864ffba | ||
|
|
0da9781973 | ||
|
|
8241de2b65 | ||
|
|
f89816449a | ||
|
|
f14ae3a604 | ||
|
|
c68d50a4d0 | ||
|
|
78b276c350 | ||
|
|
243ff9cbe6 | ||
|
|
c6de66fe18 | ||
|
|
f10d9442c3 | ||
|
|
3c59adce57 | ||
|
|
223611d7a9 | ||
|
|
e208060156 | ||
|
|
396f2017c5 | ||
|
|
7ca35b908b | ||
|
|
a79016397a | ||
|
|
03c3af1a4f | ||
|
|
4b711b1fab | ||
|
|
25e6f29e7c | ||
|
|
2e627fe3e2 | ||
|
|
a146b51fb1 | ||
|
|
39c9d96924 | ||
|
|
6952bab715 | ||
|
|
1802dd8007 | ||
|
|
51427be3e9 | ||
|
|
2d98efd16c | ||
|
|
de1d1d5145 | ||
|
|
c14b133a42 | ||
|
|
a8016dff00 | ||
|
|
6573e0cbbc | ||
|
|
254eea7780 | ||
|
|
c36bac0c84 | ||
|
|
59ec8eb6e5 | ||
|
|
07de010a28 | ||
|
|
0db2b30a77 | ||
|
|
8830035af5 | ||
|
|
729f060f91 | ||
|
|
2316fac678 | ||
|
|
04eea994d8 | ||
|
|
86b23b33a2 | ||
|
|
f02ac94bbf | ||
|
|
1946de926b | ||
|
|
76988a509b | ||
|
|
29d50b69c1 | ||
|
|
2015027ed6 | ||
|
|
616de1ce97 | ||
|
|
4fef03f925 | ||
|
|
f5652c641e | ||
|
|
f3ec01870b | ||
|
|
2067dc7c38 | ||
|
|
13d6d586b3 | ||
|
|
3a978f196d | ||
|
|
c55531168d | ||
|
|
e32b79c941 | ||
|
|
b6a81e04e3 | ||
|
|
64088b6147 | ||
|
|
20dd2a9665 | ||
|
|
6d21e25679 | ||
|
|
4d1a0b5eb3 | ||
|
|
f8f336d21a | ||
|
|
79cd7f1225 | ||
|
|
3c5958eb93 | ||
|
|
183e758971 | ||
|
|
3574080e8e | ||
|
|
58e2cbcf51 | ||
|
|
7e5d94a281 | ||
|
|
14dc4662eb | ||
|
|
c89e1d4400 | ||
|
|
d45429127a | ||
|
|
2ccf4c9446 | ||
|
|
3d49060550 | ||
|
|
910c253b8f | ||
|
|
92a123de78 | ||
|
|
b78a6ec4ec | ||
|
|
7bcea67f9e | ||
|
|
86747ac16c | ||
|
|
3613676b81 | ||
|
|
86a19a559c | ||
|
|
fb62419006 | ||
|
|
bc978b6add | ||
|
|
ad837a7d24 | ||
|
|
da734db699 | ||
|
|
a2003f72c8 | ||
|
|
693e1ce641 | ||
|
|
cdb4b5746e | ||
|
|
30935885d4 | ||
|
|
473273627e | ||
|
|
9534fd5881 | ||
|
|
ba05d685c4 | ||
|
|
8ce9cd97b4 | ||
|
|
4b4773f8a5 | ||
|
|
4e16365991 | ||
|
|
bc59190021 | ||
|
|
07b165b3ad | ||
|
|
bd596bec75 | ||
|
|
64414f61e0 | ||
|
|
7e04e840c4 | ||
|
|
30574923e5 | ||
|
|
3485ed02e6 | ||
|
|
3295e23553 | ||
|
|
48d8e01769 | ||
|
|
361826908e | ||
|
|
f344fddcdf | ||
|
|
03d44c9d23 | ||
|
|
aba539856e | ||
|
|
70ca6ace3d | ||
|
|
b3f89493b0 | ||
|
|
0e3c4e274e | ||
|
|
bce7c04afe | ||
|
|
04c8cb8a85 | ||
|
|
d9a0714622 | ||
|
|
9cb2298764 | ||
|
|
a68b21e9bd | ||
|
|
c2ea042a6c | ||
|
|
3c46d9c257 | ||
|
|
849bc0ed76 | ||
|
|
709887d5ff | ||
|
|
b9c6c47db4 | ||
|
|
d95771f9b4 | ||
|
|
7e55e7d8ea | ||
|
|
5e91ded7b5 | ||
|
|
98505fd999 | ||
|
|
5a39f5ce45 | ||
|
|
2fc7254149 | ||
|
|
862d5e8c7b | ||
|
|
f61ea0f070 | ||
|
|
8b4fdf3f34 | ||
|
|
0591499471 | ||
|
|
5312c31253 | ||
|
|
8a31bc84aa | ||
|
|
b5d8ad6e9a | ||
|
|
2fb61d4807 | ||
|
|
184f157c25 | ||
|
|
b54de50c1a | ||
|
|
b364871df5 | ||
|
|
9571e247b5 | ||
|
|
e52759791d | ||
|
|
b8170c6799 | ||
|
|
f224a2782d | ||
|
|
d901c6bf91 | ||
|
|
a449fe6f69 | ||
|
|
673b172871 | ||
|
|
1bb7b3e274 | ||
|
|
966ceea5f8 | ||
|
|
b09be9f5de | ||
|
|
7493c7d548 | ||
|
|
49ea502662 | ||
|
|
df2e45f478 | ||
|
|
cb8c7e8d56 | ||
|
|
4b51bd7116 | ||
|
|
b88367d079 | ||
|
|
f724863bc7 | ||
|
|
5d26e76ec2 | ||
|
|
73b17941ce | ||
|
|
d59399b59c | ||
|
|
09693df6eb | ||
|
|
4e1f2db8ca | ||
|
|
499ba4c4ab | ||
|
|
df2e9c402d | ||
|
|
3a73b63544 | ||
|
|
4d8faa1099 | ||
|
|
3ef2cf3f0e | ||
|
|
474627e437 | ||
|
|
55b6253b30 | ||
|
|
6325212dfb | ||
|
|
0f66a081a3 | ||
|
|
9dbd08eec9 | ||
|
|
07a50717c4 | ||
|
|
e5a3af1aa7 | ||
|
|
a0a2cce04a | ||
|
|
af48f2d695 | ||
|
|
41882d3465 | ||
|
|
60c614df9d | ||
|
|
c81f958efb | ||
|
|
7ca863f04b | ||
|
|
f0908643f6 | ||
|
|
96496f14ba | ||
|
|
0b31c6a608 | ||
|
|
d02cc0bd22 | ||
|
|
8449c8b9d9 | ||
|
|
ab0fc28c26 | ||
|
|
77265805ac | ||
|
|
611d0131c8 | ||
|
|
1f090f9d27 | ||
|
|
1140769b62 | ||
|
|
2e579b82ef | ||
|
|
58da675a7c | ||
|
|
a0bf3b65e9 | ||
|
|
93826ddfd8 | ||
|
|
24337ba172 | ||
|
|
4ad6706b47 | ||
|
|
c33ea7c0d0 | ||
|
|
c4783eae37 | ||
|
|
cb3aad5ab4 | ||
|
|
c5d4679c9a | ||
|
|
06521023a0 | ||
|
|
89de43b916 | ||
|
|
b8b6da0780 | ||
|
|
4e577fbe9b | ||
|
|
3def8154be | ||
|
|
3552f29853 | ||
|
|
d86ac3f434 | ||
|
|
0ec8bdb92b | ||
|
|
bfbeff6a86 | ||
|
|
ea419d0481 | ||
|
|
cf51054460 | ||
|
|
612c81f01a | ||
|
|
4f98303b4c | ||
|
|
ae82d9a5ad | ||
|
|
0164d15910 | ||
|
|
3e6d79942a | ||
|
|
6c66c70094 | ||
|
|
7383cba61f | ||
|
|
838d33510b | ||
|
|
235cc9f241 | ||
|
|
a3e3e0682b | ||
|
|
9b00e1f16a | ||
|
|
22a87ce3ee | ||
|
|
3388c7b5d3 | ||
|
|
4f8fd211f3 | ||
|
|
523ce285a1 |
11
.gitattributes
vendored
11
.gitattributes
vendored
@ -1,9 +1,10 @@
|
||||
* text=auto
|
||||
*.sp diff=sourcepawn
|
||||
*.txt diff=astextplain
|
||||
*.cfg diff=astextplain
|
||||
*.inc diff=sourcepawn linguist-language=SourcePawn
|
||||
*.sp diff=sourcepawn linguist-language=SourcePawn
|
||||
*.txt diff
|
||||
*.cfg diff
|
||||
|
||||
*.smx binary
|
||||
*.mp3 binary
|
||||
*.vmt binary
|
||||
*.vtf binary
|
||||
*.vmt diff
|
||||
*.vtf binary
|
||||
|
||||
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
@ -1,2 +1 @@
|
||||
github: [shavitush]
|
||||
custom: https://paypal.me/shavitush
|
||||
|
||||
|
||||
84
.github/workflows/ci.yml
vendored
Normal file
84
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
name: Compile
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
compile:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
sm-version: [ '1.12' ]
|
||||
|
||||
name: "Build SM ${{ matrix.sm-version }}"
|
||||
steps:
|
||||
- name: Prepare env
|
||||
shell: bash
|
||||
run: echo "GITHUB_SHA_SHORT=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup SP
|
||||
uses: rumblefrog/setup-sp@master
|
||||
with:
|
||||
version: ${{ matrix.sm-version }}
|
||||
|
||||
- name: Download and extract dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
# Mac zip just because it's smaller & we don't repack the extensions...
|
||||
wget https://github.com/ErikMinekus/sm-ripext/releases/download/1.3.1/sm-ripext-1.3.1-mac.zip
|
||||
unzip sm-ripext-1.3.1-mac.zip "addons/sourcemod/scripting/include/*"
|
||||
wget https://github.com/clugg/sm-json/archive/refs/tags/v5.0.1.tar.gz
|
||||
tar --strip-components=1 -xvzf v5.0.1.tar.gz sm-json-5.0.1/addons/sourcemod/scripting/include
|
||||
wget https://github.com/hermansimensen/eventqueue-fix/archive/refs/heads/main.tar.gz
|
||||
tar --strip-components=1 -xvzf main.tar.gz -C addons/sourcemod
|
||||
rm -rf *.zip *.tar.gz addons/sourcemod/.git* addons/sourcemod/LICENSE
|
||||
wget https://github.com/srcwr/eventqueuefixfix/releases/download/v1.0.1/eventqueuefixfix-v1.0.1-def5b0e-windows-x32.zip
|
||||
unzip eventqueuefixfix-v1.0.1-def5b0e-windows-x32.zip "addons/sourcemod/extensions/*"
|
||||
rm "addons/sourcemod/extensions/eventqueuefixfix.pdb"
|
||||
wget https://github.com/srcwr/srcwrfloppy/releases/download/v2.0.4/srcwrfloppy-v2.0.4.zip
|
||||
unzip -qO UTF-8 srcwrfloppy-v2.0.4.zip "addons/sourcemod/extensions/*"
|
||||
rm "addons/sourcemod/extensions/srcwr💾.pdb"
|
||||
|
||||
- name: Run compiler
|
||||
shell: bash
|
||||
run: |
|
||||
cd addons/sourcemod
|
||||
mkdir plugins
|
||||
for src in $(find scripting -maxdepth 1 -type f -name "*.sp");
|
||||
do
|
||||
spcomp $src -o=plugins/$(basename $src .sp)'.smx' -i=scripting/include -v2
|
||||
done
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bhoptimer-${{ github.head_ref || github.ref_name }}-sm${{ matrix.sm-version }}-${{ env.GITHUB_SHA_SHORT }}
|
||||
path: |
|
||||
addons
|
||||
materials
|
||||
sound
|
||||
CHANGELOG.md
|
||||
LICENSE
|
||||
README.md
|
||||
retention-days: 14
|
||||
|
||||
release:
|
||||
name: Release
|
||||
if: github.ref_type == 'tag'
|
||||
needs: compile
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Archive artifacts
|
||||
shell: bash
|
||||
run: find * -maxdepth 0 -type d -exec zip -rq {}.zip {} \;
|
||||
|
||||
- uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
draft: true
|
||||
name: ${{ github.ref_name }}
|
||||
artifacts: "*.zip"
|
||||
29
.travis.yml
29
.travis.yml
@ -1,29 +0,0 @@
|
||||
sudo: false
|
||||
|
||||
addons:
|
||||
apt_packages:
|
||||
- lib32stdc++6 # needed for spcomp
|
||||
|
||||
env:
|
||||
- SMVERSION=1.10
|
||||
|
||||
before_script:
|
||||
# install smbuilder
|
||||
- git clone https://github.com/splewis/sm-builder
|
||||
- cd sm-builder
|
||||
- pip install --user -r requirements.txt
|
||||
- python setup.py install --prefix=~/.local
|
||||
- cd ..
|
||||
|
||||
# install the sourcemod compiler
|
||||
- SMPACKAGE="http://sourcemod.net/latest.php?os=linux&version=${SMVERSION}"
|
||||
- wget $SMPACKAGE
|
||||
- tar xfz $(basename $SMPACKAGE)
|
||||
- cd addons/sourcemod/scripting/
|
||||
- chmod +x spcomp
|
||||
- PATH+=":$PWD"
|
||||
|
||||
- cd ../../..
|
||||
|
||||
script:
|
||||
- smbuilder --flags="-E"
|
||||
1895
CHANGELOG.md
Normal file
1895
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
64
FEATURES.md
64
FEATURES.md
@ -1,64 +0,0 @@
|
||||
# shavit's simple bhop timer
|
||||
*a bhop server should be simple*
|
||||
|
||||
### Features
|
||||
---
|
||||
|
||||
#### shavit-core (REQUIRED)
|
||||
`bhoptimer`'s core.
|
||||
It handles connections to the database and exposes an API (natives/forwards) for developers and other modules.
|
||||
Calculations, gameplay mechanics and such are all handled by the core plugin.
|
||||
|
||||
Includes *but not limited to*: Custom chat messages and colors, snapshots, pausing/resuming, styles (configurable), automatic bunnyhopping, strafe/sync meters that work for most playstyles, double-step fixer (+ds), practice mode, +strafe blocking, +left/right blocking, pre-jump blocking, HSW style (including SHSW) that cannot be abused with joypads, per-style `sv_airaccelerate` values, teleportation commands (start/end).
|
||||
|
||||
#### shavit-zones (REQUIRED)
|
||||
The zones plugins handles everything related to map zones (such as start/end zone etc) and is necessary for `bhoptimer` to operate.
|
||||
Zones are trigger based and are very lightweight.
|
||||
|
||||
The zones plugin includes some less common features such as: Multiple tracks (main/bonus), zone editing (after setup), snapping zones to walls/corners/grid, zone setup using the cursor's position, configurable sprite/colors for zone types, zone tracks (main/bonus - can be extended), manual adjustments of coordinates before confirmations, teleport zones, glitch zones, no-limit zones (for styles like 400-velocity), flat/3D boxes for zone rendering, an API and more.
|
||||
|
||||
It also contains support for built-in map timers (KZ) and the [Fly](https://github.com/3331/fly) zoning standard.
|
||||
|
||||
#### shavit-chat
|
||||
The chat plugin manipulates chat messages sent by players.
|
||||
It includes custom chat names, tags, colors and all can be defined by the players/admins.
|
||||
Admins need the chat flag, or the "shavit_chat" override (good for a donator perk).
|
||||
There's a user-friendly command named !cchelp so the users can easily understand what's going on.
|
||||
In addition, it integrates with rankings and allows you to have titles for players according to their ranking, relative ranking or points in the server using !chatranks.
|
||||
|
||||
#### shavit-hud
|
||||
The HUD plugin is `bhoptimer`'s OSD frontend.
|
||||
It shows most (if not all) of the information that the player needs to see.
|
||||
`shavit-hud` integrates with [Bunnyhop Statistics](https://github.com/shavitush/bhopstats) for CS:S.
|
||||
|
||||
Some features are: Per-player settings (!hud), truevel and gradient-like display (CS:GO).
|
||||
|
||||
#### shavit-misc
|
||||
This plugin handles miscellaneous things used in bunnyhop servers.
|
||||
|
||||
Such as: Segmented runs, team handling (respawning/spectating too), spectators list (!specs), smart player hiding that works for spectating too, teleportation to other players, weapon commands (!knife/!usp/!glock) and ammo management, segmented checkpoints, noclipping (can be set to work for VIPs/admins only), drop-all, godmode, prespeed blocking, prespeed limitation, chat tidying, radar hiding, weapon drop cleaning, player collision removal, auto-respawning, spawn points generator, radio removal, scoreboard manipulation, model opacity changes, fixed runspeed, automatic and configurable chat advertisements, player ragdoll removal and WR messages.
|
||||
|
||||
#### shavit-rankings
|
||||
Enables !rank, !top and introduces map tiers (!settier).
|
||||
Each record gets points assigned to it according to the map's tier and overall - how good the time is.
|
||||
This system doesn't allow "rank grinding" by beating all of the easy maps on the server but instead, awards the players that get the best times on the hardest maps and styles.
|
||||
|
||||
#### shavit-replay
|
||||
Creates a replay bot that records the players' world records and playback them on command (!replay/automatic).
|
||||
The replay bot playback can be stopped (if central) and the saved replay can be deleted by server administrators.
|
||||
Replay bots will change their clan tags/names according to the server's configuration.
|
||||
|
||||
#### shavit-sounds
|
||||
Will play custom sounds when event actions happen.
|
||||
Such as: Getting a world record, improving your own record, getting the worst record in the server, beating a map for the first time or setting a rank #X record.
|
||||
|
||||
#### shavit-stats
|
||||
The statistics plugin is a statistics frontend for the players.
|
||||
It displays rankings, maps done, maps left, server records, SteamID, country, map completion, last login date and more useful information!
|
||||
|
||||
#### shavit-timelimit
|
||||
Sets a dynamic map time limit according to the average completion time of the map.
|
||||
|
||||
#### shavit-wr (REQUIRED)
|
||||
Saves the players' records to the database and allows players to see the server's records.
|
||||
The ability to see records for other maps also exists and can be lazily looked up (!wr map_name, or a part of the map's name).
|
||||
265
README.md
265
README.md
@ -2,43 +2,269 @@
|
||||
|
||||
### RECOMPILE ALL YOUR PLUGINS THAT USE `#include <shavit>` OR STUFF WILL BREAK
|
||||
|
||||
### Build status
|
||||
[](https://travis-ci.org/shavitush/bhoptimer)
|
||||
### CS:GO is dead. Support won't be removed and gamedata should:tm: still work but it isn't actively tested.
|
||||
|
||||
[AlliedModders thread](https://forums.alliedmods.net/showthread.php?t=265456)
|
||||
[AlliedModders thread](https://forums.alliedmods.net/showthread.php?t=265456) // !!! OUTDATED !!!
|
||||
|
||||
[Download](https://github.com/shavitush/bhoptimer/releases)
|
||||
|
||||
# shavit's bhop timer
|
||||
|
||||
This is (nearly) an all-in-one server plugin for Counter-Strike: Source, Counter-Strike: Global Offensive, and Team Fortress 2 that adds a timer system and many other utilities, so you can install it and run a proper bunnyhop server.
|
||||
This is nearly an all-in-one server plugin suite for Counter-Strike: Source, Counter-Strike: Global Offensive, and Team Fortress 2 that adds a timer system and many other utilities, so you can install it and run a proper bunnyhop server.
|
||||
|
||||
Includes a records system, map zones (start/end marks etc), bonuses, HUD with useful information, chat processor, miscellaneous such as weapon commands/spawn point generator, bots that replay the best records of the map, sounds, statistics, segmented running, a fair & competitive rankings system and more!
|
||||
Includes a records system, map zones (start/end marks etc), bonuses, HUD with useful information, chat processor, miscellaneous things such as weapon commands/spawn point generator, bots that replay the best records of the map, sounds, statistics, segmented running, a fair & competitive rankings system, and more!
|
||||
|
||||
[Mapzones Setup Demonstration](https://youtu.be/OXFMGm40F6c)
|
||||
|
||||
# Requirements:
|
||||
* Steam version of Counter-Strike: Source, Counter-Strike: Global Offensive, or Team Fortress 2.
|
||||
* [Metamod:Source](https://www.sourcemm.net/downloads.php?branch=stable) and [SourceMod 1.10 or above](https://www.sourcemod.net/downloads.php?branch=stable) installed.
|
||||
* A MySQL database (preferably locally hosted) if your database is likely to grow big, or if you want to use the rankings plugin. MySQL server version of 5.5.5 or above (MariaDB equivalent works too) is highly recommended.
|
||||
* [DHooks](https://github.com/peace-maker/DHooks2/releases)
|
||||
* [Metamod:Source](https://www.sourcemm.net/downloads.php?branch=stable) and [SourceMod](https://www.sourcemod.net/downloads.php?branch=stable) 1.12 or higher.
|
||||
* A MySQL database (preferably locally hosted) if your database is likely to grow big, or if you want to use the rankings plugin. MySQL server version of 5.5.5 or above (MariaDB equivalent works too) is required.
|
||||
|
||||
# Optional requirements, for the best experience:
|
||||
* [eventqueuefix](https://github.com/hermansimensen/eventqueue-fix)
|
||||
* Some booster fixing and scaling booster delays by timescale. (Use this instead of `boosterfix`)
|
||||
* [Bunnyhop Statistics](https://forums.alliedmods.net/showthread.php?t=286135)
|
||||
* Used for scroll styles and also required for TF2.
|
||||
* Allows for timescaling boosters and is used to fix some exploits. (Use this instead of `boosterfix`)
|
||||
* (included in bhoptimer release zips)
|
||||
* Along with using [eventqueuefixfix](https://github.com/srcwr/eventqueuefixfix) at the same time to fix eventqueuefix on Windows after the 2025-02-18 update.
|
||||
* [srcwr💾](https://github.com/srcwr/srcwrfloppy)
|
||||
* Saves replays asynchronously (read: doesn't lag the server when saving a replay).
|
||||
* (included in bhoptimer release zips)
|
||||
* [SteamWorks](https://forums.alliedmods.net/showthread.php?t=229556)
|
||||
* Used to grab `{serverip}` in advertisements.
|
||||
* [DynamicChannels](https://github.com/Vauff/DynamicChannels)
|
||||
|
||||
# Installation:
|
||||
Refer to the [wiki page](https://github.com/shavitush/bhoptimer/wiki/1.-Installation-(from-source)).
|
||||
# Installation
|
||||
|
||||
# Required plugins:
|
||||
- `shavit-core`
|
||||
- `shavit-zones`
|
||||
- `shavit-wr`
|
||||
* [Build from source](https://github.com/shavitush/bhoptimer/wiki/1.-Installation-(from-source))
|
||||
* [Download an existing release](https://github.com/shavitush/bhoptimer/releases) - installing is simply drag & drop into the game server's directory.
|
||||
|
||||
# Configuration
|
||||
|
||||
The [wiki](https://github.com/shavitush/bhoptimer/wiki) contains most relevant information regarding configuration, under the 2nd category's pages.
|
||||
|
||||
Configuration files are in `cfg/sourcemod/plugin.shavit-*.cfg` and `addons/sourcemod/configs/shavit-*`.
|
||||
|
||||
# bhoptimer modules:
|
||||
|
||||
### shavit-core (REQUIRED)
|
||||
`bhoptimer`'s core.
|
||||
It handles connections to the database and exposes an API (natives/forwards) for developers and other modules.
|
||||
Calculations, gameplay mechanics and such are all handled by the core plugin.
|
||||
|
||||
Includes *but not limited to*: Custom chat messages and colors, snapshots, pausing/resuming, styles (configurable), automatic bunnyhopping, strafe/sync meters that work for most playstyles, double-step fixer (+ds), practice mode, +strafe blocking, +left/right blocking, pre-jump blocking, HSW style (including SHSW) that cannot be abused with joypads, per-style `sv_airaccelerate` values, teleportation commands (start/end).
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!style, !styles, !diff, !difficulty - Choose your bhop style.
|
||||
!s, !start, !r, !restart - Start your timer.
|
||||
!b, !bonus, !b1, !b2, etc - Start your timer on the bonus track.
|
||||
!m, !main - Start your timer on the main track.
|
||||
!end - Teleport to endzone.
|
||||
!bend, !bonusend - Teleport to endzone of the bonus track.
|
||||
!stop - Stop your timer.
|
||||
!pause, !unpause, !resume - Toggle pause.
|
||||
!auto, !autobhop - Toggle autobhop.
|
||||
|
||||
Admin commands:
|
||||
!deletemap (RCON flag) - Deletes all map data.
|
||||
!wipeplayer (BAN flag) - Wipes all bhoptimer data for specified player.
|
||||
!migration (ROOT flag) - Force a database migration to run.
|
||||
```
|
||||
|
||||
### shavit-wr (REQUIRED)
|
||||
Saves the players' records to the database and allows players to see the server's records.
|
||||
The ability to see records for other maps also exists and can be lazily looked up (!wr map_name, or a part of the map's name).
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!wr, !worldrecord - View the leaderboard of a map. Usage: !wr [map]
|
||||
!bwr, !bworldrecord, !bonusworldrecord - View the *bonus* leaderboard of a map. Usage: !bwr [map]
|
||||
!recent, !recentrecords, !rr - View the recent #1 times set.
|
||||
!pb, !time, !times - View a player's times on a specific map.
|
||||
|
||||
Admin commands: (RCON flag)
|
||||
!delete, !deleterecord, !deleterecords - Opens a record deletion menu interface.
|
||||
!deletall - Deletes all the records for this map.
|
||||
```
|
||||
|
||||
### shavit-zones (REQUIRED)
|
||||
The zones plugins handles everything related to map zones (such as start/end zone etc) and is necessary for `bhoptimer` to operate.
|
||||
Zones are trigger based and are very lightweight.
|
||||
|
||||
The zones plugin includes some less common features such as: Multiple tracks (main/bonus), zone editing (after setup), snapping zones to walls/corners/grid, zone setup using the cursor's position, configurable sprite/colors for zone types, zone tracks (main/bonus - can be extended), manual adjustments of coordinates before confirmations, teleport zones, glitch zones, no-limit zones (for styles like 400-velocity), flat/3D boxes for zone rendering, an API and more.
|
||||
|
||||
It also contains support for built-in map timers (KZ) and the [Fly](https://github.com/PMArkive/fly) zoning standard.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!set, !setstart, !ss, !sp, !startpoint - Set your current position as the teleport location on restart.
|
||||
!deletestart, !deletesetstart, !delss, !delsp - Delete your spawn point.
|
||||
!drawallzones, !drawzones - Draws all zones (if the server has the cvar for this enabled).
|
||||
|
||||
Admin commands: (RCON flag)
|
||||
!zones, !mapzones, !addzone - Opens the mapzones menu.
|
||||
!deletezone, !delzone - Delete a mapzone.
|
||||
!deleteallzones - Delete all mapzones.
|
||||
!modifier - Changes the axis modifier for the zone editor. Usage: !modifier <number>
|
||||
!addspawn - Adds a custom spawn location.
|
||||
!delspawn - Deletes a custom spawn location.
|
||||
!zoneedit, !editzone, !modifyzone - Modify an existing zone.
|
||||
!setstart, !spawnpoint, !ss, !sp - Set your restart position & angles in a start zone.
|
||||
!tptozone - Teleport to a zone.
|
||||
|
||||
Admin commands: (ROOT flag)
|
||||
!reloadzonesettings - Reloads the zone settings.
|
||||
```
|
||||
|
||||
### shavit-chat
|
||||
The chat plugin manipulates chat messages sent by players.
|
||||
It includes custom chat names, tags, colors and all can be defined by the players/admins.
|
||||
Admins need the chat flag, or the "shavit_chat" override (good for a donator perk).
|
||||
There's a user-friendly command named !cchelp so the users can easily understand what's going on.
|
||||
In addition, it integrates with rankings and allows you to have titles for players according to their ranking, relative ranking or points in the server using !chatranks.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!cchelp - Provides help with setting a custom chat name/message color.
|
||||
!ccname - Toggles/sets a custom chat name. Usage: !ccname <text> or !ccname "off" to disable.
|
||||
!ccmsg, !ccmessage - Toggles/sets a custom chat message color. Usage: !ccmsg <color> or !ccmsg "off" to disable.
|
||||
!chatrank, !chatranks - View a menu with the chat ranks available to you.
|
||||
|
||||
Admin commands: (CHAT flag)
|
||||
!ccadd - Give a user ccname & ccmsg access by steamid. Usage: !ccadd <steamid>
|
||||
|
||||
Admin commands: (ROOT flag)
|
||||
!ccdelete - Remove a user's ccname & ccmsg access that was granted by !ccadd. Usage: !ccdelete <steamid>
|
||||
!cclist - Print the custom chat setting of all online players.
|
||||
!reloadchatranks - Reloads the chatranks config file.
|
||||
```
|
||||
|
||||
### shavit-hud
|
||||
The HUD plugin is `bhoptimer`'s OSD frontend.
|
||||
It shows most (if not all) of the information that the player needs to see.
|
||||
|
||||
Some features are: Per-player settings (!hud), truevel, and gradient-like display (CS:GO).
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!hud, !options - Opens the HUD settings menu.
|
||||
!keys, !showkeys, !showmykeys - Draw plugin keys on screen.
|
||||
!master, !masterhud - Toggles the HUD.
|
||||
!center, !centerhud - Toggles the center text HUD.
|
||||
!zonehud - Toggles the zone HUD.
|
||||
!hidewep, !hideweap, !hideweapon - Toggles weapon hiding.
|
||||
!2dvel, !truevel, !truvel - Toggles 2D ('true') velocity.
|
||||
```
|
||||
|
||||
### shavit-mapchooser
|
||||
Replaces `mapchooser` to provide `bhoptimer` integration into nomination and map vote menus.
|
||||
|
||||
```
|
||||
Admin commands: (CHANGEMAP flag)
|
||||
!forcemapvote - Forces the map vote to happen.
|
||||
!reloadmaplist - Reloads the maplist.
|
||||
!reloadmap, !restartmap - Reloads the current map.
|
||||
!loadunzonedmap - Loads a random map from the maps folder that is unzoned.
|
||||
```
|
||||
|
||||
### shavit-checkpoints
|
||||
This plugin handles checkpoint related things such as segmented runs & savestates/persistent-data.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!cp, !cpmenu, !checkpoint, !checkpoints - Opens the checkpoints menu.
|
||||
!save - Saves a checkpoint.
|
||||
!tele - Teleports to a checkpoint (default: 1). Usage: !tele [number]
|
||||
!prevcp - Selects the previous checkpoint.
|
||||
!nextcp - Selects the next checkpoint.
|
||||
!deletecp - Deletes the current checkpoint.
|
||||
```
|
||||
|
||||
### shavit-misc
|
||||
This plugin handles miscellaneous things used in bunnyhop servers.
|
||||
|
||||
Such as: team handling (respawning/spectating too), spectators list (!specs), smart player hiding that works for spectating too, teleportation to other players, weapon commands (!knife/!usp/!glock) and ammo management, noclipping (can be set to work for VIPs/admins only), drop-all, godmode, prespeed blocking, prespeed limitation, chat tidying, radar hiding, weapon drop cleaning, player collision removal, auto-respawning, spawn points generator, radio removal, scoreboard manipulation, model opacity changes, fixed runspeed, automatic and configurable chat advertisements, player ragdoll removal, and WR messages.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!specs, !spectators - Show a list of spectators.
|
||||
!spec, !spectate - Moves you to the spectators' team. Usage: !spec [target]
|
||||
!hide, !unhide - Toggle players' hiding.
|
||||
!tpto, !goto - Teleport to another player. Usage: !tpto [target]
|
||||
!usp, !glock, !knife - Spawn a USP/Glock/Knife.
|
||||
!nc, !prac, !practice, !noclipme, +noclip, sm_noclip - Toggles noclip.
|
||||
!adverts - Prints all adverts to the client.
|
||||
```
|
||||
|
||||
### shavit-rankings
|
||||
Enables !rank, !top and introduces map tiers (!settier).
|
||||
Each record gets points assigned to it according to the map's tier and overall - how good the time is.
|
||||
This system doesn't allow "rank grinding" by beating all of the easy maps on the server but instead, awards the players that get the best times on the hardest maps and styles.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!tier, !maptier - Prints the map's tier to chat.
|
||||
!rank - Show your or someone else's rank. Usage: !rank [name]
|
||||
!top - Show the top 100 players.
|
||||
|
||||
Admin commands: (RCON flag)
|
||||
!settier, !setmaptier - Change the map's tier. Usage: !settier <tier>
|
||||
!recalcmap - Recalculate the current map's records' points.
|
||||
|
||||
Admin commands: (ROOT flag)
|
||||
!recalcall - Recalculate the points for every map on the server. Run this after you change the ranking multiplier for a style or after you install the plugin.
|
||||
```
|
||||
|
||||
### shavit-replay-playback
|
||||
Creates a replay bot that records the players' world records and playback them on command (!replay/automatic).
|
||||
The replay bot playback can be stopped (if central) and the saved replay can be deleted by server administrators.
|
||||
Replay bots will change their clan tags/names according to the server's configuration.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!replay - Opens the replay bot menu.
|
||||
|
||||
Admin commands: (RCON flag)
|
||||
!deletereplay - Open replay deletion menu.
|
||||
```
|
||||
|
||||
### shavit-replay-recorder
|
||||
This is now the actual plugin that records the replays. ||I wanted to split shavit-replay so I could deal with reloading plugins without losing replay data better.||
|
||||
|
||||
### shavit-sounds
|
||||
Will play custom sounds when event actions happen.
|
||||
Such as: Getting a world record, improving your own record, getting the worst record in the server, beating a map for the first time or setting a rank #X record.
|
||||
|
||||
### shavit-stats
|
||||
The statistics plugin is a statistics frontend for the players.
|
||||
It displays rankings, maps done, maps left, server records, SteamID, country, map completion, last login date, and more useful information!
|
||||
|
||||
```
|
||||
Player commands:
|
||||
!p, !profile, !stats - Show the player's profile. Usage: !profile [target]
|
||||
!mapsdone - Shows the maps the player has finished.
|
||||
!mapsleft - Shows maps that the player has not finished yet.
|
||||
!playtime - Shows the top playtime list.
|
||||
```
|
||||
|
||||
### shavit-timelimit
|
||||
Sets a dynamic map time limit according to the average completion time of the map.
|
||||
|
||||
```
|
||||
Admin commands: (CHANGEMAP flag)
|
||||
!extend, !extendmap - Extend the map.
|
||||
```
|
||||
|
||||
### shavit-tas
|
||||
Provides autostrafers and other TAS related functionality.
|
||||
|
||||
```
|
||||
Player commands:
|
||||
+autostrafer/-autostrafer, !autostrafer - Toggle the autostrafer.
|
||||
+autoprestrafe/-autoprestrafe, !autoprestrafe - Toggle automatically prestrafing.
|
||||
+autojumponstart/-autojumponstart, !autojumponstart - Toggle jumping automatically on start.
|
||||
+edgejump/-edgejump, !edgejump - Toggle edge jumping.
|
||||
```
|
||||
|
||||
# Recommended plugins:
|
||||
* [MomSurfFix](https://forums.alliedmods.net/showthread.php?p=2680743) ([github](https://github.com/GAMMACASE/MomSurfFix))
|
||||
@ -51,6 +277,8 @@ Refer to the [wiki page](https://github.com/shavitush/bhoptimer/wiki/1.-Installa
|
||||
- Allows players to toggle trigger visibility.
|
||||
* [ShowPlayerClips](https://forums.alliedmods.net/showthread.php?p=2661942) ([github](https://github.com/GAMMACASE/ShowPlayerClips))
|
||||
- Allows players to toggle player clip visibility.
|
||||
* [JumpStats](https://github.com/Nimmy2222/bhop-get-stats)
|
||||
- Covers SSJ, Jhud, StrafeTrainer, Strafe Offsets and FJT. Colors, HUD positioning editor, cookies, etc
|
||||
* [shavit-ssj](https://github.com/Nairdaa/shavit-ssj)
|
||||
- Speed of Sixth Jump + more, customisable settings with cookies remembering user prefered settings.
|
||||
* [shavit-jhud](https://github.com/blankbhop/jhud)
|
||||
@ -62,7 +290,8 @@ Refer to the [wiki page](https://github.com/shavitush/bhoptimer/wiki/1.-Installa
|
||||
* [mpbhops_but_better](https://github.com/rtldg/mpbhops_but_working)
|
||||
- A cleaner and faster mpbhops/mpbh plugin that also makes door vertical-boosters consistent and frozen.
|
||||
|
||||
* TODO: `paint`, `ljstats`, `bash2`
|
||||
### CS:GO
|
||||
* [NoViewPunch](https://github.com/hermansimensen/NoViewPunch)
|
||||
- Removes the viewpunch from landing in CS:GO.
|
||||
* [CS:GO Movement unlocker](https://forums.alliedmods.net/showthread.php?t=255298)
|
||||
- Enables prespeeding (no 240 velocity cap for runspeed anymore)
|
||||
|
||||
@ -1,59 +1,65 @@
|
||||
|
||||
"Map fixes"
|
||||
{
|
||||
"bhop_amaranthglow"
|
||||
"bhop_strafecontrol"
|
||||
{
|
||||
"shavit_zones_prebuilt_visual_offset" "16"
|
||||
}
|
||||
"bhop_crash_egypt"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "player"
|
||||
}
|
||||
"bhop_downtown"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "fil_fw"
|
||||
}
|
||||
"bhop_drop"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "activator_boost"
|
||||
}
|
||||
"bhop_kirous"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "state0"
|
||||
}
|
||||
"bhop_microwave"
|
||||
{
|
||||
"shavit_misc_resettargetname" "0"
|
||||
}
|
||||
"bhop_overthinker"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "noobinside"
|
||||
"shavit_misc_resettargetname_bonus" "filter_bonus"
|
||||
}
|
||||
"bhop_overthinker_go"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "noobinside"
|
||||
"shavit_misc_resettargetname_bonus" "filter_bonus"
|
||||
}
|
||||
"bhop_shutdown"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "asdf"
|
||||
}
|
||||
"bhop_space"
|
||||
{
|
||||
"shavit_misc_resettargetname" "0"
|
||||
}
|
||||
"bhop_symbiotic"
|
||||
{
|
||||
"shavit_misc_resettargetname_main" "filter_main"
|
||||
"shavit_misc_resettargetname_bonus" "filter_bonus"
|
||||
"shavit_zones_extra_spawn_height" "1.0"
|
||||
}
|
||||
"bhop_tranquility"
|
||||
{
|
||||
"shavit_zones_prebuilt_visual_offset" "16"
|
||||
}
|
||||
"kz_bhop_izanami"
|
||||
"bhop_amaranthglow"
|
||||
{
|
||||
"shavit_misc_resettargetname" "0"
|
||||
"shavit_zones_prebuilt_visual_offset" "16"
|
||||
}
|
||||
|
||||
"bhop_apathy"
|
||||
{
|
||||
"shavit_zones_resettargetname_main" "apathy"
|
||||
}
|
||||
"bhop_crash_egypt"
|
||||
{
|
||||
"shavit_zones_resettargetname_main" "player"
|
||||
}
|
||||
"bhop_japan"
|
||||
{
|
||||
"shavit_zones_resetclassname_main" "beginner"
|
||||
}
|
||||
"bhop_space"
|
||||
{
|
||||
"shavit_zones_resetclassname_main" "sadface"
|
||||
}
|
||||
"bhop_shutdown"
|
||||
{
|
||||
"shavit_zones_resettargetname_main" "asdf"
|
||||
}
|
||||
"bhop_interloper"
|
||||
{
|
||||
"shavit_zones_resettargetname_main" "lol"
|
||||
}
|
||||
"bhop_wasd"
|
||||
{
|
||||
"shavit_zones_resettargetname_main" "default"
|
||||
}
|
||||
|
||||
"bhop_solitude"
|
||||
{
|
||||
"shavit_zones_forcetargetnamereset" "1"
|
||||
}
|
||||
"bhop_drop"
|
||||
{
|
||||
"shavit_zones_forcetargetnamereset" "1"
|
||||
"shavit_zones_resettargetname_main" "activator_boost"
|
||||
"shavit_zones_resettargetname_bonus" "activator_boost3"
|
||||
}
|
||||
"kz_bhop_kairo"
|
||||
{
|
||||
"shavit_zones_forcetargetnamereset" "1"
|
||||
"shavit_zones_resettargetname_main" "tped"
|
||||
"shavit_zones_resetclassname_main" "cp0filter"
|
||||
}
|
||||
"bhop_avantasia"
|
||||
{
|
||||
"rngfix_triggerjump" "0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@
|
||||
{
|
||||
"enabled" "1"
|
||||
"tracks" "0"
|
||||
"styles" "1;2;3;4;5;6;8;9;10;11;12;13;14;15;16"
|
||||
"styles" "1;2;3;4;5;6;8;9;11;12;13;14;15;16"
|
||||
}
|
||||
"Bonus Normal Bot"
|
||||
{
|
||||
@ -71,7 +71,7 @@
|
||||
}
|
||||
"TAS Bot"
|
||||
{
|
||||
"enabled" "0"
|
||||
"enabled" "1"
|
||||
"tracks" "0;1;2;3;4;5;6;7;8"
|
||||
"styles" "10"
|
||||
}
|
||||
|
||||
@ -22,21 +22,31 @@
|
||||
"autobhop" "1" // Enable autobhopping and +ds?
|
||||
"easybhop" "1" // Enable easybhop (disable stamina reset)?
|
||||
"prespeed" "0" // Allow prespeeding regardless of the prespeed server setting? If set to 2, the value of shavit_core_nozaxisspeed will be respected as well.
|
||||
"prespeed_ez_vel" "0" // Whether to set velocity on first jump for prespeed styles. 0 = Disabled. >0 = set velocity to this amount (e.g. 3500).
|
||||
"velocity_limit" "0.0" // Velocity limit: set to 0.0 for unlimited, 400.00 for 400vel styles etc.
|
||||
"bunnyhopping" "1" // Per-style sv_enablebunnyhopping. Leave as 1 if you want bunnyhopping to maintain player speed. This setting will override _strafe map settings.
|
||||
|
||||
// Convar overrides
|
||||
"prespeed_type" "-1" // Set the specific value of shavit_misc_prespeed to use for this style. -1 will use the current shavit_misc_prespeed value. Requires "prespeed" to be 0.
|
||||
"blockprejump" "-1" // Set the specific value of shavit_core_blockprejump to use for this style. -1 will use the current shavit_core_blockprejump value.
|
||||
"nozaxisspeed" "-1" // Set the specific value of shavit_core_nozaxisspeed to use for this style. -1 will use the current shavit_core_nozaxisspeed value.
|
||||
"restrictnoclip" "-1" // Set the specific value of shavit_misc_restrictnoclip to use for this style. -1 will use the current shavit_misc_restrictnoclip value.
|
||||
|
||||
// Physics
|
||||
"airaccelerate" "1000.0" // sv_airaccelerate value for the style.
|
||||
"runspeed" "260.00" // Running speed. Requires DHooks, shavit-misc and shavit_misc_staticprestrafe set to 1.
|
||||
"maxprestrafe" "0.0" // The max prestrafe that still allows your timer to start/restart. You generally do *not* need or want to change this unless for surf things (combined with style-setting "prespeed_type" "6" or cvar "shavit_misc_prespeed 6"). Default is 0.0 (disabled).
|
||||
"gravity" "1.0" // Gravity setting, 1.0 for default. Standard for low gravity styles is 0.6.
|
||||
"speed" "1.0" // Speed multiplier, 1.0 for default. Standard for slowmo styles is 0.5.
|
||||
"timescale" "1.0" // Timing will scale with this setting.
|
||||
"speed" "1.0" // Speed multiplier, 1.0 for default. Standard for slowmo styles is 0.5. This a multiplier for m_flLaggedMovementValue.
|
||||
"timescale" "1.0" // Timing will scale with this setting. This is a multiplier for m_flLaggedMovementValue but also affects the timer increase speed.
|
||||
|
||||
"force_timescale" "0" // Force the timescale every jump? Default is 0 for normal timescales.
|
||||
"velocity" "1.0" // % of horizontal velocity to keep per jump. a value 0.9 will make the player lose 10% of their velocity per jump. Likewise, values above 1 will result in speed gains.
|
||||
"bonus_velocity" "0.0" // Bonus velocity to gain per jump. If set to e.g. 100.0, the player will gain 100 bonus velocity per jump.
|
||||
"min_velocity" "0.0" // Minimum amount of horizontal velocity to keep per jump. If set to 600.0, the player can't have less than 600 velocity per jump.
|
||||
"jump_multiplier" "0.0" // Mulitplier for the vertical velocity per jump. 0.0 for disabled.
|
||||
"jump_bonus" "0.0" // Bonus vertical velocity to gain per jump. If set to e.g. 100.0, the player will gain 100 bonus vertial velocity per jump.
|
||||
"startinair" "0" // 0 = Start-zones will only start the timer if the player is on the ground. 1 = timer will start without requiring the player to be on the ground in the start zone. This means with 1 that it will basically only start the timer counter once you've left the start-zone. This should only be used on gamemodes that are intended for this kind of mechanic (i.e. not bhop). Also it might be easily abusable. GL. Also this probably won't work unless you set either `"prespeed" "1"` or `"nozaxisspeed" "0"`.
|
||||
|
||||
// Mode settings
|
||||
"block_w" "0" // Block +forward (W).
|
||||
@ -44,17 +54,21 @@
|
||||
"block_s" "0" // Block +back (S).
|
||||
"block_d" "0" // Block +moveright (D).
|
||||
"block_use" "0" // Block +use (E).
|
||||
"a_or_d_only" "0" // Force A-only / D-only. You still want to block_w & block_s too. The default shavit-styles.cfg has an A/D-Only style example also.
|
||||
"force_hsw" "0" // Force half-sideways gameplay. 1 for regular HSW and 2 for surf-HSW.
|
||||
"force_groundkeys" "0" // Forces the above settings even while on ground. e.g. enabling this will not allow W/D or W/A prestrafing when playing styles that disable the keys.
|
||||
"block_pleft" "0" // Block +left. 2 to stop timer.
|
||||
"block_pright" "0" // Block +right. 2 to stop timer.
|
||||
"block_pstrafe" "0" // Prevent button inconsistencies (including +pstrafe). May have false positives when players lag. Will prevent some strafe hacks too. Set this to 2 to also stop the timer.
|
||||
"kzcheckpoints" "0" // KZ styled checkpoints. They reset upon timer start and you don't get reverted to a save state, and you cannot save when airborne or someone else's checkpoints.
|
||||
|
||||
// Feature excluding
|
||||
"unranked" "0" // Unranked style. No ranking points and no records.
|
||||
"noreplay" "0" // Disable replay bot for this style. Automatically included for unranked styles.
|
||||
|
||||
// Minimum times (to help try to prevent accidents/cheats)
|
||||
"minimum_time" "3.5" // Minimum time a main-track run needs to be.
|
||||
"minimum_time_bonus" "0.5" // Minimum time a bonus-track run needs to be.
|
||||
|
||||
// Sync/strafes
|
||||
"sync" "1" // Measure synchronization between strafes.
|
||||
"strafe_count_w" "0" // Count W (+forward) for the strafe counter.
|
||||
@ -70,6 +84,21 @@
|
||||
"specialstring" "" // For modularity. Separated with semicolon. Built-in flags: "segments".
|
||||
"permission" "" // Permission required. Syntax: "flag;override". For example "p;style_tas" to require the 'p' flag or the "style_tas" override.
|
||||
"ordering" "0" // Ordering in menus where styles appear. If this value is not present, style ID will be used instead.
|
||||
|
||||
// KZ settings
|
||||
"kzcheckpoints" "0" // KZ styled checkpoints. They reset upon timer start and you don't get reverted to a save state, and you cannot save when airborne or someone else's checkpoints.
|
||||
"kzcheckpoints_ladders" "0" // KZ styled checkpoints allowed to checkpoint onto ladders (like GOKZ)
|
||||
"kzcheckpoints_ontele" "-1" // The style to be changed to on client teleporting to a checkpoint in KZ styles. The destination style will be inaccessible if enabled. -1 or set "kzcheckpoints" to 0 for disabled.
|
||||
"kzcheckpoints_onstart" "-1" // The style to be changed to on client getting inside the start zone in KZ styles. This style will be inaccessible if enabled. -1 or set "kzcheckpoints" to 0 for disabled.
|
||||
|
||||
// TAS settings
|
||||
"segments" "0" // Segments styled checkpoints. 0 for disabled.
|
||||
"tas" "0" // 0 = Do nothing. 1 = Currently sets the following keys unless they are explicity disabled: `tas_timescale -1`, `autostrafe 1`, `autoprestrafe 1`, `edgejump 1`, and `autojumponstart 1`
|
||||
"tas_timescale" "0" // TAS-like timescaling. 0 = Disabled. -1 = User can edit the timescale (TAS menu, sm_ts, sm_tsplus, sm_tsminus). >0 = Fixed tas-timescale value for the style (e.g. 0.5 for a fixed timescale). Total time-increase-rate for the player = timescale * tas_timescale
|
||||
"autostrafe" "0" // 0 = Disabled. 1 = 1tick autostrafer. 2 = velocity/autogain. 3 = velocity/autogain (no speed loss). 4 = a basic +moveleft/+moveright presser when turning. -1 = Lets players toggle between 1tick and velocity/autogain.
|
||||
"autoprestrafe" "0" // 0 = Disabled. 1 = Enables TAS prestrafer on the ground to reach.
|
||||
"edgejump" "0" // 0 = Disabled. 1 = Automatically jumps when the player will fall off a ledge next tick.
|
||||
"autojumponstart" "0" // 0 = Disabled. 1 = Automatically jumps when the player will leave the start zone.
|
||||
}
|
||||
|
||||
"1"
|
||||
@ -163,7 +192,7 @@
|
||||
|
||||
"force_hsw" "1"
|
||||
|
||||
"strafe_count_w" "1"
|
||||
"strafe_count_w" "0"
|
||||
"strafe_count_a" "1"
|
||||
"strafe_count_s" "0"
|
||||
"strafe_count_d" "1"
|
||||
@ -173,11 +202,11 @@
|
||||
|
||||
"6"
|
||||
{
|
||||
"name" "D-Only"
|
||||
"shortname" "D"
|
||||
"name" "A/D-Only"
|
||||
"shortname" "A/D"
|
||||
"htmlcolor" "9C5BBA"
|
||||
"command" "d; donly"
|
||||
"clantag" "D"
|
||||
"command" "a; aonly; ad; d; donly"
|
||||
"clantag" "A/D"
|
||||
|
||||
"autobhop" "1"
|
||||
"easybhop" "1"
|
||||
@ -185,12 +214,11 @@
|
||||
"airaccelerate" "1000.0"
|
||||
"runspeed" "260.00"
|
||||
|
||||
"a_or_d_only" "1"
|
||||
"block_w" "1"
|
||||
"block_a" "1"
|
||||
"block_s" "1"
|
||||
|
||||
"strafe_count_w" "0"
|
||||
"strafe_count_a" "0"
|
||||
"strafe_count_s" "0"
|
||||
|
||||
"rankingmultiplier" "1.50"
|
||||
@ -204,8 +232,9 @@
|
||||
"command" "sr; seg; segment; segmented"
|
||||
"clantag" "SEG"
|
||||
|
||||
"rankingmultiplier" "0.0"
|
||||
"specialstring" "segments"
|
||||
"segments" "1"
|
||||
|
||||
"rankingmultiplier" "0.0"
|
||||
}
|
||||
|
||||
"8"
|
||||
@ -216,9 +245,7 @@
|
||||
"command" "lg; lowgrav"
|
||||
"clantag" "LG"
|
||||
|
||||
"gravity" "0.6"
|
||||
|
||||
"unranked" "1"
|
||||
"gravity" "0.5"
|
||||
}
|
||||
|
||||
"9"
|
||||
@ -229,9 +256,21 @@
|
||||
"command" "slow; slowmo"
|
||||
"clantag" "SLOW"
|
||||
|
||||
"speed" "0.5"
|
||||
"timescale" "0.5"
|
||||
}
|
||||
|
||||
"unranked" "1"
|
||||
"10"
|
||||
{
|
||||
"name" "TAS"
|
||||
"shortname" "TAS"
|
||||
"htmlcolor" "123456"
|
||||
"command" "tas"
|
||||
"clantag" "TAS"
|
||||
|
||||
"tas" "1"
|
||||
"segments" "1"
|
||||
"specialstring" "bash_bypass; oryx_bypass"
|
||||
|
||||
"rankingmultiplier" "0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,11 +16,11 @@
|
||||
"Start"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "67"
|
||||
"green" "210"
|
||||
"blue" "230"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
|
||||
@ -30,11 +30,11 @@
|
||||
"End"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "165"
|
||||
"green" "19"
|
||||
"blue" "194"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
}
|
||||
@ -42,11 +42,11 @@
|
||||
"Glitch_Respawn"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
}
|
||||
@ -54,11 +54,11 @@
|
||||
"Glitch_Stop"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
}
|
||||
@ -66,11 +66,11 @@
|
||||
"Glitch_Slay"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
}
|
||||
@ -78,23 +78,23 @@
|
||||
"Freestyle"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "25"
|
||||
"green" "25"
|
||||
"blue" "255"
|
||||
|
||||
|
||||
"alpha" "195"
|
||||
"width" "0.5"
|
||||
}
|
||||
|
||||
"Nolimit"
|
||||
"Custom Speed Limit"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "247"
|
||||
"green" "3"
|
||||
"blue" "255"
|
||||
|
||||
|
||||
"alpha" "50"
|
||||
"width" "0.5"
|
||||
}
|
||||
@ -102,11 +102,11 @@
|
||||
"Teleport"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "4.0"
|
||||
}
|
||||
@ -114,11 +114,11 @@
|
||||
"Easybhop"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "57"
|
||||
"green" "196"
|
||||
"blue" "92"
|
||||
|
||||
|
||||
"alpha" "175"
|
||||
"width" "2.5"
|
||||
}
|
||||
@ -126,11 +126,11 @@
|
||||
"Slide"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "244"
|
||||
"green" "66"
|
||||
"blue" "92"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.5"
|
||||
}
|
||||
@ -138,11 +138,11 @@
|
||||
"Airaccelerate"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "118"
|
||||
"green" "102"
|
||||
"blue" "173"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.5"
|
||||
}
|
||||
@ -150,157 +150,277 @@
|
||||
"Stage"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "153"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
}
|
||||
|
||||
"Bonus Start"
|
||||
"No Timer Gravity"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Gravity"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Speedmod"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"No Jump"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Autobhop"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus 1 Start"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "255"
|
||||
"blue" "255"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus End"
|
||||
"Bonus 1 End"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "123"
|
||||
"green" "20"
|
||||
"blue" "250"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus Glitch_Respawn"
|
||||
"Bonus 1 Glitch_Respawn"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus Glitch_Stop"
|
||||
"Bonus 1 Glitch_Stop"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus Glitch_Slay"
|
||||
"Bonus 1 Glitch_Slay"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus Freestyle"
|
||||
"Bonus 1 Freestyle"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "25"
|
||||
"green" "25"
|
||||
"blue" "255"
|
||||
|
||||
|
||||
"alpha" "195"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus Nolimit"
|
||||
"Bonus 1 Custom Speed Limit"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "247"
|
||||
"green" "3"
|
||||
"blue" "255"
|
||||
|
||||
|
||||
"alpha" "50"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus Teleport"
|
||||
"Bonus 1 Teleport"
|
||||
{
|
||||
"visible" "0"
|
||||
|
||||
|
||||
"red" "255"
|
||||
"green" "200"
|
||||
"blue" "0"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "2.0"
|
||||
}
|
||||
|
||||
"Bonus Easybhop"
|
||||
"Bonus 1 Easybhop"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "57"
|
||||
"green" "196"
|
||||
"blue" "92"
|
||||
|
||||
|
||||
"alpha" "175"
|
||||
"width" "1.75"
|
||||
}
|
||||
|
||||
"Bonus Slide"
|
||||
"Bonus 1 Slide"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "244"
|
||||
"green" "66"
|
||||
"blue" "92"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Bonus Airaccelerate"
|
||||
"Bonus 1 Airaccelerate"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "118"
|
||||
"green" "102"
|
||||
"blue" "173"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Bonus Stage"
|
||||
|
||||
"Bonus 1 Stage"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
|
||||
"red" "204"
|
||||
"green" "153"
|
||||
"blue" "255"
|
||||
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.5"
|
||||
}
|
||||
|
||||
"Bonus 1 No Timer Gravity"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Bonus 1 Gravity"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Bonus 1 Speedmod"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "1.0"
|
||||
}
|
||||
|
||||
"Bonus 1 No Jump"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
|
||||
"Bonus 1 Autobhop"
|
||||
{
|
||||
"visible" "1"
|
||||
|
||||
"red" "255"
|
||||
"green" "0"
|
||||
"blue" "255"
|
||||
|
||||
"alpha" "255"
|
||||
"width" "0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"Games"
|
||||
{
|
||||
// A guide to find most of these signatures and offsets: https://www.youtube.com/watch?v=ekyLf6hu4qI
|
||||
// A guide to find most of these signatures and offsets: https://www.youtube.com/watch?v=ekyLf6hu4qI and another https://www.youtube.com/watch?v=J7eHgK_UYOk
|
||||
|
||||
"#default"
|
||||
{
|
||||
@ -11,10 +11,22 @@
|
||||
|
||||
"Signatures"
|
||||
{
|
||||
"CreateInterface"
|
||||
"CreateInterface_Server"
|
||||
{
|
||||
"library" "server"
|
||||
"windows" "@CreateInterface"
|
||||
"windows64" "@CreateInterface"
|
||||
"linux" "@CreateInterface"
|
||||
"linux64" "@CreateInterface"
|
||||
}
|
||||
|
||||
"CreateInterface_Engine"
|
||||
{
|
||||
"library" "engine"
|
||||
"windows" "@CreateInterface"
|
||||
"windows64" "@CreateInterface"
|
||||
"linux" "@CreateInterface"
|
||||
"linux64" "@CreateInterface"
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,42 +35,61 @@
|
||||
"OS"
|
||||
{
|
||||
"windows" "1"
|
||||
"windows64" "1"
|
||||
"linux" "2"
|
||||
"linux64" "2"
|
||||
}
|
||||
|
||||
"X64"
|
||||
{
|
||||
"windows" "0"
|
||||
"windows64" "1"
|
||||
"linux" "0"
|
||||
"linux64" "1"
|
||||
}
|
||||
|
||||
"ProcessMovement"
|
||||
{
|
||||
"windows" "1"
|
||||
"windows64" "1"
|
||||
"linux" "2"
|
||||
"linux64" "2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"csgo"
|
||||
{
|
||||
"Addresses"
|
||||
{
|
||||
"m_surfaceFriction"
|
||||
{
|
||||
"signature" "CBasePlayer->m_surfaceFriction"
|
||||
"read" "4" // skip the first 4 bytes
|
||||
}
|
||||
}
|
||||
"Offsets"
|
||||
{
|
||||
// search string "#SFUI_Notice_SprayPaint_TooClose" to find IsAbleToApplySpray and then go to the next function to find GetPlayerMaxSpeed. Then calculate the vtable offset.
|
||||
// search string: "func_pushable" and you can find CBaseTrigger::PassesTriggerFilters / CBaseVPhysicsTrigger::PassesTriggerFilters. Follow references to these functions to find the vtable and then calculate the offset...
|
||||
"CBaseTrigger::PassesTriggerFilters"
|
||||
{
|
||||
"windows" "210"
|
||||
"linux" "211"
|
||||
}
|
||||
// search string: "start %f %f %f" and then check the function call offsets above it and convert them to vtable offsets (divide by 4 most likely or whatever)
|
||||
"CCSPlayer::GetPlayerMaxSpeed"
|
||||
{
|
||||
"windows" "506"
|
||||
"linux" "507"
|
||||
"mac" "507"
|
||||
}
|
||||
// add 1 to the css offset and hope it works
|
||||
// add 1 to the css offset and hope it works (or look around the references to "Invalid counterterrorist spawnpoint")
|
||||
"CGameRules::IsSpawnPointValid"
|
||||
{
|
||||
"windows" "77"
|
||||
"linux" "78"
|
||||
"mac" "78"
|
||||
}
|
||||
// can be found inside BotAddCommand
|
||||
"WEAPONTYPE_UNKNOWN"
|
||||
{
|
||||
"windows" "19"
|
||||
"linux" "19"
|
||||
"mac" "19"
|
||||
}
|
||||
// search string: "Can't find specific footstep sound!" to find CBasePlayer::PlayStepSound.
|
||||
// then find the vtable from references and CBasePlayer::UpdateStepSound is right before PlayStepSound
|
||||
"CBasePlayer::UpdateStepSound"
|
||||
@ -66,6 +97,24 @@
|
||||
"windows" "409"
|
||||
"linux" "410"
|
||||
}
|
||||
// TODO
|
||||
"m_surfaceFriction"
|
||||
{
|
||||
"windows" "8"
|
||||
"linux" "8"
|
||||
}
|
||||
// TODO
|
||||
"GetClusterForOrigin"
|
||||
{
|
||||
"windows" "12"
|
||||
"linux" "12"
|
||||
}
|
||||
// TODO
|
||||
"GetArea"
|
||||
{
|
||||
"windows" "65"
|
||||
"linux" "65"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
@ -74,96 +123,247 @@
|
||||
"Player::DoAnimationEvent"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x56\x8B\xF1\x57\x80\xBE\x2A\x2A\x2A\x2A\x00\x74\x2A\x51"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x28\x89\x5D\xF4\x8B\x5D\x08\x89\x75\xF8\x8B\x75\x0C\x89\x7D\xFC\x8B\x7D\x10\x80\xBB\x44\x23\x00\x00\x00"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x0C\x8B\x5D\x2A\x8B\x75\x2A\x8B\x7D\x2A\x80\xBB\x2A\x2A\x2A\x2A\x00\x75"
|
||||
}
|
||||
// search string: "-nobots"
|
||||
// search string: "-nobots". On Linux this leads to `AreBotsAllowed()`, which can check the references to find MaintainBotQuota
|
||||
"BotManager::MaintainBotQuota"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x18\x89\x4D\x2A\xFF\x15"
|
||||
"linux" "\x55\x89\xE5\x83\xEC\x78\x89\x7D\x2A\x8B\x7D\x2A\x89\x5D\x2A\x89\x75\x2A"
|
||||
}
|
||||
// search string: "Error - no profile for '%s' exists."
|
||||
"CCSBotManager::BotAddCommand"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x53\x56\x57\x80\x78\x2A\x00"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x4C\x8B\x15\x2A\x2A\x2A\x2A\x8B\x7D\x2A\x8B\x75\x2A\x0F\xB6\x5D\x2A"
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x14\x89\x4D\x2A\xFF\x15"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2C\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\xA1"
|
||||
}
|
||||
// search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher.
|
||||
// Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher.
|
||||
// This sucks to find.
|
||||
"PhysicsCheckForEntityUntouch"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86\xD0\x00\x00\x00"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2C\x8B\x5D\x08\xC7\x44\x24\x04\x01\x00\x00\x00\x89\x1C\x24"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x24\x8B\x75\x2A\x6A\x01\x56"
|
||||
}
|
||||
// search string: "remove 0x%p: %s-%s (%d-%d) [%d in play, %d max]\n".
|
||||
// function with one argument is PhysicsRemoveTouchedList
|
||||
// Also, this function is referenced (at least on linux) by `CPhysicsPropRespawnable::Event_Killed()` (which includes the string "PROP_CLEARFLAGS"
|
||||
"PhysicsRemoveTouchedList"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x0C\x57\x8B\xF9\x8B\x87\x2A\x2A\x2A\x2A\xD1\xE8\xA8\x01\x0F\x84"
|
||||
"linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x34\x6A\x01\xFF\x75\x2A\xE8\x2A\x2A\x2A\x2A\x83\xC4\x10"
|
||||
}
|
||||
// search string: "sv_friction", look for instruction like this: "mov some_register, offset sv_friction_cvar"
|
||||
// xref sv_friction_cvar, look for the place that it gets called and has this:
|
||||
// *(float*)(a1[1] + some_offset) * (float(__thiscall)(void*))(*(uintptr_t*)sv_friction + GetFloatIndex*sizeof(void*))(sv_friction)
|
||||
// make a signature for some_offset
|
||||
// if it's unclear: https://youtu.be/xiNQ00X4R_I
|
||||
// On Ghidra + Windows CSGO, the references are sometimes missing.
|
||||
// You can find a variable/memory-location holding -25.0 with a memory search.
|
||||
// This variable is referenced in the same function as where you can find this signature.
|
||||
"CBasePlayer->m_surfaceFriction"
|
||||
{
|
||||
"windows" "\xF3\x0F\x10\x80\x2A\x2A\x2A\x2A\xF3\x0F\x59\x45\x2A\xF3\x0F\x11\x45"
|
||||
"linux" "\xF3\x0F\x10\xB8\x2A\x2A\x2A\x2A\xA1"
|
||||
}
|
||||
// search "sv_maxusrcmdprocessticks_warning at server" to find CPlayerMove::RunCommand
|
||||
// then sig the the `mov REG1,dword ptr [REG2 + OFFSET_TO_BUTTON_DISABLED_HERE]`
|
||||
// looks like these in decompiled form:
|
||||
// (windows) `param_3[0xc] = param_3[0xc] & ~param_2[0x32b];`
|
||||
// (linux) `*(uint *)(param_3 + 0x30) = uVar12 & ~param_2[0x331];`
|
||||
"CBasePlayer->m_afButtonDisabled"
|
||||
{
|
||||
"windows" "\x8B\x86\x2A\x2A\x2A\x2A\xF7\xD0\x21\x47"
|
||||
"linux" "\x8b\x93\x2A\x2A\x2A\x2A\xF7\xD2\x21\xd0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"cstrike"
|
||||
{
|
||||
"Addresses"
|
||||
{
|
||||
}
|
||||
|
||||
"Offsets"
|
||||
{
|
||||
// https://asherkin.github.io/vtable/
|
||||
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
|
||||
// search string: "func_pushable" and you can find CBaseTrigger::PassesTriggerFilters / CBaseVPhysicsTrigger::PassesTriggerFilters. Follow references to these functions to find the vtable and then calculate the offset...
|
||||
"CBaseTrigger::PassesTriggerFilters"
|
||||
{
|
||||
"windows" "203"
|
||||
"windows64" "203"
|
||||
"linux" "204"
|
||||
"linux64" "204"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
|
||||
// search string: "start %f %f %f" and then check the function call offsets above it and convert them to vtable offsets (divide by 4 most likely or whatever)
|
||||
"CCSPlayer::GetPlayerMaxSpeed"
|
||||
{
|
||||
"windows" "438"
|
||||
"linux" "439"
|
||||
"mac" "439"
|
||||
"windows" "445"
|
||||
"windows64" "445"
|
||||
"linux" "446"
|
||||
"linux64" "446"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/
|
||||
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
|
||||
// search string: "Invalid counterterrorist spawnpoint" and then look for the first function call in each iteration of the loop
|
||||
"CGameRules::IsSpawnPointValid"
|
||||
{
|
||||
"windows" "76"
|
||||
"windows64" "77" // yes, same as linux64 (according to vtable site)
|
||||
"linux" "77"
|
||||
"mac" "77"
|
||||
"linux64" "77"
|
||||
}
|
||||
// can be found inside BotAddCommand
|
||||
"WEAPONTYPE_UNKNOWN"
|
||||
{
|
||||
"windows" "9"
|
||||
"linux" "9"
|
||||
"mac" "9"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/
|
||||
// https://asherkin.github.io/vtable/ (you can drop a .so from your srcds into this)
|
||||
// search string: "water" to find CBasePlayer::UpdateStepSound. At the bottom there's a vtable call to ::PlayStepSound. Grab that, divide by 4, subtract 1. Bam, UpdateStepSound...
|
||||
"CBasePlayer::UpdateStepSound"
|
||||
{
|
||||
"windows" "358"
|
||||
"linux" "359"
|
||||
"windows" "364"
|
||||
"windows64" "364"
|
||||
"linux" "365"
|
||||
"linux64" "365"
|
||||
}
|
||||
// find in CCSGameMovement::CheckForLadders which references CCSPlayer::CanGrabLadder
|
||||
//
|
||||
// Find CCSPlayer::CanGrabLadder by searching for 4096.0f, then find the function (CheckForLadders) that references it...
|
||||
// CanGrabLadder might look like this on Windows (or just use symbols on Linux)
|
||||
// undefined4 __thiscall CCSPlayer::CanGrabLadder(int param_1_00,float *param_1,float *param_2)
|
||||
// {
|
||||
// float10 extraout_ST0;
|
||||
// float fVar1;
|
||||
// float fVar2;
|
||||
//
|
||||
// (*(code *)**(undefined4 **)(param_1_00 + 0x1790))();
|
||||
// if ((float10)0 < (float10)*(float *)(param_1_00 + 0x1798) - extraout_ST0) {
|
||||
// fVar1 = *param_1 - *(float *)(param_1_00 + 0x17a8);
|
||||
// fVar2 = param_1[1] - *(float *)(param_1_00 + 0x17ac);
|
||||
// if (fVar2 * fVar2 + fVar1 * fVar1 < 4096.0) {
|
||||
// return 0;
|
||||
// }
|
||||
// if ((((NAN(*(float *)(param_1_00 + 0x179c)) || NAN(*param_2)) !=
|
||||
// (*(float *)(param_1_00 + 0x179c) == *param_2)) &&
|
||||
// ((NAN(*(float *)(param_1_00 + 0x17a0)) || NAN(param_2[1])) !=
|
||||
// (*(float *)(param_1_00 + 0x17a0) == param_2[1]))) &&
|
||||
// ((NAN(*(float *)(param_1_00 + 0x17a4)) || NAN(param_2[2])) !=
|
||||
// (*(float *)(param_1_00 + 0x17a4) == param_2[2]))) {
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
// return 1;
|
||||
// }
|
||||
"CCSPlayer::m_lastStandingPos"
|
||||
{
|
||||
"windows" "6016"
|
||||
"windows64" "6640"
|
||||
"linux" "6036" // +20 wow that's easy!
|
||||
"linux64" "6688" // +48 wow that's easy!
|
||||
}
|
||||
// find CCSPlayer::CanGrabLadder via 4096.0f or symbols on linux...
|
||||
"CCSPlayer::m_ladderSurpressionTimer"
|
||||
{
|
||||
"windows" "6032"
|
||||
"windows64" "6668"
|
||||
"linux" "6052" // +20 wow that's easy!
|
||||
"linux64" "6716" // +48 wow that's easy!
|
||||
}
|
||||
// find CCSPlayer::CanGrabLadder via 4096.0f or symbols on linux...
|
||||
"CCSPlayer::m_lastLadderNormal"
|
||||
{
|
||||
"windows" "6044"
|
||||
"windows64" "6672"
|
||||
"linux" "6064" // +20 wow that's easy!
|
||||
"linux64" "6720" // +48 wow that's easy!
|
||||
}
|
||||
// find CCSPlayer::CanGrabLadder via 4096.0f or symbols on linux...
|
||||
"CCSPlayer::m_lastLadderPos"
|
||||
{
|
||||
"windows" "6056"
|
||||
"windows64" "6684"
|
||||
"linux" "6076" // +20 wow that's easy!
|
||||
"linux64" "6732" // +48 wow that's easy!
|
||||
}
|
||||
// TODO
|
||||
"GetClusterForOrigin"
|
||||
{
|
||||
"windows" "11"
|
||||
"linux" "11"
|
||||
}
|
||||
// TODO
|
||||
"GetArea"
|
||||
{
|
||||
"windows" "64"
|
||||
"linux" "64"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
{
|
||||
// search string: "ReloadEffect" to find CWeaponCSBase::SendReloadEvents and then DoAnimationEvent is probably the second to last function called there.
|
||||
// search string: "ReloadEffect" to find CWeaponCSBase::SendReloadEvents and then CCSPlayer::DoAnimationEvent is probably the second to last function called there.
|
||||
"Player::DoAnimationEvent"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x10\x89\x4D\xFC\x83\x7D\x08\x02"
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x0C\x89\x4D\x2A\x83\x7D\x2A\x02"
|
||||
"windows64" "\x44\x89\x44\x24\x2A\x89\x54\x24\x2A\x48\x89\x4C\x24\x2A\x48\x83\xEC\x38\x83\x7C\x24\x2A\x02"
|
||||
"linux" "@_ZN9CCSPlayer16DoAnimationEventE17PlayerAnimEvent_ti"
|
||||
"linux64" "@_ZN9CCSPlayer16DoAnimationEventE17PlayerAnimEvent_ti"
|
||||
}
|
||||
// search string: "-nobots"
|
||||
// search string: "-nobots" (and then look for the function that also references "fill" and "match" (or just the function with 0 or 1 parameters...))
|
||||
"BotManager::MaintainBotQuota"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x14\xFF\x15"
|
||||
"windows64" "\x48\x83\xEC\x78\xFF\x15"
|
||||
"linux" "@_ZN13CCSBotManager16MaintainBotQuotaEv"
|
||||
"linux64" "@_ZN13CCSBotManager16MaintainBotQuotaEv"
|
||||
}
|
||||
// search string: "Error - no profile for '%s' exists."
|
||||
"CCSBotManager::BotAddCommand"
|
||||
// search string: "Server is hibernating" to find SetHibernating and then go to its references
|
||||
// NOTE 2025-02-19: Function has been inlined on Windows into SV_Think...
|
||||
"CGameServer::UpdateHibernationState"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x80\x78\x2A\x00\x75\x2A\x83\xB8\x2A\x2A\x2A\x2A\x00"
|
||||
"linux" "@_ZN13CCSBotManager13BotAddCommandEibPKc12CSWeaponType17BotDifficultyType"
|
||||
"library" "engine"
|
||||
//"windows" ""
|
||||
"windows64" "\x48\x89\x5C\x24\x2A\x56\x48\x83\xEC\x40\x8B\x05"
|
||||
"linux" "@_ZN11CGameServer22UpdateHibernationStateEv.part.0"
|
||||
"linux64" "@_ZN11CGameServer14SetHibernatingEb"
|
||||
}
|
||||
// search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher.
|
||||
// Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher.
|
||||
// (should be the function with one argument (this ptr))
|
||||
"PhysicsCheckForEntityUntouch"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86"
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x57\x8B\xF9\x8B\x87"
|
||||
"windows64" "\x40\x57\x48\x83\xEC\x20\x8B\x81"
|
||||
"linux" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv"
|
||||
"linux64" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv"
|
||||
}
|
||||
// search string: "Could not add bot to the game: Team is full"
|
||||
// search string: "Could not add bot to the game: Team is full" to find CCSBotManager::BotAddCommand and then follow the if-statement up to find the function call that was full (because TeamFull())
|
||||
// protip: on csgo we just use mp_randomspawn instead.
|
||||
"CCSGameRules::TeamFull"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x8B\x45\x2A\x83\xE8\x02"
|
||||
"windows64" "\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x20\x8B\xFA\x48\x8B\xD9\xE8\x2A\x2A\x2A\x2A\x83\xEF\x02"
|
||||
"linux" "@_ZN12CCSGameRules8TeamFullEi"
|
||||
"linux64" "@_ZN12CCSGameRules8TeamFullEi"
|
||||
}
|
||||
// search string: "remove 0x%p: %s-%s (%d-%d) [%d in play, %d max]\n".
|
||||
// function with one argument is PhysicsRemoveTouchedList
|
||||
"PhysicsRemoveTouchedList"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x8B\x5D\x2A\x8B\x83"
|
||||
"windows64" "\x40\x55\x56\x48\x83\xEC\x58"
|
||||
"linux" "@_ZN11CBaseEntity24PhysicsRemoveTouchedListEPS_"
|
||||
"linux64" "@_ZN11CBaseEntity24PhysicsRemoveTouchedListEPS_"
|
||||
}
|
||||
// look for CGameMovement::CategorizePosition by searching for 140.0f
|
||||
// and you will see something something `*(_DWORD*)(a1[1] + some_offset) = 0x3F800000` right at the top
|
||||
// make a signature at "mov dword ptr[eax+some_offset], 3F800000h"
|
||||
"CBasePlayer->m_surfaceFriction"
|
||||
{
|
||||
"windows" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x8B\x07"
|
||||
"windows64" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x48\x8B\x01"
|
||||
"linux" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x8B\x03"
|
||||
"linux64" "\xC7\x80\x2A\x2A\x2A\x2A\x00\x00\x80\x3F\x48\x8B\x07"
|
||||
}
|
||||
// search "sv_maxusrcmdprocessticks_warning at server" to find CPlayerMove::RunCommand
|
||||
// then sig the the `mov REG1,dword ptr [REG2 + OFFSET_TO_BUTTON_DISABLED_HERE]`
|
||||
"CBasePlayer->m_afButtonDisabled"
|
||||
{
|
||||
"windows" "\x8B\x87\x2A\x2A\x2A\x2A\xF7\xD0\x23\xC1"
|
||||
"windows64" "\x8B\x87\x2A\x2A\x2A\x2A\xF7\xD0"
|
||||
"linux" "\x8B\x93\x2A\x2A\x2A\x2A\xF7\xD2"
|
||||
"linux64" "\x8B\x83\x2A\x2A\x2A\x2A\xF7\xD0\x21\xD0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,23 +372,36 @@
|
||||
{
|
||||
"Offsets"
|
||||
{
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CBaseTrigger::PassesTriggerFilters"
|
||||
{
|
||||
"windows" "207"
|
||||
"linux" "208"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CGameRules::IsSpawnPointValid"
|
||||
{
|
||||
"windows" "76"
|
||||
"linux" "77"
|
||||
"mac" "77"
|
||||
}
|
||||
// https://asherkin.github.io/vtable/
|
||||
"CBasePlayer::UpdateStepSound"
|
||||
{
|
||||
"windows" "362"
|
||||
"linux" "363"
|
||||
"windows" "368"
|
||||
"linux" "369"
|
||||
}
|
||||
}
|
||||
|
||||
"Signatures"
|
||||
{
|
||||
// search string: "BumperCar.Jump" to find CTFGameMovement::CheckJumpButton.
|
||||
// Then the call to PreventBunnyJumping is right above the string reference somewhere...
|
||||
// Update 2024-04-18: This fucking bitch got inlined on Windows so this signature is now to the first jump instruction of it to gtfo of doing the velocity stuff. https://i.imgur.com/LDq6Ubo.png
|
||||
"CTFGameMovement::PreventBunnyJumping"
|
||||
{
|
||||
"windows" "\x75\x2A\x8B\x47\x2A\x8D\x77\x2A\x0F\x57\xC0"
|
||||
"linux" "@_ZN15CTFGameMovement19PreventBunnyJumpingEv"
|
||||
}
|
||||
// search string: "Usage: setang_exact pitch yaw" to find setang_exact's handler. Then the last function call in the handler is DoAnimationEvent.
|
||||
"Player::DoAnimationEvent"
|
||||
{
|
||||
@ -198,28 +411,29 @@
|
||||
// search string: "match"
|
||||
"BotManager::MaintainBotQuota"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x81\xEC\x14\x01\x00\x00\xA1"
|
||||
"windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x81\xEC\x10\x01\x00\x00\x83\xB8\x2A\x2A\x2A\x2A\x00"
|
||||
"linux" "@_ZN13CTFBotManager16MaintainBotQuotaEv"
|
||||
}
|
||||
// search string: "CreatePlayerBot: Unable to create bot"
|
||||
"NextBotCreatePlayerBot<CTFBot>"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x56\x57\x68\x2A\x2A\x2A\x2A\xE8"
|
||||
"linux" "@_Z22NextBotCreatePlayerBotI6CTFBotEPT_PKcb"
|
||||
}
|
||||
// search string: "remove 0x%p: %s-%s" to find PhysicsRemoveToucher.
|
||||
// Find PhysicsCheckForEntityUntouch by checking the functions that call PhysicsRemoveToucher.
|
||||
"PhysicsCheckForEntityUntouch"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86\x2A\x2A\x2A\x2A\xD1\xE8"
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x57\x8B\xF9\x8B\x87\x2A\x2A\x2A\x2A\xD1\xE8"
|
||||
"linux" "@_ZN11CBaseEntity28PhysicsCheckForEntityUntouchEv"
|
||||
}
|
||||
// search string: "scoreboard_minigame"
|
||||
"CTFGameRules::CalcPlayerScore"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x56\x8B\x75\x2A\x85\xF6\x75\x2A\x33\xC0\x5E\x5D\xC3\x8B\x56"
|
||||
"windows" "\x55\x8B\xEC\x57\x8B\x7D\x2A\x85\xFF\x75\x2A\x33\xC0\x5F\x5D\xC3\x8B\x57"
|
||||
"linux" "@_ZN12CTFGameRules15CalcPlayerScoreEP12RoundStats_tP9CTFPlayer"
|
||||
}
|
||||
// search string: "remove 0x%p: %s-%s (%d-%d) [%d in play, %d max]\n".
|
||||
// function with one argument is PhysicsRemoveTouchedList
|
||||
"PhysicsRemoveTouchedList"
|
||||
{
|
||||
"windows" "\x55\x8B\xEC\x83\xEC\x08\x53\x8B\x5D\x2A\x8B\x83"
|
||||
"linux" "@_ZN11CBaseEntity24PhysicsRemoveTouchedListEPS_"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,9 +270,9 @@ typeset SteamWorksHTTPDataReceived
|
||||
|
||||
typeset SteamWorksHTTPBodyCallback
|
||||
{
|
||||
function void (const char sData[]);
|
||||
function void (const char sData[], any value);
|
||||
function void (const int data[], any value, int datalen);
|
||||
function void (const char[] sData);
|
||||
function void (const char[] sData, any value);
|
||||
function void (const int[] data, any value, int datalen);
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#define _closestpos_included
|
||||
|
||||
methodmap ClosestPos < Handle {
|
||||
public native ClosestPos(ArrayList input, int offset=0);
|
||||
public native ClosestPos(ArrayList input, int offset=0, int startidx=0, int count=2147483647);
|
||||
public native int Find(float pos[3]);
|
||||
};
|
||||
|
||||
|
||||
@ -1,18 +1,43 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019-2020 KiD Fearless
|
||||
Copyright (c) 2021-2022 rtldg
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined _convar_class_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _convar_class_included
|
||||
|
||||
// todo: track previous default values
|
||||
// todo: track previous default values
|
||||
|
||||
static ArrayList _ConvarList;
|
||||
|
||||
enum struct convar_t
|
||||
{
|
||||
char name[255];
|
||||
ConVar cvar;
|
||||
char description[512];
|
||||
char defValue[512];
|
||||
char name[255];
|
||||
|
||||
bool GetMin(float& input)
|
||||
{
|
||||
@ -46,14 +71,19 @@ methodmap Convar < ConVar
|
||||
|
||||
convar_t savedValue;
|
||||
savedValue.cvar = cvar;
|
||||
strcopy(savedValue.name, sizeof(savedValue.name), name);
|
||||
strcopy(savedValue.description, 512, description);
|
||||
strcopy(savedValue.defValue, sizeof(savedValue.defValue), defaultValue);
|
||||
|
||||
|
||||
// Can't set default values :T
|
||||
savedValue.SetMin(hasMin, min);
|
||||
savedValue.SetMax(hasMax, max);
|
||||
|
||||
convar = savedValue;
|
||||
// Have to do it this way instead of `convar = savedValue;` because SM 1.12 is a whiny bitch.
|
||||
convar.name = savedValue.name;
|
||||
convar.cvar = savedValue.cvar;
|
||||
convar.description = savedValue.description;
|
||||
convar.defValue = convar.defValue;
|
||||
|
||||
_ConvarList.PushArray(savedValue);
|
||||
|
||||
@ -78,6 +108,7 @@ methodmap Convar < ConVar
|
||||
return false;
|
||||
}
|
||||
|
||||
_ConvarList.Sort(Sort_Ascending, Sort_String);
|
||||
|
||||
// Check if the file exists.
|
||||
char local[PLATFORM_MAX_PATH];
|
||||
@ -126,20 +157,12 @@ methodmap Convar < ConVar
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// make a copy of our description
|
||||
char descr[512];
|
||||
descr = convar.description;
|
||||
|
||||
// format newlines as comments
|
||||
ReplaceString(descr, 512, "\n", "\n// ");
|
||||
ReplaceString(convar.description, 512, "\n", "\n// ");
|
||||
|
||||
// write the values and bounds to the file if they exist
|
||||
file.WriteLine("// %s", descr);
|
||||
|
||||
// get the convar name and default value to write to file
|
||||
char name[64];
|
||||
convar.cvar.GetName(name, 64);
|
||||
file.WriteLine("// %s", convar.description);
|
||||
|
||||
file.WriteLine("// -");
|
||||
file.WriteLine("// Default: \"%s\"", convar.defValue);
|
||||
@ -152,7 +175,7 @@ methodmap Convar < ConVar
|
||||
{
|
||||
file.WriteLine("// Maximum: \"%02f\"", x);
|
||||
}
|
||||
file.WriteLine("%s \"%s\"\n", name, convar.defValue);
|
||||
file.WriteLine("%s \"%s\"\n", convar.name, convar.defValue);
|
||||
}
|
||||
// end with newline
|
||||
file.WriteLine("");
|
||||
@ -238,14 +261,8 @@ methodmap Convar < ConVar
|
||||
continue;
|
||||
}
|
||||
|
||||
char descr[512];
|
||||
descr = convar.description;
|
||||
|
||||
ReplaceString(descr, 512, "\n", "\n// ");
|
||||
file.WriteLine("// %s", descr);
|
||||
|
||||
char name[64];
|
||||
convar.cvar.GetName(name, 64);
|
||||
ReplaceString(convar.description, 512, "\n", "\n// ");
|
||||
file.WriteLine("// %s", convar.description);
|
||||
|
||||
file.WriteLine("// -");
|
||||
file.WriteLine("// Default: \"%s\"", convar.defValue);
|
||||
@ -257,16 +274,16 @@ methodmap Convar < ConVar
|
||||
{
|
||||
file.WriteLine("// Maximum: \"%02f\"", x);
|
||||
}
|
||||
|
||||
|
||||
// only difference is that now we check for a stored value.
|
||||
char storedValue[512];
|
||||
if(convars.GetString(name, storedValue, 512))
|
||||
if(convars.GetString(convar.name, storedValue, 512))
|
||||
{
|
||||
file.WriteLine("%s \"%s\"\n", name, storedValue);
|
||||
file.WriteLine("%s \"%s\"\n", convar.name, storedValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.WriteLine("%s \"%s\"\n", name, convar.defValue);
|
||||
file.WriteLine("%s \"%s\"\n", convar.name, convar.defValue);
|
||||
}
|
||||
}
|
||||
file.WriteLine("");
|
||||
@ -277,7 +294,7 @@ methodmap Convar < ConVar
|
||||
char pluginName[64];
|
||||
GetPluginFilename(GetMyHandle(), pluginName, 64);
|
||||
LogError("Failed to auto generate config for %s, make sure the directory has write permission.", pluginName);
|
||||
|
||||
|
||||
if(clearWhenDone)
|
||||
{
|
||||
delete _ConvarList;
|
||||
@ -286,7 +303,7 @@ methodmap Convar < ConVar
|
||||
delete convars;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
delete convars;
|
||||
}
|
||||
if(fileExists)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
152
addons/sourcemod/scripting/include/shavit/anti-sv_cheats.sp
Normal file
152
addons/sourcemod/scripting/include/shavit/anti-sv_cheats.sp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Anti-sv_cheats and anti- cheat-command stuff
|
||||
* by: rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// This code annoys everyone but admins would sometimes set sv_cheats 1 and then
|
||||
// forget to toggle it back off when they were done playing around so then people
|
||||
// would join and teleport into the endzone and set dumb times. And now we're here...
|
||||
// Just add some aliases to your autoexec:
|
||||
// alias cheats "sm_rcon shavit_core_disable_sv_cheats 0 ; sm_rcon sv_cheats 1"
|
||||
// alias cheat "sm_rcon shavit_core_disable_sv_cheats 0 ; sm_rcon sv_cheats 1"
|
||||
|
||||
|
||||
Convar gCV_DisableSvCheats = null;
|
||||
|
||||
#if !DEBUG
|
||||
ConVar sv_cheats = null;
|
||||
|
||||
char gS_CheatCommands[][] = {
|
||||
"ent_create",
|
||||
"ent_orient",
|
||||
"ent_pause",
|
||||
"ent_fire",
|
||||
|
||||
"ent_remove",
|
||||
"ent_remove_all",
|
||||
|
||||
"ent_setname",
|
||||
"ent_setpos",
|
||||
|
||||
"ent_teleport",
|
||||
|
||||
"firetarget",
|
||||
|
||||
"setpos",
|
||||
"setpos_exact",
|
||||
"setpos_player",
|
||||
|
||||
// can be used to kill other players
|
||||
"explode",
|
||||
"explodevector",
|
||||
"kill",
|
||||
"killvector",
|
||||
|
||||
"give",
|
||||
};
|
||||
#endif
|
||||
|
||||
void Anti_sv_cheats_cvars()
|
||||
{
|
||||
gCV_DisableSvCheats = new Convar("shavit_core_disable_sv_cheats", "1", "Force sv_cheats to 0.", 0, true, 0.0, true, 1.0);
|
||||
|
||||
#if !DEBUG
|
||||
sv_cheats = FindConVar("sv_cheats");
|
||||
sv_cheats.AddChangeHook(sv_cheats_hook);
|
||||
|
||||
for (int i = 0; i < sizeof(gS_CheatCommands); i++)
|
||||
{
|
||||
AddCommandListener(Command_Cheats, gS_CheatCommands[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Anti_sv_cheats_OnConfigsExecuted()
|
||||
{
|
||||
if (gCV_DisableSvCheats.BoolValue)
|
||||
{
|
||||
#if !DEBUG
|
||||
sv_cheats.SetInt(0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Remove_sv_cheat_Impluses(int client, int &impulse)
|
||||
{
|
||||
#if !DEBUG
|
||||
if (impulse && sv_cheats.BoolValue && !(GetUserFlagBits(client) & ADMFLAG_ROOT))
|
||||
{
|
||||
switch (impulse)
|
||||
{
|
||||
// Likely incomplete list of the most cheaty impulses...
|
||||
// 76 = spawn npc
|
||||
// 81 = something cubemap
|
||||
// 82 = create jeep
|
||||
// 83 = create airboat
|
||||
// 102 = something node
|
||||
// 195 = something node
|
||||
// 196 = something node
|
||||
// 197 = something node
|
||||
// 202 = something bloodsplat
|
||||
// 203 = remove entity
|
||||
case 76, 81, 82, 83, 102, 195, 196, 197, 202, 203:
|
||||
{
|
||||
impulse = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !DEBUG
|
||||
public void sv_cheats_hook(ConVar convar, const char[] oldValue, const char[] newValue)
|
||||
{
|
||||
if (gCV_DisableSvCheats.BoolValue)
|
||||
{
|
||||
sv_cheats.SetInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
public Action Command_Cheats(int client, const char[] command, int args)
|
||||
{
|
||||
if (!sv_cheats.BoolValue || client == 0)
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if (StrContains(command, "kill") != -1 || StrContains(command, "explode") != -1)
|
||||
{
|
||||
bool bVector = StrContains(command, "vector") != -1;
|
||||
bool bKillOther = args > (bVector ? 3 : 0);
|
||||
|
||||
if (!bKillOther)
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(GetUserFlagBits(client) & ADMFLAG_ROOT))
|
||||
{
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* shavit's Timer - area_and_cluster_stages.sp
|
||||
* by: carnifex
|
||||
*
|
||||
* This file is part of shavit's Timer.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// originally sourced from https://github.com/hermansimensen/mapstages
|
||||
|
||||
Address IVEngineServer;
|
||||
Handle gH_GetCluster;
|
||||
Handle gH_GetArea;
|
||||
|
||||
void LoadDHooks_mapstages(GameData gamedata)
|
||||
{
|
||||
StartPrepSDKCall(SDKCall_Static);
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "CreateInterface"))
|
||||
{
|
||||
SetFailState("Failed to get CreateInterface");
|
||||
}
|
||||
|
||||
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
|
||||
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
|
||||
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||
Handle CreateInterface = EndPrepSDKCall();
|
||||
|
||||
if (CreateInterface == null)
|
||||
{
|
||||
SetFailState("Unable to prepare SDKCall for CreateInterface");
|
||||
}
|
||||
|
||||
char interfaceName[64];
|
||||
if (!GameConfGetKeyValue(gamedata, "IVEngineServer", interfaceName, sizeof(interfaceName)))
|
||||
{
|
||||
SetFailState("Failed to get IVEngineServer interface name");
|
||||
}
|
||||
|
||||
IVEngineServer = SDKCall(CreateInterface, interfaceName, 0);
|
||||
|
||||
if (!IVEngineServer)
|
||||
{
|
||||
SetFailState("Failed to get IVEngineServer pointer");
|
||||
}
|
||||
|
||||
StartPrepSDKCall(SDKCall_Raw);
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Virtual, "GetClusterForOrigin"))
|
||||
{
|
||||
SetFailState("Couldn't find GetClusterForOrigin offset");
|
||||
}
|
||||
PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_Plain);
|
||||
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||
gH_GetCluster = EndPrepSDKCall();
|
||||
|
||||
StartPrepSDKCall(SDKCall_Raw);
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Virtual, "GetArea"))
|
||||
{
|
||||
SetFailState("Couldn't find GetArea offset");
|
||||
}
|
||||
PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_Plain);
|
||||
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||
gH_GetArea = EndPrepSDKCall();
|
||||
|
||||
delete CreateInterface;
|
||||
}
|
||||
|
||||
public int GetClusterForOrigin(const float pos[3])
|
||||
{
|
||||
return SDKCall(gH_GetCluster, IVEngineServer, pos);
|
||||
}
|
||||
|
||||
public int GetAreaForOrigin(const float pos[3])
|
||||
{
|
||||
return SDKCall(gH_GetArea, IVEngineServer, pos);
|
||||
}
|
||||
@ -2,7 +2,8 @@
|
||||
* Bunnyhop Statistics API - Include file
|
||||
* by: shavit
|
||||
*
|
||||
* This file is part of Bunnyhop Statistics API.
|
||||
* Originally from Bunnyhop Statistics API (https://github.com/shavitush/bhopstats)
|
||||
* but edited to be part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
@ -16,21 +17,12 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
#if defined _bhopstats_included
|
||||
#if defined _shavit_bhopstats_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _bhopstats_included
|
||||
|
||||
#define BHOPSTATS_VERSION "1.2.0"
|
||||
|
||||
enum CheatType
|
||||
{
|
||||
Cheat_HighPerfects = 0,
|
||||
Cheat_Auto,
|
||||
Cheat_JumpSpam
|
||||
}
|
||||
#define _shavit_bhopstats_included
|
||||
|
||||
/**
|
||||
* Called when the jump key is pressed.
|
||||
@ -40,7 +32,7 @@ enum CheatType
|
||||
* @param perfect Was the jump perfectly timed?
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Bunnyhop_OnJumpPressed(int client, bool onground, bool perfect);
|
||||
forward void Shavit_Bhopstats_OnJumpPressed(int client, bool onground, bool perfect);
|
||||
|
||||
/**
|
||||
* Called when the jump key is released.
|
||||
@ -49,7 +41,7 @@ forward void Bunnyhop_OnJumpPressed(int client, bool onground, bool perfect);
|
||||
* @param onground True if the jump key will do anything for the player when tapped.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Bunnyhop_OnJumpReleased(int client, bool onground);
|
||||
forward void Shavit_Bhopstats_OnJumpReleased(int client, bool onground);
|
||||
|
||||
/**
|
||||
* Called when the player touches the ground.
|
||||
@ -57,7 +49,7 @@ forward void Bunnyhop_OnJumpReleased(int client, bool onground);
|
||||
* @param client Client index.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Bunnyhop_OnTouchGround(int client);
|
||||
forward void Shavit_Bhopstats_OnTouchGround(int client);
|
||||
|
||||
/**
|
||||
* Called when the player leaves the ground, by either jumping or falling from somewhere.
|
||||
@ -70,7 +62,7 @@ forward void Bunnyhop_OnTouchGround(int client);
|
||||
* @param ladder Did the client leave the ground by leaving a ladder, aka ladderstrafing?
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Bunnyhop_OnLeaveGround(int client, bool jumped, bool ladder);
|
||||
forward void Shavit_Bhopstats_OnLeaveGround(int client, bool jumped, bool ladder);
|
||||
|
||||
/**
|
||||
* Retrieves the amount of separate +jump inputs since the player left the ground.
|
||||
@ -78,7 +70,7 @@ forward void Bunnyhop_OnLeaveGround(int client, bool jumped, bool ladder);
|
||||
* @param client Client index.
|
||||
* @return Amount of +jump inputs since the left the ground, or 0 if the player is on ground.
|
||||
*/
|
||||
native int Bunnyhop_GetScrollCount(int client);
|
||||
native int Shavit_Bhopstats_GetScrollCount(int client);
|
||||
|
||||
/**
|
||||
* Checks if the player is on ground, or if the jump key will function as in actually triggering a jump or altering velocity.
|
||||
@ -87,7 +79,7 @@ native int Bunnyhop_GetScrollCount(int client);
|
||||
* @param client Client index.
|
||||
* @return Boolean value of 'is the player on ground?'
|
||||
*/
|
||||
native bool Bunnyhop_IsOnGround(int client);
|
||||
native bool Shavit_Bhopstats_IsOnGround(int client);
|
||||
|
||||
/**
|
||||
* Checks if the player is holding his jump key.
|
||||
@ -95,16 +87,16 @@ native bool Bunnyhop_IsOnGround(int client);
|
||||
* @param client Client index.
|
||||
* @return Boolean value of 'is the player holding the jump key?''
|
||||
*/
|
||||
native bool Bunnyhop_IsHoldingJump(int client);
|
||||
native bool Shavit_Bhopstats_IsHoldingJump(int client);
|
||||
|
||||
/**
|
||||
* Gets a percentage of perfectly timed bunnyhops.
|
||||
* Resets at player connection or the Bunnyhop_ResetPerfectJumps native for it is called.
|
||||
* Resets at player connection or the Shavit_Bhopstats_ResetPerfectJumps native for it is called.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Perfect jump percentage. Results are from 0.0 to 100.0.
|
||||
*/
|
||||
native float Bunnyhop_GetPerfectJumps(int client);
|
||||
native float Shavit_Bhopstats_GetPerfectJumps(int client);
|
||||
|
||||
/**
|
||||
* Resets the perfect jumps percentage of a player back to 0.0.
|
||||
@ -112,13 +104,13 @@ native float Bunnyhop_GetPerfectJumps(int client);
|
||||
* @param client Client index.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Bunnyhop_ResetPerfectJumps(int client);
|
||||
native void Shavit_Bhopstats_ResetPerfectJumps(int client);
|
||||
|
||||
methodmap BunnyhopStats __nullable__
|
||||
methodmap Shavit_BunnyhopStats __nullable__
|
||||
{
|
||||
public BunnyhopStats(int client)
|
||||
public Shavit_BunnyhopStats(int client)
|
||||
{
|
||||
return view_as<BunnyhopStats>(client);
|
||||
return view_as<Shavit_BunnyhopStats>(client);
|
||||
}
|
||||
|
||||
property int index
|
||||
@ -133,83 +125,72 @@ methodmap BunnyhopStats __nullable__
|
||||
{
|
||||
public get()
|
||||
{
|
||||
return Bunnyhop_GetScrollCount(this.index);
|
||||
return Shavit_Bhopstats_GetScrollCount(this.index);
|
||||
}
|
||||
}
|
||||
|
||||
property bool OnGround
|
||||
{
|
||||
{
|
||||
public get()
|
||||
{
|
||||
return Bunnyhop_IsOnGround(this.index);
|
||||
return Shavit_Bhopstats_IsOnGround(this.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property bool HoldingJump
|
||||
{
|
||||
{
|
||||
public get()
|
||||
{
|
||||
return Bunnyhop_IsHoldingJump(this.index);
|
||||
return Shavit_Bhopstats_IsHoldingJump(this.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property float PerfectJumps
|
||||
{
|
||||
{
|
||||
public get()
|
||||
{
|
||||
return Bunnyhop_GetPerfectJumps(this.index);
|
||||
return Shavit_Bhopstats_GetPerfectJumps(this.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetPrefects()
|
||||
{
|
||||
Bunnyhop_ResetPerfectJumps(this.index);
|
||||
Shavit_Bhopstats_ResetPerfectJumps(this.index);
|
||||
}
|
||||
|
||||
public static int GetScrollCount(int client)
|
||||
{
|
||||
return Bunnyhop_GetScrollCount(client);
|
||||
}
|
||||
{
|
||||
return Shavit_Bhopstats_GetScrollCount(client);
|
||||
}
|
||||
|
||||
public static bool IsOnGround(int client)
|
||||
{
|
||||
return Bunnyhop_IsOnGround(client);
|
||||
}
|
||||
{
|
||||
return Shavit_Bhopstats_IsOnGround(client);
|
||||
}
|
||||
|
||||
public static bool IsHoldingJump(int client)
|
||||
{
|
||||
return Bunnyhop_IsHoldingJump(client);
|
||||
}
|
||||
{
|
||||
return Shavit_Bhopstats_IsHoldingJump(client);
|
||||
}
|
||||
|
||||
public static float GetPerfectJumps(int client)
|
||||
{
|
||||
return Bunnyhop_GetPerfectJumps(client);
|
||||
}
|
||||
{
|
||||
return Shavit_Bhopstats_GetPerfectJumps(client);
|
||||
}
|
||||
|
||||
public static float ResetPrefectJumps(int client)
|
||||
{
|
||||
return Bunnyhop_ResetPerfectJumps(client);
|
||||
}
|
||||
public static void ResetPrefectJumps(int client)
|
||||
{
|
||||
Shavit_Bhopstats_ResetPerfectJumps(client);
|
||||
}
|
||||
}
|
||||
|
||||
public SharedPlugin __pl_bhopstats =
|
||||
{
|
||||
name = "bhopstats",
|
||||
file = "bhopstats.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_bhopstats_SetNTVOptional()
|
||||
public void __pl_shavit_bhopstats_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Bunnyhop_GetScrollCount");
|
||||
MarkNativeAsOptional("Bunnyhop_IsOnGround");
|
||||
MarkNativeAsOptional("Bunnyhop_IsHoldingJump");
|
||||
MarkNativeAsOptional("Bunnyhop_GetPerfectJumps");
|
||||
MarkNativeAsOptional("Bunnyhop_ResetPerfectJumps");
|
||||
MarkNativeAsOptional("Shavit_Bhopstats_GetScrollCount");
|
||||
MarkNativeAsOptional("Shavit_Bhopstats_IsOnGround");
|
||||
MarkNativeAsOptional("Shavit_Bhopstats_IsHoldingJump");
|
||||
MarkNativeAsOptional("Shavit_Bhopstats_GetPerfectJumps");
|
||||
MarkNativeAsOptional("Shavit_Bhopstats_ResetPerfectJumps");
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Bunnyhop Statistics API - Plugin
|
||||
* by: shavit
|
||||
*
|
||||
* Originally from Bunnyhop Statistics API (https://github.com/shavitush/bhopstats)
|
||||
* but edited to be part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma newdecls required
|
||||
#pragma semicolon 1
|
||||
|
||||
bool gB_OnGround[MAXPLAYERS+1];
|
||||
bool gB_PlayerTouchingGround[MAXPLAYERS+1];
|
||||
|
||||
int gI_Scrolls[MAXPLAYERS+1];
|
||||
int gI_Buttons[MAXPLAYERS+1];
|
||||
bool gB_JumpHeld[MAXPLAYERS+1];
|
||||
|
||||
int gI_Jumps[MAXPLAYERS+1];
|
||||
int gI_PerfectJumps[MAXPLAYERS+1];
|
||||
|
||||
Handle gH_Forwards_OnJumpPressed = null;
|
||||
Handle gH_Forwards_OnJumpReleased = null;
|
||||
Handle gH_Forwards_OnTouchGround = null;
|
||||
Handle gH_Forwards_OnLeaveGround = null;
|
||||
|
||||
public void Bhopstats_CreateNatives()
|
||||
{
|
||||
CreateNative("Shavit_Bhopstats_GetScrollCount", Native_GetScrollCount);
|
||||
CreateNative("Shavit_Bhopstats_IsOnGround", Native_IsOnGround);
|
||||
CreateNative("Shavit_Bhopstats_IsHoldingJump", Native_IsHoldingJump);
|
||||
CreateNative("Shavit_Bhopstats_GetPerfectJumps", Native_Bhopstats_GetPerfectJumps);
|
||||
CreateNative("Shavit_Bhopstats_ResetPerfectJumps", Native_ResetPerfectJumps);
|
||||
}
|
||||
|
||||
public void Bhopstats_CreateForwards()
|
||||
{
|
||||
gH_Forwards_OnJumpPressed = CreateGlobalForward("Shavit_Bhopstats_OnJumpPressed", ET_Event, Param_Cell, Param_Cell);
|
||||
gH_Forwards_OnJumpReleased = CreateGlobalForward("Shavit_Bhopstats_OnJumpReleased", ET_Event, Param_Cell, Param_Cell);
|
||||
gH_Forwards_OnTouchGround = CreateGlobalForward("Shavit_Bhopstats_OnTouchGround", ET_Event, Param_Cell);
|
||||
gH_Forwards_OnLeaveGround = CreateGlobalForward("Shavit_Bhopstats_OnLeaveGround", ET_Event, Param_Cell, Param_Cell, Param_Cell);
|
||||
}
|
||||
|
||||
public void Bhopstats_OnClientPutInServer(int client)
|
||||
{
|
||||
gB_OnGround[client] = false;
|
||||
gB_PlayerTouchingGround[client] = false;
|
||||
|
||||
gI_Scrolls[client] = 0;
|
||||
gI_Buttons[client] = 0;
|
||||
gB_JumpHeld[client] = false;
|
||||
|
||||
gI_Jumps[client] = 0;
|
||||
gI_PerfectJumps[client] = 0;
|
||||
|
||||
SDKHook(client, SDKHook_PostThinkPost, Bhopstats_PostThinkPost);
|
||||
}
|
||||
|
||||
public int Native_GetScrollCount(Handle handler, int numParams)
|
||||
{
|
||||
return gI_Scrolls[GetNativeCell(1)];
|
||||
}
|
||||
|
||||
public int Native_IsOnGround(Handle handler, int numParams)
|
||||
{
|
||||
return view_as<int>(gB_OnGround[GetNativeCell(1)]);
|
||||
}
|
||||
|
||||
public int Native_IsHoldingJump(Handle handler, int numParams)
|
||||
{
|
||||
return view_as<int>(gI_Buttons[GetNativeCell(1)] & IN_JUMP);
|
||||
}
|
||||
|
||||
public int Native_Bhopstats_GetPerfectJumps(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
return view_as<int>((float(gI_PerfectJumps[client]) / gI_Jumps[client]) * 100.0);
|
||||
}
|
||||
|
||||
public int Native_ResetPerfectJumps(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
gI_Jumps[client] = 0;
|
||||
gI_PerfectJumps[client] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Bhopstats_PostThinkPost(int client)
|
||||
{
|
||||
if(!IsPlayerAlive(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int buttons = GetClientButtons(client);
|
||||
bool bOldOnGround = gB_OnGround[client];
|
||||
|
||||
int iGroundEntity;
|
||||
|
||||
if (gB_ReplayPlayback && IsFakeClient(client))
|
||||
{
|
||||
iGroundEntity = (Shavit_GetReplayEntityFlags(client) & FL_ONGROUND) ? 0 : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iGroundEntity = GetEntPropEnt(client, Prop_Send, "m_hGroundEntity");
|
||||
}
|
||||
|
||||
bool bOnLadder = (GetEntityMoveType(client) == MOVETYPE_LADDER);
|
||||
gB_OnGround[client] = (iGroundEntity != -1 || GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 2 || bOnLadder);
|
||||
|
||||
gB_JumpHeld[client] = (buttons & IN_JUMP && !(gI_Buttons[client] & IN_JUMP));
|
||||
|
||||
if(gB_PlayerTouchingGround[client] && gB_OnGround[client])
|
||||
{
|
||||
Call_StartForward(gH_Forwards_OnTouchGround);
|
||||
Call_PushCell(client);
|
||||
Call_Finish();
|
||||
|
||||
gB_PlayerTouchingGround[client] = false;
|
||||
}
|
||||
else if(!gB_PlayerTouchingGround[client] && ((gB_JumpHeld[client] && iGroundEntity != -1) || iGroundEntity == -1 || bOnLadder))
|
||||
{
|
||||
Call_StartForward(gH_Forwards_OnLeaveGround);
|
||||
Call_PushCell(client);
|
||||
Call_PushCell(gB_JumpHeld[client]);
|
||||
Call_PushCell(bOnLadder);
|
||||
Call_Finish();
|
||||
|
||||
gB_PlayerTouchingGround[client] = true;
|
||||
gI_Scrolls[client] = 0;
|
||||
}
|
||||
|
||||
if(gB_JumpHeld[client])
|
||||
{
|
||||
gI_Scrolls[client]++;
|
||||
|
||||
Call_StartForward(gH_Forwards_OnJumpPressed);
|
||||
Call_PushCell(client);
|
||||
Call_PushCell(gB_OnGround[client]);
|
||||
Call_Finish();
|
||||
|
||||
if(gB_OnGround[client])
|
||||
{
|
||||
gI_Jumps[client]++;
|
||||
|
||||
if(!bOldOnGround)
|
||||
{
|
||||
gI_PerfectJumps[client]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(gI_Buttons[client] & IN_JUMP && !(buttons & IN_JUMP))
|
||||
{
|
||||
Call_StartForward(gH_Forwards_OnJumpReleased);
|
||||
Call_PushCell(client);
|
||||
Call_PushCell(gB_OnGround[client]);
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
gI_Buttons[client] = buttons;
|
||||
}
|
||||
84
addons/sourcemod/scripting/include/shavit/chat-colors.inc
Normal file
84
addons/sourcemod/scripting/include/shavit/chat-colors.inc
Normal file
@ -0,0 +1,84 @@
|
||||
#if defined _shavit_chat_colors_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_chat_colors_included
|
||||
|
||||
char gS_GlobalColorNames[][] =
|
||||
{
|
||||
"{default}",
|
||||
"{def}",
|
||||
"{team}",
|
||||
"{green}"
|
||||
};
|
||||
|
||||
char gS_GlobalColors[][] =
|
||||
{
|
||||
"\x01",
|
||||
"\x01",
|
||||
"\x03",
|
||||
"\x04"
|
||||
};
|
||||
|
||||
char gS_CSGOColorNames[][] =
|
||||
{
|
||||
"{blue}",
|
||||
"{bluegrey}",
|
||||
"{darkblue}",
|
||||
"{darkred}",
|
||||
"{gold}",
|
||||
"{grey}",
|
||||
"{grey2}",
|
||||
"{lightgreen}",
|
||||
"{lightred}",
|
||||
"{lime}",
|
||||
"{orchid}",
|
||||
"{yellow}",
|
||||
"{palered}"
|
||||
};
|
||||
|
||||
char gS_CSGOColors[][] =
|
||||
{
|
||||
"\x0B",
|
||||
"\x0A",
|
||||
"\x0C",
|
||||
"\x02",
|
||||
"\x10",
|
||||
"\x08",
|
||||
"\x0D",
|
||||
"\x05",
|
||||
"\x0F",
|
||||
"\x06",
|
||||
"\x0E",
|
||||
"\x09",
|
||||
"\x07"
|
||||
};
|
||||
|
||||
|
||||
stock void FormatColors(char[] buffer, int size, bool colors, bool escape, bool csgo, bool funky_chars=true)
|
||||
{
|
||||
if(colors)
|
||||
{
|
||||
for(int i = 0; i < sizeof(gS_GlobalColorNames); i++)
|
||||
{
|
||||
ReplaceString(buffer, size, gS_GlobalColorNames[i], gS_GlobalColors[i]);
|
||||
}
|
||||
|
||||
if(csgo)
|
||||
{
|
||||
for(int i = 0; i < sizeof(gS_CSGOColorNames); i++)
|
||||
{
|
||||
ReplaceString(buffer, size, gS_CSGOColorNames[i], gS_CSGOColors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (funky_chars) ReplaceString(buffer, size, "^", "\x07");
|
||||
ReplaceString(buffer, size, "{RGB}", "\x07");
|
||||
if (funky_chars) ReplaceString(buffer, size, "&", "\x08");
|
||||
ReplaceString(buffer, size, "{RGBA}", "\x08");
|
||||
}
|
||||
|
||||
if(escape)
|
||||
{
|
||||
ReplaceString(buffer, size, "%%", "");
|
||||
}
|
||||
}
|
||||
54
addons/sourcemod/scripting/include/shavit/chat.inc
Normal file
54
addons/sourcemod/scripting/include/shavit/chat.inc
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* shavit's Timer - chat.inc file
|
||||
* by: rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_chat_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_chat_included
|
||||
|
||||
/*
|
||||
* Retrieves the player's chatrank trimmed and without colors.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param buf Buffer to put the put the chatrank into
|
||||
* @param buflen Size of buf
|
||||
* @param includename Include {name} in result.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetPlainChatrank(int client, char[] buf, int buflen, bool includename=false);
|
||||
|
||||
public SharedPlugin __pl_shavit_chat =
|
||||
{
|
||||
name = "shavit-chat",
|
||||
file = "shavit-chat.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_chat_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetPlainChatrank");
|
||||
}
|
||||
#endif
|
||||
344
addons/sourcemod/scripting/include/shavit/checkpoints.inc
Normal file
344
addons/sourcemod/scripting/include/shavit/checkpoints.inc
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
* shavit's Timer - Checkpoints
|
||||
* by: shavit, kidfearless, Nairda, GAMMA CASE, rtldg, sh4hrazad, Ciallo-Ani, olivia
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_checkpoints_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_checkpoints_included
|
||||
|
||||
enum struct cp_cache_t
|
||||
{
|
||||
float fPosition[3];
|
||||
float fAngles[3];
|
||||
float fVelocity[3];
|
||||
MoveType iMoveType;
|
||||
float fGravity;
|
||||
float fSpeed;
|
||||
float fStamina;
|
||||
bool bDucked;
|
||||
bool bDucking;
|
||||
float fDucktime; // m_flDuckAmount in csgo
|
||||
float fDuckSpeed; // m_flDuckSpeed in csgo; doesn't exist in css
|
||||
int iFlags;
|
||||
timer_snapshot_t aSnapshot;
|
||||
char sTargetname[64];
|
||||
char sClassname[64];
|
||||
ArrayList aFrames;
|
||||
int iPreFrames;
|
||||
bool bSegmented;
|
||||
int iGroundEntity;
|
||||
int iSteamID;
|
||||
ArrayList aEvents;
|
||||
ArrayList aOutputWaits;
|
||||
float vecLadderNormal[3];
|
||||
// This handle will be deleted when the checkpoint is deleted, or something like that...
|
||||
// If you want to keep this (which you probably should) then you'd have
|
||||
// to use StringMap.Clone() (owned clone) or CloneHandle() (shared object).
|
||||
StringMap customdata;
|
||||
|
||||
bool m_bHasWalkMovedSinceLastJump; // csgo only
|
||||
float m_ignoreLadderJumpTime; // csgo only
|
||||
|
||||
float m_lastStandingPos[3]; // css only
|
||||
float m_ladderSurpressionTimer[2]; // css only // 0 = duration, 1 = remaining
|
||||
float m_lastLadderNormal[3]; // css only
|
||||
float m_lastLadderPos[3]; // css only
|
||||
|
||||
// used by player_speedmod
|
||||
int m_afButtonDisabled;
|
||||
// used by trigger_playermovement
|
||||
int m_afButtonForced;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player will be teleported with checkpoints.
|
||||
*
|
||||
* @param client Client index that will be teleported to the checkpoint.
|
||||
* @param index Checkpoint that was teleported to.
|
||||
* @param target Target index that owns the checkpoint.
|
||||
* @return Plugin_Continue to allow teleporting, anything else to prevent.
|
||||
*/
|
||||
forward Action Shavit_OnTeleportPre(int client, int index, int target);
|
||||
|
||||
/**
|
||||
* Called when a player has been teleported with checkpoints.
|
||||
*
|
||||
* @param client Client index that has been teleported to the checkpoint.
|
||||
* @param index Checkpoint that was teleported to.
|
||||
* @param target Target index that owns the checkpoint.
|
||||
* @return Unused. Use Shavit_OnTeleportPre if you want to block teleporting.
|
||||
*/
|
||||
forward Action Shavit_OnTeleport(int client, int index, int target);
|
||||
|
||||
/**
|
||||
* Called when a player is saving a checkpoint.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param index Checkpoint that was saved to.
|
||||
* @param overflow Does this checkpoint shift the rest.
|
||||
* @param duplicate Whether the checkpoint to be saved is a duplicate of others
|
||||
* @return Plugin_Continue to allow saving, anything else to prevent.
|
||||
*/
|
||||
forward Action Shavit_OnSavePre(int client, int index, bool overflow, bool duplicate);
|
||||
|
||||
/**
|
||||
* Called when a player has saved a checkpoint.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param index Checkpoint that was saved to.
|
||||
* @param overflow Does this checkpoint shift the rest.
|
||||
* @param duplicate Whether the checkpoint that has been saved is a duplicate of others
|
||||
* @return Unused. Use Shavit_OnSavePre if you want to block checkpoint saving.
|
||||
*/
|
||||
forward Action Shavit_OnSave(int client, int index, bool overflow, bool duplicate);
|
||||
|
||||
/**
|
||||
* Called when a player deletes a checkpoint.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param index Checkpoint that will be deleted.
|
||||
* @param cleared Whether the checkpoint is being deleted due to all the checkpoints being cleared/reset.
|
||||
The return value CANNOT be used to block deletion of these.
|
||||
*
|
||||
* @return Plugin_Continue to continue deletion, anything else to prevent.
|
||||
*/
|
||||
forward Action Shavit_OnDelete(int client, int index, bool cleared);
|
||||
|
||||
/**
|
||||
* Called after the checkpoint menu has been made and before it's sent to the client.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param segmented If the menu was a segmented menu
|
||||
* @param menu Handle to the menu so you can .AddItem().
|
||||
* @return Plugin_Handled or Plugin_Stop to stop the menu.
|
||||
*/
|
||||
forward Action Shavit_OnCheckpointMenuMade(int client, bool segmented, Menu menu);
|
||||
|
||||
/**
|
||||
* Called before a selection is processed in the main checkpoint menu.
|
||||
*
|
||||
* @param client Client index who selects in the menu
|
||||
* @param param2 Second parameter in the callback, usually the item selected.
|
||||
* @param info reference copy of the info string used in the callback
|
||||
* @param maxlength length of the info buffer
|
||||
* @param currentCheckpoint Clients current checkpoint selected
|
||||
* @param maxCPs Max checkpoints the client can use
|
||||
* @param owner Client index who owns the current checkpoint
|
||||
* @return Plugin_Continue to continue the callback. Return Plugin_Stop to prevent the checkpoints menu from reopening.
|
||||
*/
|
||||
forward Action Shavit_OnCheckpointMenuSelect(int client, int param2, char[] info, int maxlength, int currentCheckpoint, int maxCPs, int owner);
|
||||
|
||||
/**
|
||||
* Called when a checkpoint cache is saved.
|
||||
*
|
||||
* @param client The client the checkpoint cache is being saved for.
|
||||
* @param cache The resulting checkpoint cache structure.
|
||||
* @param index The resulting checkpoint index for this checkpoint cache. -1 if the cache is being saved as "persistent data" for rejoins/spectating. 0 if not being saved to checkpoints list.
|
||||
* @param target The target of the checkpoint cache.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnCheckpointCacheSaved(int client, cp_cache_t cache, int index, int target);
|
||||
|
||||
/**
|
||||
* Called when a checkpoint cache is being loaded.
|
||||
*
|
||||
* @param client The client who is loading the checkpoint cache.
|
||||
* @param cache The cache.
|
||||
* @param index The checkpoint index for this cache. -1 if the cache is being loaded from "persistent data" for rejoins/spectating. 0 if the cache is being loaded usually by Shavit_LoadCheckpointCache().
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnCheckpointCacheLoaded(int client, cp_cache_t cache, int index);
|
||||
|
||||
/**
|
||||
* Gets the total number of CPs that a client has saved
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @return Total number of checkpoints
|
||||
*/
|
||||
native int Shavit_GetTotalCheckpoints(int client);
|
||||
|
||||
/**
|
||||
* Gets CP data for a client at specified index
|
||||
*
|
||||
* @param client Client index
|
||||
* @param index Index of CP to get
|
||||
* @param cpcache Buffer to store cp data in sizeof(cp_cache_t)
|
||||
* @param size Size of the cpcache buffer, e.g sizeof(cp_cache_t)
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native bool Shavit_GetCheckpoint(int client, int index, any[] cpcache, int size = sizeof(cp_cache_t));
|
||||
|
||||
/**
|
||||
* Sets checkpoint data at the given index for the given client
|
||||
*
|
||||
* @param client Client index
|
||||
* @param index Index of CP to set, or -1 to push cp as last. 0 to push cp to first without erasing.
|
||||
* @param cpcache Buffer to store cp data in sizeof(cp_cache_t)
|
||||
* @param size Size of the cpcache buffer, e.g sizeof(cp_cache_t)
|
||||
* @param cheapCloneHandle False means we duplicate aFrames, aEvents, and aOutputWaits (ArrayList.Clone). True means we clone the handle (CloneHandle).
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetCheckpoint(int client, int index, any[] cpcache, int size = sizeof(cp_cache_t), bool cheapCloneHandle=true);
|
||||
|
||||
/**
|
||||
* Teleports client to the checkpoint at given target and index
|
||||
*
|
||||
* @param client Client index to be teleported
|
||||
* @param index Index of CP to teleport to
|
||||
* @param suppress Supress checkpoint message
|
||||
* @param target Player index that owns the checkpoint. 0 to use the client variable.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_TeleportToCheckpoint(int client, int index, bool suppress = false, int target=0);
|
||||
|
||||
/**
|
||||
* Clears all saved checkpoints for the specified client
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_ClearCheckpoints(int client);
|
||||
|
||||
/**
|
||||
* Saves a new checkpoint and returns the new checkpoint index
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @return The new current checkpoint
|
||||
*/
|
||||
native int Shavit_SaveCheckpoint(int client);
|
||||
|
||||
/**
|
||||
* Gets the current checkpoint index.
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @return The current checkpoint
|
||||
*/
|
||||
native int Shavit_GetCurrentCheckpoint(int client);
|
||||
|
||||
/**
|
||||
* Sets the current checkpoint index.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param index New index to use
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetCurrentCheckpoint(int client, int index);
|
||||
|
||||
/**
|
||||
* Gets how many times the client has teleported to checkpoints.
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @return The number of times the client has teleported to checkpoints.
|
||||
*/
|
||||
native int Shavit_GetTimesTeleported(int client);
|
||||
|
||||
/**
|
||||
* Sets the number of times the client has teleported to checkpoints.
|
||||
* This is useful to have if you intend to implement a plugin to save "persistent data" between map changes".
|
||||
*
|
||||
* @param client Client index
|
||||
* @param count Teleport count
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetTimesTeleported(int client, int count);
|
||||
|
||||
/**
|
||||
* Checks whether the client has savestate data.
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @return Whether a savestate or rejoin-savestate data exists for the client.
|
||||
*/
|
||||
native bool Shavit_HasSavestate(int client);
|
||||
|
||||
/**
|
||||
* Loads a cp_cache_t on a player. AKA teleports players.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param cache Input cp_cache_t
|
||||
* @param index -1 if you want the cp_cache_t to be loaded as "persistent data". 0 if not. greater-than-zero if you know what you're doing and intentionally want to spoof the cp_cache_t as a checkpoint index for some reason... I recommend looking at shavit-checkpoints.sp to see how "index" and "isPersistentData" are used to see what kind of difference there is.
|
||||
* @param size sizeof(cp_cache_t) to mostly ensure the calling plugin has a matching cp_cache_t.
|
||||
* @param force Forcibly load the cp_cache_t without checking the style access for a player.
|
||||
*
|
||||
* @return Returns whether the checkpoint cache was able to be loaded.
|
||||
*/
|
||||
native bool Shavit_LoadCheckpointCache(int client, any[] cache, int index, int size = sizeof(cp_cache_t), bool force = false);
|
||||
|
||||
/**
|
||||
* Saves a cp_cache_t from a player.
|
||||
*
|
||||
* @param saver The client saving the checkpoint.
|
||||
* @param target The target the checkpoint cache is being saved from.
|
||||
* @param cache Output cp_cache_t
|
||||
* @param index -1 if you want the cp_cache_t to be saved as "persistent data". 0 if not. greater-than-zero if you what you're doing and intentionally want to spoof the cp_cache_t creation as a checkpoint index for some reason... I recommend looking at shavit-checkpoints.sp to see how "index" and "isPersistentData" are used to see what kind of difference there is.
|
||||
* @param size sizeof(cp_cache_t) to mostly ensure the calling plugin has a matching cp_cache_t.
|
||||
* @param saveReplay Whether or not replay frames will be saved.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SaveCheckpointCache(int saver, int target, any[] cache, int index, int size = sizeof(cp_cache_t), bool saveReplay = false);
|
||||
|
||||
public SharedPlugin __pl_shavit_checkpoints =
|
||||
{
|
||||
name = "shavit-checkpoints",
|
||||
file = "shavit-checkpoints.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_checkpoints_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetTotalCheckpoints");
|
||||
|
||||
MarkNativeAsOptional("Shavit_GetCheckpoint");
|
||||
MarkNativeAsOptional("Shavit_SetCheckpoint");
|
||||
|
||||
MarkNativeAsOptional("Shavit_TeleportToCheckpoint");
|
||||
MarkNativeAsOptional("Shavit_ClearCheckpoints");
|
||||
MarkNativeAsOptional("Shavit_SaveCheckpoint");
|
||||
|
||||
MarkNativeAsOptional("Shavit_GetCurrentCheckpoint");
|
||||
MarkNativeAsOptional("Shavit_SetCurrentCheckpoint");
|
||||
|
||||
MarkNativeAsOptional("Shavit_GetTimesTeleported");
|
||||
MarkNativeAsOptional("Shavit_SetTimesTeleported");
|
||||
|
||||
MarkNativeAsOptional("Shavit_HasSavestate");
|
||||
|
||||
MarkNativeAsOptional("Shavit_LoadCheckpointCache");
|
||||
MarkNativeAsOptional("Shavit_SaveCheckpointCache");
|
||||
}
|
||||
#endif
|
||||
1459
addons/sourcemod/scripting/include/shavit/core.inc
Normal file
1459
addons/sourcemod/scripting/include/shavit/core.inc
Normal file
File diff suppressed because it is too large
Load Diff
254
addons/sourcemod/scripting/include/shavit/hud.inc
Normal file
254
addons/sourcemod/scripting/include/shavit/hud.inc
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* shavit's Timer - hud.inc file
|
||||
* by: shavit
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_hud_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_hud_included
|
||||
|
||||
#define HUD_NONE 0
|
||||
#define HUD_MASTER (1 << 0) // master setting
|
||||
#define HUD_CENTER (1 << 1) // show hud as hint text
|
||||
#define HUD_ZONEHUD (1 << 2) // show start/end zone hud
|
||||
#define HUD_OBSERVE (1 << 3) // show the HUD of the player you spectate
|
||||
#define HUD_SPECTATORS (1 << 4) // show list of spectators
|
||||
#define HUD_KEYOVERLAY (1 << 5) // show a key overlay
|
||||
#define HUD_HIDEWEAPON (1 << 6) // hide the player's weapon
|
||||
#define HUD_TOPLEFT (1 << 7) // show top left white HUD with WR/PB times
|
||||
#define HUD_SYNC (1 << 8) // shows sync at right side of the screen (css only)
|
||||
#define HUD_TIMELEFT (1 << 9) // shows time left at right tside of the screen (css only)
|
||||
#define HUD_2DVEL (1 << 10) // shows 2d velocity
|
||||
#define HUD_NOSOUNDS (1 << 11) // disables sounds on personal best, world record etc
|
||||
#define HUD_NOPRACALERT (1 << 12) // hides practice mode chat alert
|
||||
#define HUD_USP (1 << 13) // makes you spawn with a USP
|
||||
#define HUD_GLOCK (1 << 14) // makes you spawn with a Glock
|
||||
#define HUD_DEBUGTARGETNAME (1 << 15) // admin option to show current targetname & classname
|
||||
#define HUD_SPECTATORSDEAD (1 << 16) // for only showing spectators list when you're dead/spectating.
|
||||
#define HUD_PERFS_CENTER (1 << 17) // for the perf percentage in the center hud. e.g. "Jumps: 20 (66.6%)"
|
||||
|
||||
// HUD2 - these settings will *disable* elements for the main hud
|
||||
#define HUD2_TIME (1 << 0)
|
||||
#define HUD2_SPEED (1 << 1)
|
||||
#define HUD2_JUMPS (1 << 2)
|
||||
#define HUD2_STRAFE (1 << 3)
|
||||
#define HUD2_SYNC (1 << 4)
|
||||
#define HUD2_STYLE (1 << 5)
|
||||
#define HUD2_RANK (1 << 6)
|
||||
#define HUD2_TRACK (1 << 7)
|
||||
#define HUD2_SPLITPB (1 << 8)
|
||||
#define HUD2_MAPTIER (1 << 9)
|
||||
#define HUD2_TIMEDIFFERENCE (1 << 10)
|
||||
#define HUD2_PERFS (1 << 11)
|
||||
#define HUD2_TOPLEFT_RANK (1 << 12)
|
||||
#define HUD2_VELOCITYDIFFERENCE (1 << 13)
|
||||
#define HUD2_USPSILENCER (1 << 14) // spawns usps with a silencer on
|
||||
#define HUD2_GLOCKBURST (1 << 15) // spawns glocks with burst
|
||||
#define HUD2_CENTERKEYS (1 << 16) // CSGO option to toggle whether !keys is shown as center-text or in that panel thing.
|
||||
|
||||
#define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS)
|
||||
#define HUD_DEFAULT2 (HUD2_PERFS)
|
||||
|
||||
stock bool HUD1Enabled(int hudbits, int flag)
|
||||
{
|
||||
return (hudbits & flag) != 0;
|
||||
}
|
||||
|
||||
stock bool HUD2Enabled(int hudbits, int flag)
|
||||
{
|
||||
return (hudbits & flag) == 0;
|
||||
}
|
||||
|
||||
enum ZoneHUD
|
||||
{
|
||||
ZoneHUD_None,
|
||||
ZoneHUD_Start,
|
||||
ZoneHUD_End
|
||||
};
|
||||
|
||||
enum struct huddata_t
|
||||
{
|
||||
int iTarget;
|
||||
float fTime;
|
||||
int iSpeed;
|
||||
int iStyle;
|
||||
int iTrack;
|
||||
int iJumps;
|
||||
int iStrafes;
|
||||
int iRank;
|
||||
float fSync;
|
||||
float fPB;
|
||||
float fWR;
|
||||
bool bReplay;
|
||||
bool bPractice;
|
||||
TimerStatus iTimerStatus;
|
||||
ZoneHUD iZoneHUD;
|
||||
|
||||
int iHUDSettings;
|
||||
int iHUD2Settings;
|
||||
|
||||
int iPreviousSpeed;
|
||||
float fClosestReplayTime;
|
||||
float fClosestVelocityDifference;
|
||||
int iMapTier;
|
||||
float fClosestReplayLength;
|
||||
|
||||
int iButtons;
|
||||
int iScrolls;
|
||||
int iScrollsPrev;
|
||||
float fAngleDiff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when top left HUD updates.
|
||||
*
|
||||
* @param client Client index that recieves the hud.
|
||||
* @param target Target entity that is either the client or what the client is spectating.
|
||||
* @param topleft Reference to the HUD buffer.
|
||||
* @param topleftlength Max length of the topleft buffer.
|
||||
* @param track Target's track.
|
||||
* @param style Target's style.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to block the HUD message from appearing. Anything else to pass along new values.
|
||||
*/
|
||||
forward Action Shavit_OnTopLeftHUD(int client, int target, char[] topleft, int topleftlength, int track, int style);
|
||||
|
||||
/**
|
||||
* Called before the top left HUD updates and used to build the string for shavit-hud.
|
||||
*
|
||||
* @param client Client index that recieves the hud.
|
||||
* @param target Target entity that is either the client or what the client is spectating.
|
||||
* @param topleft Reference to the HUD buffer.
|
||||
* @param topleftlength Max length of the topleft buffer.
|
||||
* @param track Target's track.
|
||||
* @param style Target's style.
|
||||
* @param forceUpdate Force even if the client has disabled HUD_TOPLEFT.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to block the HUD message from appearing. Plugin_Changed to use own topleft string instead of shavit-hud building it.
|
||||
*/
|
||||
forward Action Shavit_PreOnTopLeftHUD(int client, int target, char[] topleft, int topleftlength, int track, int style, bool &forceUpdate);
|
||||
|
||||
/**
|
||||
* Called when key hint (bottom left) HUD updates (Source 2013 only).
|
||||
*
|
||||
* @param client Client index that recieves the hud.
|
||||
* @param target Target entity that is either the client or what the client is spectating.
|
||||
* @param keyhint Reference to the HUD buffer.
|
||||
* @param keyhintlength Max length of the keyhint buffer.
|
||||
* @param track Target's track.
|
||||
* @param style Target's style.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to block the HUD message from appearing. Anything else to pass along new values.
|
||||
*/
|
||||
forward Action Shavit_OnKeyHintHUD(int client, int target, char[] keyhint, int keyhintlength, int track, int style);
|
||||
|
||||
/**
|
||||
* Called before the key hint HUD (bottom left) updates and used to build the string for shavit-hud (Source 2013 only).
|
||||
*
|
||||
* @param client Client index that recieves the hud.
|
||||
* @param target Target entity that is either the client or what the client is spectating.
|
||||
* @param keyhint Reference to the HUD buffer.
|
||||
* @param keyhintlength Max length of the keyhint buffer.
|
||||
* @param track Target's track.
|
||||
* @param style Target's style.
|
||||
* @param forceUpdate Force even if the client has disabled HUD_SYNC, HUD_TIMELEFT, and HUD2_PERFS.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to block the HUD message from appearing. Plugin_Changed to use own keyhint string instead of shavit-hud building it.
|
||||
*/
|
||||
forward Action Shavit_PreOnKeyHintHUD(int client, int target, char[] keyhint, int keyhintlength, int track, int style, bool &forceUpdate);
|
||||
|
||||
/**
|
||||
* Called before the center hud updates.
|
||||
*
|
||||
* @param client Client index that recieves the hud.
|
||||
* @param target Target entity that is either the client or what the client is spectating.
|
||||
* @param buffer Reference to the HUD buffer.
|
||||
* @param buflen Max length of the buffer.
|
||||
* @param data huddata_t which contains target info.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to block the HUD message from appearing. Plugin_Changed if you modify the buffer string.
|
||||
*/
|
||||
forward Action Shavit_PreOnDrawCenterHUD(int client, int target, char[] buffer, int buflen, huddata_t data);
|
||||
|
||||
/**
|
||||
* Called before the !keys hud updates.
|
||||
*
|
||||
* @param client Client index that recieves the hud.
|
||||
* @param target Target entity that is either the client or what the client is spectating.
|
||||
* @param style The target's style.
|
||||
* @param buttons The target's buttons.
|
||||
* @param anglediff The difference from the target's last angles and current angles.
|
||||
* @param buffer Reference to the HUD buffer.
|
||||
* @param buflen Max length of the buffer.
|
||||
* @param scrolls How many scrolls the player has so far (relevant for non-auto styles).
|
||||
* @param prevscrolls How many scrolls previously.
|
||||
* @param alternate_center_keys True when you should draw a Linux-specific format since fonts & alignment are different.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to block the HUD message from appearing. Plugin_Changed if you modify the buffer string.
|
||||
*/
|
||||
forward Action Shavit_PreOnDrawKeysHUD(int client, int target, int style, int buttons, float anglediff, char[] buffer, int buflen, int scrolls, int prevscrolls, bool alternate_center_keys);
|
||||
|
||||
/**
|
||||
* Force an HUD update for a player. Requires shavit-hud.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param spectators Should also update it for the player's spectators?
|
||||
* @error Error code 200 if client isn't valid.
|
||||
* @return Amount of players that had their HUD updated (client + spectators) or -1 on error.
|
||||
*/
|
||||
native int Shavit_ForceHUDUpdate(int client, bool spectators);
|
||||
|
||||
/**
|
||||
* Gets the HUD settings of a player.
|
||||
* See the HUD_* defines for information.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return HUD settings.
|
||||
*/
|
||||
native int Shavit_GetHUDSettings(int client);
|
||||
|
||||
/**
|
||||
* Gets the HUD2 settings of a player.
|
||||
* See the HUD2_* defines for information.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return HUD settings.
|
||||
*/
|
||||
native int Shavit_GetHUD2Settings(int client);
|
||||
|
||||
public SharedPlugin __pl_shavit_hud =
|
||||
{
|
||||
name = "shavit-hud",
|
||||
file = "shavit-hud.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_hud_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_ForceHUDUpdate");
|
||||
MarkNativeAsOptional("Shavit_GetHUDSettings");
|
||||
MarkNativeAsOptional("Shavit_GetHUD2Settings");
|
||||
}
|
||||
#endif
|
||||
84
addons/sourcemod/scripting/include/shavit/mapchooser.inc
Normal file
84
addons/sourcemod/scripting/include/shavit/mapchooser.inc
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* shavit's Timer - mapchooser.inc file
|
||||
* by: SlidyBat, KiD Fearless, mbhound, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_mapchooser_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_mapchooser_included
|
||||
|
||||
/**
|
||||
* Called when a player RTV's.
|
||||
* Requires shavit-mapchooser.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void SMC_OnRTV(int client);
|
||||
|
||||
/**
|
||||
* Called when a player UNRTV's.
|
||||
* Requires shavit-mapchooser.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void SMC_OnUnRTV(int client);
|
||||
|
||||
/**
|
||||
* Called when the map changes from an RTV.
|
||||
* Requires shavit-mapchooser.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
forward void SMC_OnSuccesfulRTV();
|
||||
|
||||
/**
|
||||
* Returns the ArrayList of maps currently on rotation.
|
||||
*
|
||||
* @return The ArrayList of Maps. Don't delete this handle.
|
||||
*/
|
||||
native ArrayList Shavit_GetMapsArrayList();
|
||||
|
||||
/**
|
||||
* Returns the StringMap of maps currently on rotation.
|
||||
*
|
||||
* @return the StringMap of maps. Don't delete this handle.
|
||||
*/
|
||||
native StringMap Shavit_GetMapsStringMap();
|
||||
|
||||
public SharedPlugin __pl_shavit_mapchooser =
|
||||
{
|
||||
name = "shavit-mapchooser",
|
||||
file = "shavit-mapchooser.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_mapchooser_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetMapsArrayList");
|
||||
MarkNativeAsOptional("Shavit_GetMapsStringMap");
|
||||
}
|
||||
#endif
|
||||
254
addons/sourcemod/scripting/include/shavit/maps-folder-stocks.inc
Normal file
254
addons/sourcemod/scripting/include/shavit/maps-folder-stocks.inc
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* shavit's Timer - maps-folder-stocks.inc file
|
||||
* by: rtldg, kidfearless
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_mapsfolderstocks_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_mapsfolderstocks_included
|
||||
|
||||
stock bool WriteNavMesh(const char[] map, bool skipExistsCheck = false)
|
||||
{
|
||||
char sTempMap[PLATFORM_MAX_PATH];
|
||||
FormatEx(sTempMap, PLATFORM_MAX_PATH, "maps/%s.nav", map);
|
||||
|
||||
if (skipExistsCheck || !FileExists(sTempMap))
|
||||
{
|
||||
File file = OpenFile(sTempMap, "wb");
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
int zero[1];
|
||||
static int defaultNavMesh[51] = {
|
||||
-17958194, 16, 1, 128600, 16777217, 1, 1, 0, -1007845376, 1112014848, 1107304447, -1035468800,
|
||||
1139638272, 1107304447, 1107304447, 1107304447, 0, 0, 0, 0, 4, -415236096, 2046820547, 2096962,
|
||||
65858, 0, 49786, 536822394, 33636864, 0, 12745216, -12327104, 21102623, 3, -1008254976, 1139228672,
|
||||
1107304447, 1, 0, 0, 0, 4386816, 4386816, 4161536, 4161536, 4161536, 20938752, 16777216, 33554432, 0, 0
|
||||
};
|
||||
|
||||
file.Write(defaultNavMesh, sizeof(defaultNavMesh), 4);
|
||||
file.Write(zero, 1, 1);
|
||||
delete file;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
stock bool WriteNavMeshBz2(const char[] map, bool skipExistsCheck = false)
|
||||
{
|
||||
char sTempMap[PLATFORM_MAX_PATH];
|
||||
FormatEx(sTempMap, PLATFORM_MAX_PATH, "maps/%s.nav.bz2", map);
|
||||
|
||||
if (skipExistsCheck || !FileExists(sTempMap))
|
||||
{
|
||||
File file = OpenFile(sTempMap, "wb");
|
||||
|
||||
if (file != null)
|
||||
{
|
||||
static int defaultNavMeshBz2[132/4] = {
|
||||
0x39685A42, 0x26594131, 0xB8955953, 0x0000B354,
|
||||
0xFEC56E4E, 0x80004004, 0x0040D800, 0x40100040,
|
||||
0x00011800, 0xA0114182, 0xA7127200, 0x915133AA,
|
||||
0x04B501A0, 0x64A03285, 0x31190D0D, 0x96F2A658,
|
||||
0x864651CE, 0xA93468D3, 0xD269C634, 0x66EE82B6,
|
||||
0x3B1D4103, 0xD4BE309C, 0x58DF5463, 0xC0076E1B,
|
||||
0x346C6DC1, 0x8B9FD47B, 0x0385015D, 0x3B260D99,
|
||||
0xF43C28F0, 0xD071CFB3, 0xC95DFC92, 0x4242E114,
|
||||
0xCC52E156
|
||||
};
|
||||
|
||||
file.Write(defaultNavMeshBz2, sizeof(defaultNavMeshBz2), 4);
|
||||
delete file;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
stock void CreateAllNavFiles()
|
||||
{
|
||||
StringMap mapList = new StringMap();
|
||||
DirectoryListing dir = OpenDirectory("maps", true);
|
||||
|
||||
if (dir == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char fileName[PLATFORM_MAX_PATH];
|
||||
FileType type;
|
||||
|
||||
// Loop through maps folder.
|
||||
// If .bsp, mark as need .nav
|
||||
// If .nav, mark as have .nav
|
||||
while (dir.GetNext(fileName, sizeof(fileName), type))
|
||||
{
|
||||
if (type != FileType_File)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int length = strlen(fileName);
|
||||
|
||||
if (length < 5 || fileName[length-4] != '.') // a.bsp
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fileName[length-3] == 'b' && fileName[length-2] == 's' && fileName[length-1] == 'p')
|
||||
{
|
||||
fileName[length-4] = 0;
|
||||
mapList.SetValue(fileName, false, false); // note: false for 'replace'
|
||||
}
|
||||
else if (fileName[length-3] == 'n' && fileName[length-2] == 'a' && fileName[length-1] == 'v')
|
||||
{
|
||||
fileName[length-4] = 0;
|
||||
mapList.SetValue(fileName, true, true); // note: true for 'replace'
|
||||
}
|
||||
}
|
||||
|
||||
delete dir;
|
||||
|
||||
// StringMap shenanigans are used so we don't call FileExists() 2000 times
|
||||
StringMapSnapshot snapshot = mapList.Snapshot();
|
||||
|
||||
for (int i = 0; i < snapshot.Length; i++)
|
||||
{
|
||||
snapshot.GetKey(i, fileName, sizeof(fileName));
|
||||
|
||||
bool hasNAV = false;
|
||||
mapList.GetValue(fileName, hasNAV);
|
||||
|
||||
if (!hasNAV)
|
||||
{
|
||||
WriteNavMesh(fileName, true);
|
||||
}
|
||||
}
|
||||
|
||||
delete snapshot;
|
||||
delete mapList;
|
||||
}
|
||||
|
||||
stock bool ReadMapsFolderHandler(const char path[PLATFORM_MAX_PATH], bool is_stringmap, Handle data, bool lowercase, bool display, bool iter_subfolders, bool use_valve_fs, char[][] exclude_prefixes, int exclude_count)
|
||||
{
|
||||
bool first_iteration = StrEqual(path, "maps");
|
||||
DirectoryListing dir = OpenDirectory(path, use_valve_fs, NULL_STRING);
|
||||
|
||||
if (dir == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[PLATFORM_MAX_PATH];
|
||||
FileType type;
|
||||
|
||||
while (dir.GetNext(buffer, sizeof(buffer), type))
|
||||
{
|
||||
if (type == FileType_Directory)
|
||||
{
|
||||
if (buffer[0] == '.' && (buffer[1] == 0 || (buffer[1] == '.' && buffer[2] == 0)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter_subfolders)
|
||||
{
|
||||
char subfolder[PLATFORM_MAX_PATH];
|
||||
FormatEx(subfolder, sizeof(subfolder), "%s/%s", path, buffer);
|
||||
ReadMapsFolderHandler(subfolder, is_stringmap, data, lowercase, display, iter_subfolders, use_valve_fs, exclude_prefixes, exclude_count);
|
||||
}
|
||||
}
|
||||
else if (type == FileType_File)
|
||||
{
|
||||
int length = strlen(buffer);
|
||||
|
||||
if (length < 5 || buffer[length-4] != '.') // a.bsp
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((buffer[length-3] == 'b' && buffer[length-2] == 's' && buffer[length-1] == 'p') ||
|
||||
(buffer[length-3] == 'u' && buffer[length-2] == 'g' && buffer[length-1] == 'c'))
|
||||
{
|
||||
buffer[length-4] = 0;
|
||||
|
||||
if (lowercase)
|
||||
{
|
||||
LowercaseString(buffer);
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
|
||||
for (int i = 0; i < exclude_count; i++)
|
||||
{
|
||||
if (strncmp(buffer, exclude_prefixes[i], strlen(exclude_prefixes[i]), lowercase) == 0)
|
||||
{
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!display && !first_iteration)
|
||||
{
|
||||
char temp[PLATFORM_MAX_PATH];
|
||||
int skip_this = 5; // strlen("maps/")
|
||||
FormatEx(temp, sizeof(temp), "%s/%s", path[skip_this], buffer);
|
||||
buffer = temp;
|
||||
}
|
||||
|
||||
if (is_stringmap)
|
||||
{
|
||||
view_as<StringMap>(data).SetValue(buffer, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
view_as<ArrayList>(data).PushString(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete dir;
|
||||
return true;
|
||||
}
|
||||
|
||||
static char empty_excludes[][] = {""};
|
||||
|
||||
stock bool ReadMapsFolderStringMap(StringMap data, bool lowercase=true, bool display=false, bool iter_subfolders=true, bool use_valve_fs=true, char[][] exclude_prefixes=empty_excludes, int exclude_count=0)
|
||||
{
|
||||
return ReadMapsFolderHandler("maps", true, data, lowercase, display, iter_subfolders, use_valve_fs, exclude_prefixes, exclude_count);
|
||||
}
|
||||
|
||||
// don't forget to declare your ArrayList like below :)))
|
||||
//// ArrayList maps = new ArrayList(ByteCountToCells(PLATFORM_MAX_PATH));
|
||||
stock bool ReadMapsFolderArrayList(ArrayList data, bool lowercase=true, bool display=false, bool iter_subfolders=true, bool use_valve_fs=true, char[][] exclude_prefixes=empty_excludes, int exclude_count=0)
|
||||
{
|
||||
return ReadMapsFolderHandler("maps", false, data, lowercase, display, iter_subfolders, use_valve_fs, exclude_prefixes, exclude_count);
|
||||
}
|
||||
71
addons/sourcemod/scripting/include/shavit/misc.inc
Normal file
71
addons/sourcemod/scripting/include/shavit/misc.inc
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* shavit's Timer - misc.inc file
|
||||
* by: EvanIMK, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_misc_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_misc_included
|
||||
|
||||
/**
|
||||
* Checks if a player is hiding players
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Boolean value.
|
||||
*/
|
||||
native bool Shavit_IsClientUsingHide(int client);
|
||||
|
||||
/**
|
||||
* Called before clan tag variables are processed.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param clantag Reference to the clan tag buffer.
|
||||
* @param clantaglength Max length of the customtag buffer.
|
||||
* @return Plugin_Handled or Plugin_Stop to block the clan tag from changing. Anything else to pass along new values.
|
||||
*/
|
||||
forward Action Shavit_OnClanTagChangePre(int client, char[] clantag, int clantaglength);
|
||||
|
||||
/**
|
||||
* Called after clan tags are changed.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param customtag Reference to the custom clan tag buffer.
|
||||
* @param customtaglength Max length of the customtag buffer.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnClanTagChangePost(int client, char[] customtag, int customtaglength);
|
||||
|
||||
public SharedPlugin __pl_shavit_misc =
|
||||
{
|
||||
name = "shavit-misc",
|
||||
file = "shavit-misc.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_misc_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_IsClientUsingHide");
|
||||
}
|
||||
#endif
|
||||
56
addons/sourcemod/scripting/include/shavit/physicsuntouch.inc
Normal file
56
addons/sourcemod/scripting/include/shavit/physicsuntouch.inc
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* physicsuntouch.inc
|
||||
* by: rumour
|
||||
*
|
||||
* Originally from EndTouch Fix (https://github.com/rumourA/End-Touch-Fix)
|
||||
* but edited to be part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _physicuntouch_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _physicuntouch_included
|
||||
|
||||
|
||||
#define EFL_CHECK_UNTOUCH (1<<24)
|
||||
|
||||
Handle gH_PhysicsCheckForEntityUntouch;
|
||||
|
||||
stock void LoadPhysicsUntouch(Handle gamedata)
|
||||
{
|
||||
StartPrepSDKCall(SDKCall_Entity);
|
||||
|
||||
if (!PrepSDKCall_SetFromConf(gamedata, SDKConf_Signature, "PhysicsCheckForEntityUntouch"))
|
||||
{
|
||||
SetFailState("Failed to get PhysicsCheckForEntityUntouch");
|
||||
}
|
||||
|
||||
gH_PhysicsCheckForEntityUntouch = EndPrepSDKCall();
|
||||
}
|
||||
|
||||
stock bool GetCheckUntouch(int client)
|
||||
{
|
||||
int flags = GetEntProp(client, Prop_Data, "m_iEFlags");
|
||||
return (flags & EFL_CHECK_UNTOUCH) != 0;
|
||||
}
|
||||
|
||||
stock void MaybeDoPhysicsUntouch(int client)
|
||||
{
|
||||
if (GetCheckUntouch(client))
|
||||
{
|
||||
SDKCall(gH_PhysicsCheckForEntityUntouch, client);
|
||||
}
|
||||
}
|
||||
175
addons/sourcemod/scripting/include/shavit/rankings.inc
Normal file
175
addons/sourcemod/scripting/include/shavit/rankings.inc
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* shavit's Timer - rankings.inc file
|
||||
* by: shavit
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_rankings_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_rankings_included
|
||||
|
||||
/**
|
||||
* Gets called when a map's tier is assigned.
|
||||
* Only called once per map, if the rankings plugin is enabled.
|
||||
* The exception is if the admin changes the current map's tier.
|
||||
*
|
||||
* @param map Map display name.
|
||||
* @param tier Map's tier.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnTierAssigned(const char[] map, int tier);
|
||||
|
||||
/**
|
||||
* Gets called when the server acknowledges the client's ranking status.
|
||||
* It is called after OnClientPostAdminCheck and at forced rank recalculations.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param rank Client's rank. (0 if unranked or unassigned)
|
||||
* @param points Client's points. (0.0 if unranked or unassigned)
|
||||
* @param first True if the forward is called after the initial connection, false if it is caused by recalculation.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnRankAssigned(int client, int rank, float points, bool first);
|
||||
|
||||
/**
|
||||
* Gets the map tier for a specified map.
|
||||
* Use the map's display name.
|
||||
*
|
||||
* @param map Map to get the tier of. Using "" will get the current map's tier.
|
||||
* @return Map tier. 0 if no results were found.
|
||||
*/
|
||||
native int Shavit_GetMapTier(const char[] map = "");
|
||||
|
||||
/**
|
||||
* Gets a StringMap that contains all the cached map tiers.
|
||||
* The returned StringMap must be deleted from memory after use!
|
||||
*
|
||||
* @return StringMap with {const char[]: map, int: tier} structure.
|
||||
*/
|
||||
native StringMap Shavit_GetMapTiers();
|
||||
|
||||
/**
|
||||
* Gets player points.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Points. 0.0 if unranked.
|
||||
*/
|
||||
native float Shavit_GetPoints(int client);
|
||||
|
||||
/**
|
||||
* Gets player rank.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Rank. 0 if unranked.
|
||||
*/
|
||||
native int Shavit_GetRank(int client);
|
||||
|
||||
/**
|
||||
* Gets the amount of players with over 0 points.
|
||||
*
|
||||
* @return Amount of ranked players.
|
||||
*/
|
||||
native int Shavit_GetRankedPlayers();
|
||||
|
||||
/**
|
||||
* Deletes tier setting for the specified map.
|
||||
* Points recalculation will run right after this is finished.
|
||||
*
|
||||
* @param map Map name.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_Rankings_DeleteMap(const char[] map);
|
||||
|
||||
/**
|
||||
* Retrieves the amount of #1 records a player has.
|
||||
* Requires shavit-rankings.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param track Track to retrieve WRs from. -1 to use all tracks. All bonus tracks are combined.
|
||||
* @param style Style to retrieve WRs from. -1 to use all styles.
|
||||
* @param usecvars Whether to depend on the value of `shavit_stats_mvprankones` and `shavit_stats_mvprankones_maintrack`.
|
||||
* @return The number of WRs.
|
||||
*/
|
||||
native int Shavit_GetWRCount(int client, int track = -1, int style = -1, bool usecvars = true);
|
||||
|
||||
/**
|
||||
* Retrieves the number of players who hold #1 records.
|
||||
* Requires shavit-rankings.
|
||||
*
|
||||
* @param track Track to retrieve WRs from. -1 to use all tracks. All bonus tracks are combined.
|
||||
* @param style Style to retrieve WRs from. -1 to use all styles.
|
||||
* @param usecvars Whether to depend on the value of `shavit_stats_mvprankones` and `shavit_stats_mvprankones_maintrack`.
|
||||
* @return The number of WR holders. 0 if none.
|
||||
*/
|
||||
native int Shavit_GetWRHolders(int track = -1, int style = -1, bool usecvars = true);
|
||||
|
||||
/**
|
||||
* Retrieves the player's rank based on how many #1 records they hold.
|
||||
* Requires shavit-rankings.
|
||||
* Only works with MySQL 8.0+ or with MariaDB 10.2+.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param track Track to retrieve WRs from. -1 to use all tracks. All bonus tracks are combined.
|
||||
* @param style Style to retrieve WRs from. -1 to use all styles.
|
||||
* @param usecvars Whether to depend on the value of `shavit_stats_mvprankones` and `shavit_stats_mvprankones_maintrack`.
|
||||
* @return The rank. 0 if none, or not supported.
|
||||
*/
|
||||
native int Shavit_GetWRHolderRank(int client, int track = -1, int style = -1, bool usecvars = true);
|
||||
|
||||
/*
|
||||
* Calculates how many points a time will give.
|
||||
* Used to minimize number of SQL queries.
|
||||
* Requires shavit-rankings.
|
||||
*
|
||||
* @param track The track the time is from.
|
||||
* @param style The style the time is from.
|
||||
* @param tier The map tier. -1 to use the current map's tier.
|
||||
* @param time The time you want to calculate the points for.
|
||||
* @param wr WR.
|
||||
*
|
||||
* @return The number of points the time would give.
|
||||
*/
|
||||
native float Shavit_GuessPointsForTime(int track, int style, int tier, float time, float wr);
|
||||
|
||||
public SharedPlugin __pl_shavit_rankings =
|
||||
{
|
||||
name = "shavit-rankings",
|
||||
file = "shavit-rankings.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_rankings_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetMapTier");
|
||||
MarkNativeAsOptional("Shavit_GetMapTiers");
|
||||
MarkNativeAsOptional("Shavit_GetPoints");
|
||||
MarkNativeAsOptional("Shavit_GetRank");
|
||||
MarkNativeAsOptional("Shavit_GetRankedPlayers");
|
||||
MarkNativeAsOptional("Shavit_Rankings_DeleteMap");
|
||||
MarkNativeAsOptional("Shavit_GetWRCount");
|
||||
MarkNativeAsOptional("Shavit_GetWRHolders");
|
||||
MarkNativeAsOptional("Shavit_GetWRHolderRank");
|
||||
MarkNativeAsOptional("Shavit_GuessPointsForTime");
|
||||
}
|
||||
#endif
|
||||
429
addons/sourcemod/scripting/include/shavit/replay-file.inc
Normal file
429
addons/sourcemod/scripting/include/shavit/replay-file.inc
Normal file
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* shavit's Timer - replay file stocks & format
|
||||
* by: shavit, rtldg, KiD Fearless, carnifex, Nairda, EvanIMK
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_replay_file_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_replay_file_included
|
||||
|
||||
// History of REPLAY_FORMAT_SUBVERSION:
|
||||
// 0x01: standard origin[3], angles[2], and buttons
|
||||
// 0x02: flags added movetype added
|
||||
// 0x03: integrity stuff: style, track, and map added to header. preframe count added (unimplemented until later though)
|
||||
// 0x04: steamid/accountid written as a 32-bit int instead of a string
|
||||
// 0x05: postframes & fTickrate added
|
||||
// 0x06: mousexy and vel added
|
||||
// 0x07: fixed iFrameCount because postframes were included in the value when they shouldn't be
|
||||
// 0x08: added zone-offsets to header
|
||||
// 0x09: bumped with no actual file changes because time calculation in regards to offsets have been changed/fixed since it seems to have been using the end-zone-offset incorrectly (and should now be fine hopefully since 2021-12-21 / a146b51fb16febf1847657fba7ef9e0c056d7476)
|
||||
|
||||
#define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}"
|
||||
#define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}"
|
||||
#define REPLAY_FORMAT_SUBVERSION 0x09
|
||||
|
||||
#define REPLAY_FRAMES_PER_WRITE 100 // amounts of frames to write per read/write call
|
||||
|
||||
enum struct replay_header_t
|
||||
{
|
||||
char sReplayFormat[40];
|
||||
int iReplayVersion;
|
||||
char sMap[PLATFORM_MAX_PATH];
|
||||
int iStyle;
|
||||
int iTrack;
|
||||
int iPreFrames;
|
||||
int iFrameCount;
|
||||
float fTime;
|
||||
int iSteamID;
|
||||
int iPostFrames;
|
||||
float fTickrate;
|
||||
float fZoneOffset[2];
|
||||
}
|
||||
|
||||
enum struct frame_t
|
||||
{
|
||||
float pos[3];
|
||||
float ang[2];
|
||||
int buttons;
|
||||
// iReplayVersion >= 0x02
|
||||
int flags;
|
||||
MoveType mt;
|
||||
// Everything below is generally NOT loaded into memory for playback
|
||||
// iReplayVersion >= 0x06
|
||||
int mousexy; // `mousex | (mousey << 16)` // unpack with UnpackSignedShorts
|
||||
int vel; // basically `forwardmove | (sidemove << 16)` // unpack with UnpackSignedShorts
|
||||
}
|
||||
|
||||
enum struct frame_cache_t
|
||||
{
|
||||
int iFrameCount;
|
||||
float fTime;
|
||||
bool bNewFormat;
|
||||
int iReplayVersion;
|
||||
char sReplayName[MAX_NAME_LENGTH];
|
||||
int iPreFrames;
|
||||
ArrayList aFrames;
|
||||
// iReplayVersion >= 0x05
|
||||
int iPostFrames;
|
||||
float fTickrate;
|
||||
// blah blah not affected by iReplayVersion
|
||||
int iSteamID;
|
||||
}
|
||||
|
||||
// Can be used to unpack frame_t.mousexy and frame_t.vel
|
||||
stock void UnpackSignedShorts(int x, int[] out)
|
||||
{
|
||||
out[0] = ((x & 0xFFFF) ^ 0x8000) - 0x8000;
|
||||
out[1] = (((x >> 16) & 0xFFFF) ^ 0x8000) - 0x8000;
|
||||
}
|
||||
|
||||
stock bool LoadReplayCache(frame_cache_t cache, int style, int track, const char[] path, const char[] mapname)
|
||||
{
|
||||
bool success = false;
|
||||
replay_header_t header;
|
||||
File fFile = ReadReplayHeader(path, header, style, track);
|
||||
|
||||
if (fFile != null)
|
||||
{
|
||||
if (header.iReplayVersion > REPLAY_FORMAT_SUBVERSION)
|
||||
{
|
||||
// not going to try and read it
|
||||
}
|
||||
else if (header.iReplayVersion < 0x03 || (StrEqual(header.sMap, mapname, false) && header.iStyle == style && header.iTrack == track))
|
||||
{
|
||||
success = ReadReplayFrames(fFile, header, cache);
|
||||
}
|
||||
|
||||
delete fFile;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
stock bool ReadReplayFrames(File file, replay_header_t header, frame_cache_t cache)
|
||||
{
|
||||
int total_cells = 6;
|
||||
int used_cells = 6;
|
||||
bool is_btimes = false;
|
||||
|
||||
if (header.iReplayVersion > 0x01)
|
||||
{
|
||||
total_cells = 8;
|
||||
used_cells = 8;
|
||||
}
|
||||
|
||||
// We have differing total_cells & used_cells because we want to save memory during playback since the latest two cells added (vel & mousexy) aren't needed and are only useful for replay file anticheat usage stuff....
|
||||
if (header.iReplayVersion >= 0x06)
|
||||
{
|
||||
total_cells = 10;
|
||||
used_cells = 8;
|
||||
}
|
||||
|
||||
any aReplayData[sizeof(frame_t)];
|
||||
|
||||
delete cache.aFrames;
|
||||
int iTotalSize = header.iFrameCount + header.iPreFrames + header.iPostFrames;
|
||||
cache.aFrames = new ArrayList(used_cells, iTotalSize);
|
||||
|
||||
if (!header.sReplayFormat[0]) // old replay format. no header.
|
||||
{
|
||||
char sLine[320];
|
||||
char sExplodedLine[6][64];
|
||||
|
||||
if(!file.Seek(0, SEEK_SET))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (!file.EndOfFile())
|
||||
{
|
||||
file.ReadLine(sLine, 320);
|
||||
int iStrings = ExplodeString(sLine, "|", sExplodedLine, 6, 64);
|
||||
|
||||
aReplayData[0] = StringToFloat(sExplodedLine[0]);
|
||||
aReplayData[1] = StringToFloat(sExplodedLine[1]);
|
||||
aReplayData[2] = StringToFloat(sExplodedLine[2]);
|
||||
aReplayData[3] = StringToFloat(sExplodedLine[3]);
|
||||
aReplayData[4] = StringToFloat(sExplodedLine[4]);
|
||||
aReplayData[5] = (iStrings == 6) ? StringToInt(sExplodedLine[5]) : 0;
|
||||
|
||||
cache.aFrames.PushArray(aReplayData, 6);
|
||||
}
|
||||
|
||||
cache.iFrameCount = cache.aFrames.Length;
|
||||
}
|
||||
else // assumes the file position will be at the start of the frames
|
||||
{
|
||||
is_btimes = StrEqual(header.sReplayFormat, "btimes");
|
||||
|
||||
for (int i = 0; i < iTotalSize; i++)
|
||||
{
|
||||
if(file.Read(aReplayData, total_cells, 4) >= 0)
|
||||
{
|
||||
cache.aFrames.SetArray(i, aReplayData, used_cells);
|
||||
|
||||
if (is_btimes && (aReplayData[5] & IN_BULLRUSH))
|
||||
{
|
||||
if (!header.iPreFrames)
|
||||
{
|
||||
header.iPreFrames = i;
|
||||
header.iFrameCount -= i;
|
||||
}
|
||||
else if (!header.iPostFrames)
|
||||
{
|
||||
header.iPostFrames = header.iFrameCount + header.iPreFrames - i;
|
||||
header.iFrameCount -= header.iPostFrames;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.aFrames.Length <= 10) // worthless replay so it doesn't get to load
|
||||
{
|
||||
delete cache.aFrames;
|
||||
return false;
|
||||
}
|
||||
|
||||
cache.iFrameCount = header.iFrameCount;
|
||||
cache.fTime = header.fTime;
|
||||
cache.iReplayVersion = header.iReplayVersion;
|
||||
cache.bNewFormat = StrEqual(header.sReplayFormat, REPLAY_FORMAT_FINAL) || is_btimes;
|
||||
cache.sReplayName = "unknown";
|
||||
cache.iPreFrames = header.iPreFrames;
|
||||
cache.iPostFrames = header.iPostFrames;
|
||||
cache.fTickrate = header.fTickrate;
|
||||
cache.iSteamID = header.iSteamID;
|
||||
|
||||
if (cache.iSteamID != 0)
|
||||
{
|
||||
FormatEx(cache.sReplayName, sizeof(cache.sReplayName), "[U:1:%u]", cache.iSteamID);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
stock File ReadReplayHeader(const char[] path, replay_header_t header, int style = 0, int track = 0)
|
||||
{
|
||||
replay_header_t empty_header;
|
||||
header = empty_header;
|
||||
|
||||
File file = OpenFile(path, "rb");
|
||||
|
||||
if (file == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
char sHeader[64];
|
||||
|
||||
if(!file.ReadLine(sHeader, 64))
|
||||
{
|
||||
delete file;
|
||||
return null;
|
||||
}
|
||||
|
||||
TrimString(sHeader);
|
||||
char sExplodedHeader[2][64];
|
||||
ExplodeString(sHeader, ":", sExplodedHeader, 2, 64);
|
||||
|
||||
strcopy(header.sReplayFormat, sizeof(header.sReplayFormat), sExplodedHeader[1]);
|
||||
|
||||
if(StrEqual(header.sReplayFormat, REPLAY_FORMAT_FINAL)) // hopefully, the last of them
|
||||
{
|
||||
int version = StringToInt(sExplodedHeader[0]);
|
||||
|
||||
header.iReplayVersion = version;
|
||||
|
||||
// replay file integrity and PreFrames
|
||||
if(version >= 0x03)
|
||||
{
|
||||
file.ReadString(header.sMap, PLATFORM_MAX_PATH);
|
||||
file.ReadUint8(header.iStyle);
|
||||
file.ReadUint8(header.iTrack);
|
||||
|
||||
file.ReadInt32(header.iPreFrames);
|
||||
|
||||
// In case the replay was from when there could still be negative preframes
|
||||
if(header.iPreFrames < 0)
|
||||
{
|
||||
header.iPreFrames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
file.ReadInt32(header.iFrameCount);
|
||||
file.ReadInt32(view_as<int>(header.fTime));
|
||||
|
||||
if (header.iReplayVersion < 0x07)
|
||||
{
|
||||
header.iFrameCount -= header.iPreFrames;
|
||||
}
|
||||
|
||||
if(version >= 0x04)
|
||||
{
|
||||
file.ReadInt32(header.iSteamID);
|
||||
}
|
||||
else
|
||||
{
|
||||
char sAuthID[32];
|
||||
file.ReadString(sAuthID, 32);
|
||||
ReplaceString(sAuthID, 32, "[U:1:", "");
|
||||
ReplaceString(sAuthID, 32, "]", "");
|
||||
header.iSteamID = StringToInt(sAuthID);
|
||||
}
|
||||
|
||||
if (version >= 0x05)
|
||||
{
|
||||
file.ReadInt32(header.iPostFrames);
|
||||
file.ReadInt32(view_as<int>(header.fTickrate));
|
||||
|
||||
if (header.iReplayVersion < 0x07)
|
||||
{
|
||||
header.iFrameCount -= header.iPostFrames;
|
||||
}
|
||||
}
|
||||
|
||||
if (version >= 0x08)
|
||||
{
|
||||
file.ReadInt32(view_as<int>(header.fZoneOffset[0]));
|
||||
file.ReadInt32(view_as<int>(header.fZoneOffset[1]));
|
||||
}
|
||||
}
|
||||
else if(StrEqual(header.sReplayFormat, REPLAY_FORMAT_V2))
|
||||
{
|
||||
header.iFrameCount = StringToInt(sExplodedHeader[0]);
|
||||
}
|
||||
else // old, outdated and slow - only used for ancient replays
|
||||
{
|
||||
// check for btimes replays
|
||||
file.Seek(0, SEEK_SET);
|
||||
any stuff[2];
|
||||
file.Read(stuff, 2, 4);
|
||||
|
||||
int btimes_player_id = stuff[0];
|
||||
float run_time = stuff[1];
|
||||
|
||||
if (btimes_player_id >= 0 && run_time > 0.0 && run_time < (10.0 * 60.0 * 60.0))
|
||||
{
|
||||
header.sReplayFormat = "btimes";
|
||||
header.fTime = run_time;
|
||||
|
||||
file.Seek(0, SEEK_END);
|
||||
header.iFrameCount = (file.Position / 4 - 2) / 6;
|
||||
file.Seek(2*4, SEEK_SET);
|
||||
}
|
||||
}
|
||||
|
||||
if (header.iReplayVersion < 0x03)
|
||||
{
|
||||
header.iStyle = style;
|
||||
header.iTrack = track;
|
||||
}
|
||||
|
||||
if (header.iReplayVersion < 0x05)
|
||||
{
|
||||
header.fTickrate = (1.0 / GetTickInterval()); // just assume it's our own tickrate...
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
stock void WriteReplayHeader(File fFile, int style, int track, float time, int steamid, int preframes, int postframes, float fZoneOffset[2], int iSize, float tickrate, const char[] sMap)
|
||||
{
|
||||
fFile.WriteLine("%d:" ... REPLAY_FORMAT_FINAL, REPLAY_FORMAT_SUBVERSION);
|
||||
|
||||
fFile.WriteString(sMap, true);
|
||||
fFile.WriteInt8(style);
|
||||
fFile.WriteInt8(track);
|
||||
fFile.WriteInt32(preframes);
|
||||
|
||||
fFile.WriteInt32(iSize - preframes - postframes);
|
||||
fFile.WriteInt32(view_as<int>(time));
|
||||
fFile.WriteInt32(steamid);
|
||||
|
||||
fFile.WriteInt32(postframes);
|
||||
fFile.WriteInt32(view_as<int>(tickrate));
|
||||
|
||||
fFile.WriteInt32(view_as<int>(fZoneOffset[0]));
|
||||
fFile.WriteInt32(view_as<int>(fZoneOffset[1]));
|
||||
}
|
||||
|
||||
stock void cell2buf(char[] buf, int& pos, int cell)
|
||||
{
|
||||
buf[pos++] = cell & 0xFF;
|
||||
buf[pos++] = (cell >> 8) & 0xFF;
|
||||
buf[pos++] = (cell >> 16) & 0xFF;
|
||||
buf[pos++] = (cell >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
stock int WriteReplayHeaderToBuffer(char[] buf, int style, int track, float time, int steamid, int preframes, int postframes, float fZoneOffset[2], int totalframes, float tickrate, const char[] sMap)
|
||||
{
|
||||
int pos = FormatEx(buf, 512, "%d:%s\n%s", REPLAY_FORMAT_SUBVERSION, REPLAY_FORMAT_FINAL, sMap);
|
||||
pos += 1; // skip past NUL
|
||||
buf[pos++] = style & 0xFF;
|
||||
buf[pos++] = track & 0xFF;
|
||||
cell2buf(buf, pos, preframes);
|
||||
|
||||
cell2buf(buf, pos, totalframes - preframes - postframes);
|
||||
cell2buf(buf, pos, view_as<int>(time));
|
||||
cell2buf(buf, pos, steamid);
|
||||
|
||||
cell2buf(buf, pos, postframes);
|
||||
cell2buf(buf, pos, view_as<int>(tickrate));
|
||||
|
||||
cell2buf(buf, pos, view_as<int>(fZoneOffset[0]));
|
||||
cell2buf(buf, pos, view_as<int>(fZoneOffset[1]));
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// file_a is usually used as the wr replay file.
|
||||
// file_b is usually used as the duplicate/backup replay file.
|
||||
stock void WriteReplayFrames(ArrayList playerrecording, int iSize, File file_a, File file_b)
|
||||
{
|
||||
any aFrameData[sizeof(frame_t)];
|
||||
any aWriteData[sizeof(frame_t) * REPLAY_FRAMES_PER_WRITE];
|
||||
int iFramesWritten = 0;
|
||||
|
||||
for(int i = 0; i < iSize; i++)
|
||||
{
|
||||
playerrecording.GetArray(i, aFrameData, sizeof(frame_t));
|
||||
|
||||
for(int j = 0; j < sizeof(frame_t); j++)
|
||||
{
|
||||
aWriteData[(sizeof(frame_t) * iFramesWritten) + j] = aFrameData[j];
|
||||
}
|
||||
|
||||
if(++iFramesWritten == REPLAY_FRAMES_PER_WRITE || i == iSize - 1)
|
||||
{
|
||||
if (file_a)
|
||||
{
|
||||
file_a.Write(aWriteData, sizeof(frame_t) * iFramesWritten, 4);
|
||||
}
|
||||
|
||||
if (file_b)
|
||||
{
|
||||
file_b.Write(aWriteData, sizeof(frame_t) * iFramesWritten, 4);
|
||||
}
|
||||
|
||||
iFramesWritten = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
501
addons/sourcemod/scripting/include/shavit/replay-playback.inc
Normal file
501
addons/sourcemod/scripting/include/shavit/replay-playback.inc
Normal file
@ -0,0 +1,501 @@
|
||||
/*
|
||||
* shavit's Timer - replay-playback.inc file
|
||||
* by: shavit, rtldg, carnifex, KiD Fearless
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_replay_playback_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_replay_playback_included
|
||||
|
||||
#include <shavit/replay-file>
|
||||
|
||||
enum //ReplayStatus
|
||||
{
|
||||
Replay_Start,
|
||||
Replay_Running,
|
||||
Replay_End,
|
||||
Replay_Idle
|
||||
};
|
||||
|
||||
enum //ReplayBotType
|
||||
{
|
||||
Replay_Central,
|
||||
Replay_Looping, // these are the ones that loop styles, tracks, and (eventually) stages...
|
||||
Replay_Dynamic, // these are bots that spawn on !replay when the central bot is taken
|
||||
Replay_Prop, // A prop entity that is being used as a replay...
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when replay playback starts.
|
||||
* Will be called twice for every replay bot unless the replay is canceled before the second call. Use `delay_elapsed` to check for the first & second time.
|
||||
*
|
||||
* @param ent Entity index for the replay.
|
||||
* @param type The type of replay. Replay_Prop means `ent` is not a fakeclient, but instead a prop.
|
||||
* @param delay_elapsed `false` when the replay bot just spawned but before the start delay has elapsed. `true` when the start delay has elapsed.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnReplayStart(int ent, int type, bool delay_elapsed);
|
||||
|
||||
/**
|
||||
* Called when replay playback ends.
|
||||
* Will be called twice for most replay bots unless the replay bot is canceled before it finishes. See `actually_finished`.
|
||||
*
|
||||
* @param ent Entity index for the replay.
|
||||
* @param type The type of replay. Replay_Prop means `ent` is not a fakeclient, but instead a prop.
|
||||
* @param actually_finished `false` when the replay runs out of frames and is starting the timer to despawn. `true` when the replay bot is about to despawn. `true` will always run.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnReplayEnd(int ent, int type, bool actually_finished);
|
||||
|
||||
/**
|
||||
* Called when all replays files have been loaded.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnReplaysLoaded();
|
||||
|
||||
/**
|
||||
* Deletes all replays for the specified map.
|
||||
* Plugin will refresh if map is currently on.
|
||||
*
|
||||
* @param map Map name.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_Replay_DeleteMap(const char[] map);
|
||||
|
||||
/**
|
||||
* Deletes the specified replay file.
|
||||
* Replay data will be unloaded if necessary.
|
||||
*
|
||||
* @param map Map display name.
|
||||
* @param style Bhop style.
|
||||
* @param track Timer track.
|
||||
* @param accountid Account ID to validate against, 0 to skip validation.
|
||||
* @return true if replay existed, false if the steam id didn't match or the file didn't exist.
|
||||
*/
|
||||
native bool Shavit_DeleteReplay(const char[] map, int style, int track, int accountid = 0);
|
||||
|
||||
/**
|
||||
* Retrieves the engine time of the replay bot's first frame.
|
||||
*
|
||||
* @param entity Entity index.
|
||||
* @return The engine time of the replay bot's first frame.
|
||||
*/
|
||||
native float Shavit_GetReplayBotFirstFrameTime(int entity);
|
||||
|
||||
/**
|
||||
* Retrieve the replay bot's entity index.
|
||||
*
|
||||
* @param style Style you want. -1 if you want the central bot. If no central bot, the first bot it finds it used.
|
||||
* @param track Track you want. -1 if you want the central bot. If no central bot, the first bot it finds it used.
|
||||
* @return Client index for the replay bot. -1 if not found.
|
||||
*/
|
||||
native int Shavit_GetReplayBotIndex(int style, int track);
|
||||
|
||||
/**
|
||||
* Retrieve the style being played by the replay bot.
|
||||
*
|
||||
* @param entity Entity index.
|
||||
* @return Style being played by the replay bot. -1 if the replay bot is idle.
|
||||
*/
|
||||
native int Shavit_GetReplayBotStyle(int entity);
|
||||
|
||||
/**
|
||||
* Retrieve the timer track being played by the replay bot.
|
||||
*
|
||||
* @param entity entity index.
|
||||
* @return Timer track replayed by the bot. -1 if the replay bot is idle.
|
||||
*/
|
||||
native int Shavit_GetReplayBotTrack(int entity);
|
||||
|
||||
/**
|
||||
* Gets the replay bot type setting of the server.
|
||||
*
|
||||
* @return See ReplayBotType enum.
|
||||
*/
|
||||
native int Shavit_GetReplayBotType();
|
||||
|
||||
/**
|
||||
* Retrieve the replay bot's current played frame.
|
||||
*
|
||||
* @param entity Entity index.
|
||||
* @return Current played frame.
|
||||
*/
|
||||
native int Shavit_GetReplayBotCurrentFrame(int entity);
|
||||
|
||||
/**
|
||||
* Retrieves the client who started the replay.
|
||||
*
|
||||
* @param Replay entity.
|
||||
* @return Client index of starter. Can be 0
|
||||
*/
|
||||
native int Shavit_GetReplayStarter(int ent);
|
||||
|
||||
/**
|
||||
* Retrieves the replay's buttons for its current tick.
|
||||
* Really, this is only useful for things like replay props.
|
||||
*
|
||||
* @param Replay entity.
|
||||
* @param anglediff The angle difference between the previous and current y angles.
|
||||
*
|
||||
* @return buttons
|
||||
*/
|
||||
native int Shavit_GetReplayButtons(int ent, float& anglediff);
|
||||
|
||||
/**
|
||||
* Retrieves the replay's entity flags for its current tick.
|
||||
* @param Replay entity.
|
||||
* @return Entity flags
|
||||
*/
|
||||
native int Shavit_GetReplayEntityFlags(int ent);
|
||||
|
||||
/**
|
||||
* Retrieves a replay's frame count.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @return Frame count.
|
||||
*/
|
||||
native int Shavit_GetReplayFrameCount(int style, int track);
|
||||
|
||||
/**
|
||||
* Retrieves a replay's pre-run frame count.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @return Frame count.
|
||||
*/
|
||||
native int Shavit_GetReplayPreFrames(int style, int track);
|
||||
|
||||
/**
|
||||
* Retrieves a replay's post-run frame count.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @return Frame count.
|
||||
*/
|
||||
native int Shavit_GetReplayPostFrames(int style, int track);
|
||||
|
||||
/**
|
||||
* Retrieves the frame count from the currently running replay bot's frame_cache_t.
|
||||
*
|
||||
* @param bot Replay bot entity.
|
||||
* @return Frame count.
|
||||
*/
|
||||
native int Shavit_GetReplayCacheFrameCount(int bot);
|
||||
|
||||
/**
|
||||
* Retrieves the pre-run frame count from the currently running replay bot's frame_cache_t.
|
||||
*
|
||||
* @param bot Replay bot entity.
|
||||
* @return Frame count.
|
||||
*/
|
||||
native int Shavit_GetReplayCachePreFrames(int bot);
|
||||
|
||||
/**
|
||||
* Retrieves the post-run frame count from the currently running replay bot's frame_cache_t.
|
||||
*
|
||||
* @param bot Replay bot entity.
|
||||
* @return Frame count.
|
||||
*/
|
||||
native int Shavit_GetReplayCachePostFrames(int bot);
|
||||
|
||||
/**
|
||||
* Retrieves the replay data for the given style and track.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @param cheapCloneHandle False means we duplicate the frames (ArrayList.Clone). True means we clone the handle to the frames (CloneHandle).
|
||||
*
|
||||
* @return ArrayList with proper replay data, or null if there is no recorded data. Delete this handle when you're done with it.
|
||||
*/
|
||||
native ArrayList Shavit_GetReplayFrames(int style, int track, bool cheapCloneHandle=false);
|
||||
|
||||
/**
|
||||
* Retrieves a replay's total length in seconds.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @return Replay length.
|
||||
*/
|
||||
native float Shavit_GetReplayLength(int style, int track);
|
||||
|
||||
/**
|
||||
* Retrieves the replay's total length in seconds from the currently running replay bot's frame_cache_t.
|
||||
*
|
||||
* @param bot Replay bot entity.
|
||||
* @return Replay length.
|
||||
*/
|
||||
native float Shavit_GetReplayCacheLength(int bot);
|
||||
|
||||
/**
|
||||
* Retrieves an actively playing replay's time.
|
||||
*
|
||||
* @param entity Entity index.
|
||||
* @return The bot's current time in the replay.
|
||||
*/
|
||||
native float Shavit_GetReplayTime(int entity);
|
||||
|
||||
/**
|
||||
* Retrieves a replay holder's name.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @param buffer Buffer string.
|
||||
* @param length String length.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetReplayName(int style, int track, char[] buffer, int length);
|
||||
|
||||
/**
|
||||
* Retrieves a replay holder's name from an active replay bot.
|
||||
*
|
||||
* @param bot Bot.
|
||||
* @param buffer Buffer string.
|
||||
* @param length String length.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetReplayCacheName(int bot, char[] buffer, int length);
|
||||
|
||||
/**
|
||||
* Retrieves the folder path where the replay files are saved.
|
||||
*
|
||||
* @param buffer Buffer string.
|
||||
* @param length String length.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetReplayFolderPath(char[] buffer, int length);
|
||||
|
||||
/**
|
||||
* Checks if there's loaded replay data for a bhop style or not.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Track.
|
||||
* @return Boolean value of if there's loaded replay data.
|
||||
*/
|
||||
native bool Shavit_IsReplayDataLoaded(int style, int track);
|
||||
|
||||
/**
|
||||
* Checks if the given entity is a replay bot (fakeclient) or replay prop.
|
||||
*
|
||||
* @param The entity index to check.
|
||||
*/
|
||||
native bool Shavit_IsReplayEntity(int ent);
|
||||
|
||||
/**
|
||||
* Sets the sReplayName value in the bot's frame_cache_t.
|
||||
* Useful for `Shavit_StartReplayFromFile` and family.
|
||||
*
|
||||
* @param bot The replay bot entity.
|
||||
* @param name The name to use.
|
||||
*/
|
||||
native void Shavit_SetReplayCacheName(int bot, char[] name);
|
||||
|
||||
/**
|
||||
* Starts a replay given a style and track.
|
||||
*
|
||||
* @param style Bhop style.
|
||||
* @param track Timer track.
|
||||
* @param delay Delay until starting. If -1.0, then uses shavit_replay_delay
|
||||
* @param client Client index.
|
||||
* @param bot Bot to play on. Should be of type Replay_Central or Replay_Dynamic. -1 to create new replay bot.
|
||||
* @param type ReplayBotType. Replay_Prop needs `bot` to be -1.
|
||||
* @param ignorelimit Ignore cvar limit for dynamic bots.
|
||||
* @return Replay entity. 0 is returned if couldn't be created.
|
||||
*/
|
||||
native int Shavit_StartReplay(int style, int track, float delay, int client, int bot, int type, bool ignorelimit);
|
||||
|
||||
/**
|
||||
* Starts a replay with a given set of frames.
|
||||
* Useful for playing a replay downloaded from a global WR database...
|
||||
*
|
||||
* @param style Bhop style.
|
||||
* @param track Timer track.
|
||||
* @param delay Delay until starting. If -1.0, then uses shavit_replay_delay
|
||||
* @param client Client index.
|
||||
* @param bot Bot to play on. Should be of type Replay_Central or Replay_Dynamic. -1 to create new replay bot.
|
||||
* @param type ReplayBotType. Replay_Prop needs `bot` to be -1.
|
||||
* @param ignorelimit Ignore cvar limit for dynamic bots.
|
||||
* @param cache frame_cache_t filled with replay info and frames.
|
||||
* @param size sizeof(frame_cache_t). Used to throw errors at you if you don't recompile plugins.
|
||||
* @return Replay entity. 0 is returned if couldn't be created.
|
||||
*/
|
||||
native int Shavit_StartReplayFromFrameCache(int style, int track, float delay, int client, int bot, int type, bool ignorelimit, any[] cache, int size = sizeof(frame_cache_t));
|
||||
|
||||
/**
|
||||
* Starts a replay from a replay file.
|
||||
* Useful for playing a replay downloaded from a global WR database...
|
||||
*
|
||||
* @param style Bhop style.
|
||||
* @param track Timer track.
|
||||
* @param delay Delay until starting. If -1.0, then uses shavit_replay_delay
|
||||
* @param client Client index.
|
||||
* @param bot Bot to play on. Should be of type Replay_Central or Replay_Dynamic. -1 to create new replay bot.
|
||||
* @param type ReplayBotType. Replay_Prop needs `bot` to be -1.
|
||||
* @param ignorelimit Ignore cvar limit for dynamic bots.
|
||||
* @param path File path to replay
|
||||
* @return Replay entity. 0 is returned if couldn't be created.
|
||||
*/
|
||||
native int Shavit_StartReplayFromFile(int style, int track, float delay, int client, int bot, int type, bool ignorelimit, const char[] path);
|
||||
|
||||
/**
|
||||
* Reloads a specific replay into the replay bot cache.
|
||||
* Note: Not guaranteed to work with legacy replay bots.
|
||||
*
|
||||
* @param style Replay style.
|
||||
* @param track Replay track.
|
||||
* @param restart Restart the playback of the replay bot if it's playing?
|
||||
* @param path Path to the replay file. Use `BuildPath(Path_SM, ...)` to generate one. Leave as empty to use default.
|
||||
* @return Was the replay loaded?
|
||||
*/
|
||||
native bool Shavit_ReloadReplay(int style, int track, bool restart, char[] path = "");
|
||||
|
||||
/**
|
||||
* Reloads all of the replays for the map.
|
||||
*
|
||||
* @param restart Restart the playback of the replay bots?
|
||||
* @return Amount of loaded replays.
|
||||
*/
|
||||
native int Shavit_ReloadReplays(bool restart);
|
||||
|
||||
/**
|
||||
* Gets time from replay frame that is closest to client.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param outlength Fills this variable with the total length of the replay that's being compared to.
|
||||
*
|
||||
* @return Replay time.
|
||||
*/
|
||||
native float Shavit_GetClosestReplayTime(int client, float &outlength=0.0);
|
||||
|
||||
/**
|
||||
* Gets the style the client is getting the closest replay time from.
|
||||
*
|
||||
* @param client Client index.
|
||||
*
|
||||
* @return style
|
||||
*/
|
||||
native int Shavit_GetClosestReplayStyle(int client);
|
||||
|
||||
/**
|
||||
* Sets the style to grab the closest replay time from.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style blah.
|
||||
*
|
||||
* @param Style to grab replay time from. -1 to use the client's current style.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetClosestReplayStyle(int client, int style);
|
||||
|
||||
/**
|
||||
* Gets velocity from replay frame that is closest to client.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param threeD true for 3D velocity difference. false for 2D velocity difference.
|
||||
*
|
||||
* @return Velocity difference from closest replay position.
|
||||
*/
|
||||
native float Shavit_GetClosestReplayVelocityDifference(int client, bool threeD);
|
||||
|
||||
/**
|
||||
* Gets the replay status
|
||||
*
|
||||
* @param Replay bot (or prop) entity
|
||||
*
|
||||
* @return Replay's status
|
||||
*/
|
||||
native int Shavit_GetReplayStatus(int ent);
|
||||
|
||||
/*
|
||||
* Used to find a looping replay bot from the loop config name.
|
||||
*
|
||||
* @param name Looping bot config name. An example is "Other Styles" from the default set of looping bots in shavit-replay.cfg
|
||||
*
|
||||
* @return The client index of the looping replay bot. -1 if could not find the config name. 0 if could not find the replay bot client.
|
||||
*/
|
||||
native int Shavit_GetLoopingBotByName(const char[] name);
|
||||
|
||||
/*
|
||||
* Retrieves the playback speed of the replay bot.
|
||||
*
|
||||
* @param bot
|
||||
*
|
||||
* @return Should be 0.5, 1.0, or 2.0.
|
||||
*/
|
||||
native float Shavit_GetReplayPlaybackSpeed(int bot);
|
||||
|
||||
|
||||
public SharedPlugin __pl_shavit_replay_playback =
|
||||
{
|
||||
name = "shavit-replay-playback",
|
||||
file = "shavit-replay-playback.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_replay_playback_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_DeleteReplay");
|
||||
MarkNativeAsOptional("Shavit_GetReplayBotCurrentFrame");
|
||||
MarkNativeAsOptional("Shavit_GetReplayBotFirstFrameTime");
|
||||
MarkNativeAsOptional("Shavit_GetReplayBotIndex");
|
||||
MarkNativeAsOptional("Shavit_GetReplayBotStyle");
|
||||
MarkNativeAsOptional("Shavit_GetReplayBotTrack");
|
||||
MarkNativeAsOptional("Shavit_GetReplayBotType");
|
||||
MarkNativeAsOptional("Shavit_GetReplayStarter");
|
||||
MarkNativeAsOptional("Shavit_GetReplayFrameCount");
|
||||
MarkNativeAsOptional("Shavit_GetReplayFrames");
|
||||
MarkNativeAsOptional("Shavit_GetReplayLength");
|
||||
MarkNativeAsOptional("Shavit_GetReplayName");
|
||||
MarkNativeAsOptional("Shavit_GetReplayCacheName");
|
||||
MarkNativeAsOptional("Shavit_GetReplayStatus");
|
||||
MarkNativeAsOptional("Shavit_GetReplayTime");
|
||||
MarkNativeAsOptional("Shavit_IsReplayDataLoaded");
|
||||
MarkNativeAsOptional("Shavit_ReloadReplay");
|
||||
MarkNativeAsOptional("Shavit_ReloadReplays");
|
||||
MarkNativeAsOptional("Shavit_Replay_DeleteMap");
|
||||
MarkNativeAsOptional("Shavit_StartReplay");
|
||||
MarkNativeAsOptional("Shavit_GetClosestReplayTime");
|
||||
MarkNativeAsOptional("Shavit_GetClosestReplayVelocityDifference");
|
||||
MarkNativeAsOptional("Shavit_IsReplayEntity");
|
||||
MarkNativeAsOptional("Shavit_GetReplayButtons");
|
||||
MarkNativeAsOptional("Shavit_GetReplayEntityFlags");
|
||||
MarkNativeAsOptional("Shavit_GetClosestReplayStyle");
|
||||
MarkNativeAsOptional("Shavit_SetClosestReplayStyle");
|
||||
MarkNativeAsOptional("Shavit_GetReplayCacheFrameCount");
|
||||
MarkNativeAsOptional("Shavit_GetReplayCacheLength");
|
||||
MarkNativeAsOptional("Shavit_StartReplayFromFrameCache");
|
||||
MarkNativeAsOptional("Shavit_StartReplayFromFile");
|
||||
MarkNativeAsOptional("Shavit_GetReplayPreFrames");
|
||||
MarkNativeAsOptional("Shavit_GetReplayPostFrames");
|
||||
MarkNativeAsOptional("Shavit_GetReplayCachePreFrames");
|
||||
MarkNativeAsOptional("Shavit_GetReplayCachePostFrames");
|
||||
MarkNativeAsOptional("Shavit_GetLoopingBotByName");
|
||||
MarkNativeAsOptional("Shavit_SetReplayCacheName");
|
||||
MarkNativeAsOptional("Shavit_GetReplayFolderPath");
|
||||
MarkNativeAsOptional("Shavit_GetReplayPlaybackSpeed");
|
||||
}
|
||||
#endif
|
||||
165
addons/sourcemod/scripting/include/shavit/replay-recorder.inc
Normal file
165
addons/sourcemod/scripting/include/shavit/replay-recorder.inc
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* shavit's Timer - replay-recorder.inc file
|
||||
* by: shavit, rtldg,
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_replay_recorder_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_replay_recorder_included
|
||||
|
||||
/**
|
||||
* Called when a player finishes a time. Allows you to save a replay even if the run is not a WR.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style the record was done on.
|
||||
* @param time Record time.
|
||||
* @param jumps Jumps amount.
|
||||
* @param strafes Amount of strafes.
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param track Timer track.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @param avgvel Player's average velocity throughout the run.
|
||||
* @param maxvel Player's highest reached velocity.
|
||||
* @param timestamp System time of when player finished.
|
||||
* @param isbestreplay If the time is the new replay.
|
||||
* @param istoolong If the time is too long to save a replay if the time is a WR. Note: replays WON'T be full length if this is true.
|
||||
*
|
||||
* @return Return Plugin_Changed (or higher) to cause a copy of the replay to be saved. Return Plugin_Continue otherwise.
|
||||
*/
|
||||
forward Action Shavit_ShouldSaveReplayCopy(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong);
|
||||
|
||||
/**
|
||||
* Called when either a WR replay or a copy of a replay has been saved.
|
||||
* NOTE: Can be called with a delay after a run is finished due to asynchronous replay saving through extensions.
|
||||
*
|
||||
* @param client Client index. Can be 0 if the replay was saved asynchronously & the client disconnected super duper quick...
|
||||
* @param style Style the record was done on.
|
||||
* @param time Record time.
|
||||
* @param jumps Jumps amount.
|
||||
* @param strafes Amount of strafes.
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param track Timer track.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @param avgvel Player's average velocity throughout the run.
|
||||
* @param maxvel Player's highest reached velocity.
|
||||
* @param timestamp System time of when player finished.
|
||||
* @param isbestreplay If the time is the new replay.
|
||||
* @param istoolong If the time is too long to save a replay if the time is a WR. Note: replays WON'T be full length if this is true.
|
||||
* @param iscopy If the path points to a copy of the replay.
|
||||
* @param replaypath Path to the saved replay.
|
||||
* @param frames ArrayList of the player's frames in the replay.
|
||||
* @param preframes The number of preframes in the replay.
|
||||
* @param postframes The number of postframes in the replay.
|
||||
* @param name Player's name at the time of the replay.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnReplaySaved(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, bool isbestreplay, bool istoolong, bool iscopy, const char[] replaypath, ArrayList frames, int preframes, int postframes, const char[] name);
|
||||
|
||||
/**
|
||||
* Retrieves a client's frame count.
|
||||
*
|
||||
* @param client Client Index.
|
||||
*
|
||||
* @return Current number of frames.
|
||||
*/
|
||||
native int Shavit_GetClientFrameCount(int client);
|
||||
|
||||
/*
|
||||
* returns the number of preframes in the players current run.
|
||||
*
|
||||
* @param client Client index
|
||||
*
|
||||
* @return Preframe count
|
||||
*/
|
||||
native int Shavit_GetPlayerPreFrames(int client);
|
||||
|
||||
/*
|
||||
* Sets player's preframe length.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param PreFrame PreFrame length
|
||||
* @param TimerPreFrame Timer start frame length
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetPlayerPreFrames(int client, int PreFrame);
|
||||
|
||||
/**
|
||||
* Sets a player's replay recording frames from a provided ArrayList.
|
||||
* To be used by save states/TAS etc.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param data ArrayList with proper replay data.
|
||||
* @param cheapCloneHandle False means we duplicate the frames (ArrayList.Clone). True means we clone the handle to the frames (CloneHandle).
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetReplayData(int client, ArrayList data, bool cheapCloneHandle=false);
|
||||
|
||||
/**
|
||||
* Saves a player's replay recording frames (if exists) into an ArrayList.
|
||||
* To be used by save states/TAS etc.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param cheapCloneHandle False means we duplicate the frames (Arraylist.Clone). True means we clone the handle to the frames (CloneHandle). This is going to be used for peristent-data in shavit-misc so we don't allocate duplicate memory needlessly.
|
||||
*
|
||||
* @return ArrayList with proper replay data, or null if the player has no recorded data. Delete this handle when you're done with it.
|
||||
*/
|
||||
native ArrayList Shavit_GetReplayData(int client, bool cheapCloneHandle=false);
|
||||
|
||||
/**
|
||||
* Hijack the replay data so that this view angle will be used for the next ticks.
|
||||
* Use case is to make segmented runs look smoother.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param pitch Vertical view angle.
|
||||
* @param yaw Horizontal view angle.
|
||||
* @param ticks The number of ticks to hijack angles for. -1 will calculate the number of ticks based on the client's latency.
|
||||
* @param keeponstart Whether to continue hijacking angles even after someone restarts.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_HijackAngles(int client, float pitch, float yaw, int ticks = -1, bool keeponstart = false);
|
||||
|
||||
public SharedPlugin __pl_shavit_replay_recorder =
|
||||
{
|
||||
name = "shavit-replay-recorder",
|
||||
file = "shavit-replay-recorder.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_replay_recorder_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetClientFrameCount");
|
||||
MarkNativeAsOptional("Shavit_GetPlayerPreFrames");
|
||||
MarkNativeAsOptional("Shavit_SetPlayerPreFrames");
|
||||
MarkNativeAsOptional("Shavit_GetReplayData");
|
||||
MarkNativeAsOptional("Shavit_HijackAngles");
|
||||
MarkNativeAsOptional("Shavit_SetReplayData");
|
||||
}
|
||||
#endif
|
||||
103
addons/sourcemod/scripting/include/shavit/replay-stocks.sp
Normal file
103
addons/sourcemod/scripting/include/shavit/replay-stocks.sp
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* shavit's Timer - stocks used by the replay plugins
|
||||
* by: shavit
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
stock bool Shavit_ReplayEnabledStyle(int style)
|
||||
{
|
||||
return !Shavit_GetStyleSettingBool(style, "unranked") && !Shavit_GetStyleSettingBool(style, "noreplay");
|
||||
}
|
||||
|
||||
stock void Shavit_GetReplayFilePath(int style, int track, const char[] mapname, const char[] replayfolder, char sPath[PLATFORM_MAX_PATH])
|
||||
{
|
||||
char sTrack[4];
|
||||
FormatEx(sTrack, 4, "_%d", track);
|
||||
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d/%s%s.replay", replayfolder, style, mapname, (track > 0)? sTrack:"");
|
||||
}
|
||||
|
||||
stock bool Shavit_GetReplayFolderPath_Stock(char buffer[PLATFORM_MAX_PATH])
|
||||
{
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-replay.cfg");
|
||||
|
||||
KeyValues kv = new KeyValues("shavit-replay");
|
||||
|
||||
if (!kv.ImportFromFile(sPath))
|
||||
{
|
||||
delete kv;
|
||||
return false;
|
||||
}
|
||||
|
||||
kv.GetString("replayfolder", buffer, PLATFORM_MAX_PATH, "{SM}/data/replaybot");
|
||||
|
||||
if (StrContains(buffer, "{SM}") != -1)
|
||||
{
|
||||
ReplaceString(buffer, PLATFORM_MAX_PATH, "{SM}/", "");
|
||||
BuildPath(Path_SM, buffer, PLATFORM_MAX_PATH, "%s", buffer);
|
||||
}
|
||||
|
||||
delete kv;
|
||||
return true;
|
||||
}
|
||||
|
||||
stock void Shavit_Replay_CreateDirectories(const char[] sReplayFolder, int styles)
|
||||
{
|
||||
if (!DirExists(sReplayFolder) && !CreateDirectory(sReplayFolder, 511))
|
||||
{
|
||||
SetFailState("Failed to create replay folder (%s). Make sure you have file permissions", sReplayFolder);
|
||||
}
|
||||
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/copy", sReplayFolder);
|
||||
|
||||
if (!DirExists(sPath) && !CreateDirectory(sPath, 511))
|
||||
{
|
||||
SetFailState("Failed to create replay copy folder (%s). Make sure you have file permissions", sPath);
|
||||
}
|
||||
|
||||
for(int i = 0; i < styles; i++)
|
||||
{
|
||||
if (!Shavit_ReplayEnabledStyle(i))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d", sReplayFolder, i);
|
||||
|
||||
if (!DirExists(sPath) && !CreateDirectory(sPath, 511))
|
||||
{
|
||||
SetFailState("Failed to create replay style folder (%s). Make sure you have file permissions", sPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Test to see if replay file creation works
|
||||
FormatEx(sPath, sizeof(sPath), "%s/0/faketestfile_69.replay", sReplayFolder);
|
||||
File fTest = OpenFile(sPath, "wb+");
|
||||
|
||||
// Check if the file was opened successfully for writing
|
||||
if (fTest == null)
|
||||
{
|
||||
SetFailState("Failed to write to replay folder (%s). Make sure you have file permissions.", sReplayFolder);
|
||||
}
|
||||
else
|
||||
{
|
||||
// File was opened successfully, now close it
|
||||
CloseHandle(fTest);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
97
addons/sourcemod/scripting/include/shavit/steamid-stocks.inc
Normal file
97
addons/sourcemod/scripting/include/shavit/steamid-stocks.inc
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Steam ID handling stocks
|
||||
* by: rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _steamid_stocks_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _steamid_stocks_included
|
||||
|
||||
|
||||
// Retrieves accountid from STEAM_X:Y:Z, [U:1:123], and 765xxxxxxxxxxxxxx
|
||||
stock int SteamIDToAccountID(const char[] sInput)
|
||||
{
|
||||
char sSteamID[32];
|
||||
strcopy(sSteamID, sizeof(sSteamID), sInput);
|
||||
ReplaceString(sSteamID, 32, "\"", "");
|
||||
TrimString(sSteamID);
|
||||
|
||||
if (StrContains(sSteamID, "STEAM_") != -1)
|
||||
{
|
||||
ReplaceString(sSteamID, 32, "STEAM_", "");
|
||||
|
||||
char parts[3][11];
|
||||
ExplodeString(sSteamID, ":", parts, 3, 11);
|
||||
|
||||
// Let X, Y and Z constants be defined by the SteamID: STEAM_X:Y:Z.
|
||||
// Using the formula W=Z*2+Y, a SteamID can be converted:
|
||||
return StringToInt(parts[2]) * 2 + StringToInt(parts[1]);
|
||||
}
|
||||
else if (StrContains(sSteamID, "U:1:") != -1)
|
||||
{
|
||||
ReplaceString(sSteamID, 32, "[", "");
|
||||
ReplaceString(sSteamID, 32, "U:1:", "");
|
||||
ReplaceString(sSteamID, 32, "]", "");
|
||||
|
||||
return StringToInt(sSteamID);
|
||||
}
|
||||
else if (StrContains(sSteamID, "765") == 0)
|
||||
{
|
||||
return SteamID64ToAccountID(sSteamID);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
stock void AccountIDToSteamID64Num(int accountid, int num[2])
|
||||
{
|
||||
num[0] = accountid;
|
||||
// universe | type | instance
|
||||
num[1] = (1 << 24) | (1 << 20) | 1; // 0x01100001
|
||||
}
|
||||
|
||||
stock void AccountIDToSteamID64(int accountid, char[] buf, int buflen)
|
||||
{
|
||||
int num[2];
|
||||
AccountIDToSteamID64Num(accountid, num);
|
||||
SteamID64ToString(num, buf, buflen);
|
||||
}
|
||||
|
||||
stock void AccountIDToSteamID2(int accountid, char[] buf, int buflen)
|
||||
{
|
||||
FormatEx(buf, buflen, "STEAM_0:%d:%d", accountid&1, (accountid>>1) & 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
stock void AccountIDToSteamID3(int accountid, char[] buf, int buflen)
|
||||
{
|
||||
FormatEx(buf, buflen, "[U:1:%u]", accountid);
|
||||
}
|
||||
|
||||
stock void SteamID64ToString(const int num[2], char[] buf, int buflen)
|
||||
{
|
||||
Int64ToString(num, buf, buflen);
|
||||
}
|
||||
|
||||
stock int SteamID64ToAccountID(const char[] steamid64)
|
||||
{
|
||||
int num[2];
|
||||
StringToInt64(steamid64, num);
|
||||
return num[0];
|
||||
}
|
||||
728
addons/sourcemod/scripting/include/shavit/style-settings.sp
Normal file
728
addons/sourcemod/scripting/include/shavit/style-settings.sp
Normal file
@ -0,0 +1,728 @@
|
||||
/*
|
||||
* shavit's Timer - Style settings
|
||||
* by: shavit, KiD Fearless, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma newdecls required
|
||||
#pragma semicolon 1
|
||||
|
||||
#define SS_VAL_SZ 128
|
||||
#define SS_KEY_SZ 64
|
||||
|
||||
enum struct style_setting_t
|
||||
{
|
||||
float f;
|
||||
char str[SS_VAL_SZ];
|
||||
}
|
||||
|
||||
Handle gH_Forwards_OnStyleConfigLoaded = null;
|
||||
|
||||
bool gB_StyleCommandsRegistered = false;
|
||||
|
||||
int gI_Styles = 0;
|
||||
int gI_OrderedStyles[STYLE_LIMIT];
|
||||
int gI_CurrentParserIndex = 0;
|
||||
|
||||
StringMap gSM_StyleKeys[STYLE_LIMIT];
|
||||
StringMap gSM_StyleCommands = null;
|
||||
StringMap gSM_StyleKeysSet = null;
|
||||
|
||||
int gI_StyleFlag[STYLE_LIMIT];
|
||||
char gS_StyleOverride[STYLE_LIMIT][32];
|
||||
|
||||
void Shavit_Style_Settings_Natives()
|
||||
{
|
||||
CreateNative("Shavit_GetOrderedStyles", Native_GetOrderedStyles);
|
||||
CreateNative("Shavit_GetStyleCount", Native_GetStyleCount);
|
||||
|
||||
CreateNative("Shavit_GetStyleSetting", Native_GetStyleSetting);
|
||||
CreateNative("Shavit_GetStyleSettingInt", Native_GetStyleSettingInt);
|
||||
CreateNative("Shavit_GetStyleSettingBool", Native_GetStyleSettingBool);
|
||||
CreateNative("Shavit_GetStyleSettingFloat", Native_GetStyleSettingFloat);
|
||||
|
||||
CreateNative("Shavit_HasStyleAccess", Native_HasStyleAccess);
|
||||
CreateNative("Shavit_HasStyleSetting", Native_HasStyleSetting);
|
||||
|
||||
CreateNative("Shavit_SetStyleSetting", Native_SetStyleSetting);
|
||||
CreateNative("Shavit_SetStyleSettingInt", Native_SetStyleSettingInt);
|
||||
CreateNative("Shavit_SetStyleSettingBool", Native_SetStyleSettingBool);
|
||||
CreateNative("Shavit_SetStyleSettingFloat", Native_SetStyleSettingFloat);
|
||||
|
||||
CreateNative("Shavit_GetStyleStrings", Native_GetStyleStrings);
|
||||
CreateNative("Shavit_GetStyleStringsStruct", Native_GetStyleStringsStruct);
|
||||
|
||||
gSM_StyleCommands = new StringMap();
|
||||
}
|
||||
|
||||
void Shavit_Style_Settings_Forwards()
|
||||
{
|
||||
gH_Forwards_OnStyleConfigLoaded = CreateGlobalForward("Shavit_OnStyleConfigLoaded", ET_Event, Param_Cell);
|
||||
}
|
||||
|
||||
bool LoadStyles()
|
||||
{
|
||||
for (int i = 0; i < STYLE_LIMIT; i++)
|
||||
{
|
||||
delete gSM_StyleKeys[i];
|
||||
}
|
||||
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-styles.cfg");
|
||||
|
||||
SMCParser parser = new SMCParser();
|
||||
parser.OnEnterSection = OnStyleEnterSection;
|
||||
parser.OnLeaveSection = OnStyleLeaveSection;
|
||||
parser.OnKeyValue = OnStyleKeyValue;
|
||||
parser.ParseFile(sPath);
|
||||
delete parser;
|
||||
|
||||
for (int i = 0; i < gI_Styles; i++)
|
||||
{
|
||||
if (gSM_StyleKeys[i] == null)
|
||||
{
|
||||
SetFailState("Missing style index %d. Highest index is %d. Fix addons/sourcemod/configs/shavit-styles.cfg", i, gI_Styles-1);
|
||||
}
|
||||
}
|
||||
|
||||
gB_StyleCommandsRegistered = true;
|
||||
|
||||
SortCustom1D(gI_OrderedStyles, gI_Styles, SortAscending_StyleOrder);
|
||||
|
||||
Call_StartForward(gH_Forwards_OnStyleConfigLoaded);
|
||||
Call_PushCell(gI_Styles);
|
||||
Call_Finish();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public SMCResult OnStyleEnterSection(SMCParser smc, const char[] name, bool opt_quotes)
|
||||
{
|
||||
// styles key
|
||||
if (!IsCharNumeric(name[0]))
|
||||
{
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
gI_CurrentParserIndex = StringToInt(name);
|
||||
|
||||
if (gSM_StyleKeys[gI_CurrentParserIndex] != null)
|
||||
{
|
||||
SetFailState("Style index %d (%s) already parsed. Stop using the same index for multiple styles. Fix addons/sourcemod/configs/shavit-styles.cfg", gI_CurrentParserIndex, name);
|
||||
}
|
||||
|
||||
if (gI_CurrentParserIndex >= STYLE_LIMIT)
|
||||
{
|
||||
SetFailState("Style index %d (%s) too high (limit %d). Fix addons/sourcemod/configs/shavit-styles.cfg", gI_CurrentParserIndex, name, STYLE_LIMIT);
|
||||
}
|
||||
|
||||
if (gI_Styles <= gI_CurrentParserIndex)
|
||||
{
|
||||
gI_Styles = gI_CurrentParserIndex + 1;
|
||||
}
|
||||
|
||||
delete gSM_StyleKeysSet;
|
||||
gSM_StyleKeysSet = new StringMap();
|
||||
|
||||
gSM_StyleKeys[gI_CurrentParserIndex] = new StringMap();
|
||||
|
||||
SetStyleSetting(gI_CurrentParserIndex, "name", "<MISSING STYLE NAME>");
|
||||
SetStyleSetting(gI_CurrentParserIndex, "shortname", "<MISSING SHORT STYLE NAME>");
|
||||
SetStyleSetting(gI_CurrentParserIndex, "htmlcolor", "<MISSING STYLE HTML COLOR>");
|
||||
SetStyleSetting(gI_CurrentParserIndex, "command", "");
|
||||
SetStyleSetting(gI_CurrentParserIndex, "clantag", "<MISSING STYLE CLAN TAG>");
|
||||
SetStyleSetting(gI_CurrentParserIndex, "specialstring", "");
|
||||
SetStyleSetting(gI_CurrentParserIndex, "permission", "");
|
||||
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "autobhop", 1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "easybhop", 1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "prespeed", 0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "prespeed_ez_vel", 0.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "velocity_limit", 0.0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "bunnyhopping", 1);
|
||||
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "prespeed_type", -1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "blockprejump", -1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "nozaxisspeed", -1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "restrictnoclip", -1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "startinair", 0);
|
||||
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "airaccelerate", 1000.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "runspeed", 260.00);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "maxprestrafe", 0.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "gravity", 1.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "speed", 1.0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "halftime", 0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "timescale", 1.0);
|
||||
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "tas", 0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "tas_timescale", 0.0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "autostrafe", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "autoprestrafe", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "edgejump", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "autojumponstart", 0);
|
||||
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "force_timescale", 0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "velocity", 1.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "bonus_velocity", 0.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "min_velocity", 0.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "jump_multiplier", 0.0);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "jump_bonus", 0.0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_w", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_a", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_s", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_d", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_use", 0);
|
||||
SetStyleSettingBool (gI_CurrentParserIndex, "a_or_d_only", false);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "force_hsw", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_pleft", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_pright", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "block_pstrafe", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "unranked", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "noreplay", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "sync", 1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "strafe_count_w", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "strafe_count_a", 1);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "strafe_count_s", 0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "strafe_count_d", 1);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "rankingmultiplier", 1.0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "special", 0);
|
||||
|
||||
// bhop_freedompuppies on css auto is like 4.2s. prob lower on csgo so 3.5
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "minimum_time", 3.5);
|
||||
// bhop_uc_minecraft_beta2 on css auto has a 0.62s time
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "minimum_time_bonus", 0.5);
|
||||
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "ordering", gI_CurrentParserIndex);
|
||||
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "inaccessible", 0);
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "enabled", 1);
|
||||
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "kzcheckpoints", 0);
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "kzcheckpoints_ladders", 0);
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "kzcheckpoints_ontele", -1);
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "kzcheckpoints_onstart", -1);
|
||||
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "segments", 0);
|
||||
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "force_groundkeys", 0);
|
||||
|
||||
gI_OrderedStyles[gI_CurrentParserIndex] = gI_CurrentParserIndex;
|
||||
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
public SMCResult OnStyleLeaveSection(SMCParser smc)
|
||||
{
|
||||
if (gI_CurrentParserIndex == -1)
|
||||
{
|
||||
// OnStyleLeaveSection can be called back to back.
|
||||
// And does for when hitting the last style!
|
||||
// So we set gI_CurrentParserIndex to -1 at the end of this function.
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
// if this style is disabled, we will force certain settings
|
||||
if (GetStyleSettingInt(gI_CurrentParserIndex, "enabled") <= 0)
|
||||
{
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "noreplay", 1);
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "rankingmultiplier", 0.0);
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "inaccessible", 1);
|
||||
}
|
||||
|
||||
if (GetStyleSettingInt(gI_CurrentParserIndex, "kzcheckpoints_onstart") != -1)
|
||||
{
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "inaccessible", 1);
|
||||
}
|
||||
|
||||
if (GetStyleSettingBool(gI_CurrentParserIndex, "halftime"))
|
||||
{
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "timescale", 0.5);
|
||||
}
|
||||
|
||||
if (GetStyleSettingFloat(gI_CurrentParserIndex, "timescale") <= 0.0)
|
||||
{
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "timescale", 1.0);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Setting it here so that we can reference the timescale setting.
|
||||
if (!HasStyleSetting(gI_CurrentParserIndex, "force_timescale"))
|
||||
{
|
||||
if (GetStyleSettingFloat(gI_CurrentParserIndex, "timescale") == 1.0)
|
||||
{
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "force_timescale", 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStyleSettingInt(gI_CurrentParserIndex, "force_timescale", 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (GetStyleSettingInt(gI_CurrentParserIndex, "prespeed") > 0 || GetStyleSettingInt(gI_CurrentParserIndex, "prespeed_type") > 0)
|
||||
{
|
||||
bool value;
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("minimum_time", value))
|
||||
{
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "minimum_time", 0.01);
|
||||
}
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("minimum_time_bonus", value))
|
||||
{
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "minimum_time_bonus", 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
char sStyleCommand[SS_VAL_SZ];
|
||||
GetStyleSetting(gI_CurrentParserIndex, "command", sStyleCommand, sizeof(sStyleCommand));
|
||||
char sName[64];
|
||||
GetStyleSetting(gI_CurrentParserIndex, "name", sName, sizeof(sName));
|
||||
|
||||
if (!gB_StyleCommandsRegistered && strlen(sStyleCommand) > 0 && !GetStyleSettingBool(gI_CurrentParserIndex, "inaccessible"))
|
||||
{
|
||||
char sStyleCommands[32][32];
|
||||
int iCommands = ExplodeString(sStyleCommand, ";", sStyleCommands, 32, 32, false);
|
||||
|
||||
char sDescription[128];
|
||||
FormatEx(sDescription, 128, "Change style to %s.", sName);
|
||||
|
||||
for (int x = 0; x < iCommands; x++)
|
||||
{
|
||||
TrimString(sStyleCommands[x]);
|
||||
StripQuotes(sStyleCommands[x]);
|
||||
|
||||
char sCommand[32];
|
||||
FormatEx(sCommand, 32, "sm_%s", sStyleCommands[x]);
|
||||
|
||||
gSM_StyleCommands.SetValue(sCommand, gI_CurrentParserIndex);
|
||||
|
||||
RegConsoleCmd(sCommand, Command_StyleChange, sDescription);
|
||||
}
|
||||
}
|
||||
|
||||
char sPermission[64];
|
||||
GetStyleSetting(gI_CurrentParserIndex, "permission", sPermission, sizeof(sPermission));
|
||||
|
||||
if (StrContains(sPermission, ";") != -1)
|
||||
{
|
||||
char sText[2][32];
|
||||
int iCount = ExplodeString(sPermission, ";", sText, 2, 32);
|
||||
|
||||
AdminFlag flag = Admin_Reservation;
|
||||
|
||||
if(FindFlagByChar(sText[0][0], flag))
|
||||
{
|
||||
gI_StyleFlag[gI_CurrentParserIndex] = FlagToBit(flag);
|
||||
}
|
||||
|
||||
strcopy(gS_StyleOverride[gI_CurrentParserIndex], 32, (iCount >= 2)? sText[1]:"");
|
||||
}
|
||||
else if (strlen(sPermission) > 0)
|
||||
{
|
||||
AdminFlag flag = Admin_Reservation;
|
||||
|
||||
if(FindFlagByChar(sPermission[0], flag))
|
||||
{
|
||||
gI_StyleFlag[gI_CurrentParserIndex] = FlagToBit(flag);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasStyleSetting(gI_CurrentParserIndex, "specialstring"))
|
||||
{
|
||||
char value[SS_VAL_SZ];
|
||||
GetStyleSetting(gI_CurrentParserIndex, "specialstring", value, sizeof(value));
|
||||
|
||||
char keys[32][32];
|
||||
int count = ExplodeString(value, ";", keys, 32, 32, false);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
TrimString(keys[i]);
|
||||
|
||||
char pair[2][32];
|
||||
ExplodeString(keys[i], "=", pair, 2, 32, false);
|
||||
|
||||
TrimString(pair[0]);
|
||||
TrimString(pair[1]);
|
||||
|
||||
if (!pair[0][0])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LowercaseString(pair[0]);
|
||||
|
||||
#if 0
|
||||
if (HasStyleSetting(gI_CurrentParserIndex, pair[0]))
|
||||
#else
|
||||
bool x;
|
||||
if (gSM_StyleKeysSet.GetValue(pair[0], x))
|
||||
#endif
|
||||
{
|
||||
char asdf[SS_VAL_SZ];
|
||||
GetStyleSetting(gI_CurrentParserIndex, pair[0], asdf, sizeof(asdf));
|
||||
char name[SS_VAL_SZ];
|
||||
GetStyleSetting(gI_CurrentParserIndex, "name", name, sizeof(name));
|
||||
LogError("Style %s (%d) has '%s' set (%s) but is also trying to set it from specialstring (%s).", name, gI_CurrentParserIndex, pair[0], asdf, pair[1][0] ? pair[1] : "1");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pair[1][0])
|
||||
{
|
||||
SetStyleSetting(gI_CurrentParserIndex, pair[0], pair[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStyleSettingBool(gI_CurrentParserIndex, pair[0], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GetStyleSettingBool(gI_CurrentParserIndex, "tas"))
|
||||
{
|
||||
bool x;
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("tas_timescale", x))
|
||||
{
|
||||
SetStyleSettingFloat(gI_CurrentParserIndex, "tas_timescale", -1.0);
|
||||
}
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("autostrafe", x))
|
||||
{
|
||||
SetStyleSettingInt (gI_CurrentParserIndex, "autostrafe", 1);
|
||||
}
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("autoprestrafe", x))
|
||||
{
|
||||
SetStyleSettingBool (gI_CurrentParserIndex, "autoprestrafe", true);
|
||||
}
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("edgejump", x))
|
||||
{
|
||||
SetStyleSettingBool (gI_CurrentParserIndex, "edgejump", true);
|
||||
}
|
||||
|
||||
if (!gSM_StyleKeysSet.GetValue("autojumponstart", x))
|
||||
{
|
||||
SetStyleSettingBool (gI_CurrentParserIndex, "autojumponstart", true);
|
||||
}
|
||||
}
|
||||
|
||||
delete gSM_StyleKeysSet;
|
||||
gI_CurrentParserIndex = -1;
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
public SMCResult OnStyleKeyValue(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes)
|
||||
{
|
||||
SetStyleSetting(gI_CurrentParserIndex, key, value);
|
||||
gSM_StyleKeysSet.SetValue(key, true);
|
||||
|
||||
return SMCParse_Continue;
|
||||
}
|
||||
|
||||
public int SortAscending_StyleOrder(int index1, int index2, const int[] array, Handle hndl)
|
||||
{
|
||||
return GetStyleSettingInt(index1, "ordering") - GetStyleSettingInt(index2, "ordering");
|
||||
}
|
||||
|
||||
public Action Command_StyleChange(int client, int args)
|
||||
{
|
||||
char sCommand[128];
|
||||
GetCmdArg(0, sCommand, 128);
|
||||
|
||||
int style = 0;
|
||||
|
||||
if (gSM_StyleCommands.GetValue(sCommand, style))
|
||||
{
|
||||
ChangeClientStyle(client, style, true);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public int Native_GetStyleCount(Handle handler, int numParams)
|
||||
{
|
||||
return (gI_Styles > 0)? gI_Styles:-1;
|
||||
}
|
||||
|
||||
public int Native_GetOrderedStyles(Handle handler, int numParams)
|
||||
{
|
||||
return SetNativeArray(1, gI_OrderedStyles, GetNativeCell(2));
|
||||
}
|
||||
|
||||
public int Native_GetStyleSetting(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[64];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
int maxlength = GetNativeCell(4);
|
||||
|
||||
char sValue[SS_VAL_SZ];
|
||||
bool ret = GetStyleSetting(style, sKey, sValue, sizeof(sValue));
|
||||
|
||||
SetNativeString(3, sValue, maxlength);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GetStyleSetting(int style, const char[] key, char[] value, int size)
|
||||
{
|
||||
style_setting_t ss;
|
||||
|
||||
if (gSM_StyleKeys[style].GetArray(key, ss, sizeof(ss)))
|
||||
{
|
||||
strcopy(value, size, ss.str);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int Native_GetStyleSettingInt(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[64];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
return GetStyleSettingInt(style, sKey);
|
||||
}
|
||||
|
||||
int GetStyleSettingInt(int style, char[] key)
|
||||
{
|
||||
float val[1];
|
||||
gSM_StyleKeys[style].GetArray(key, val, 1);
|
||||
return RoundToFloor(val[0]);
|
||||
}
|
||||
|
||||
public int Native_GetStyleSettingBool(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[256];
|
||||
GetNativeString(2, sKey, 256);
|
||||
|
||||
return GetStyleSettingBool(style, sKey);
|
||||
}
|
||||
|
||||
bool GetStyleSettingBool(int style, char[] key)
|
||||
{
|
||||
return GetStyleSettingFloat(style, key) != 0.0;
|
||||
}
|
||||
|
||||
public any Native_GetStyleSettingFloat(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[SS_KEY_SZ];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
return GetStyleSettingFloat(style, sKey);
|
||||
}
|
||||
|
||||
float GetStyleSettingFloat(int style, char[] key)
|
||||
{
|
||||
float val[1];
|
||||
gSM_StyleKeys[style].GetArray(key, val, 1);
|
||||
return val[0];
|
||||
}
|
||||
|
||||
public any Native_HasStyleSetting(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[SS_KEY_SZ];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
return HasStyleSetting(style, sKey);
|
||||
}
|
||||
|
||||
bool HasStyleSetting(int style, char[] key)
|
||||
{
|
||||
return gSM_StyleKeys[style].ContainsKey(key);
|
||||
}
|
||||
|
||||
bool SetStyleSetting(int style, const char[] key, const char[] value, bool replace=true)
|
||||
{
|
||||
style_setting_t ss;
|
||||
ss.f = StringToFloat(value);
|
||||
int bytes = 4 + 1 + strcopy(ss.str, sizeof(ss.str), value);
|
||||
return gSM_StyleKeys[style].SetArray(key, ss, ByteCountToCells(bytes), replace);
|
||||
}
|
||||
|
||||
public any Native_SetStyleSetting(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[SS_KEY_SZ];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
char sValue[SS_VAL_SZ];
|
||||
GetNativeString(3, sValue, sizeof(sValue));
|
||||
|
||||
bool replace = GetNativeCell(4);
|
||||
|
||||
return SetStyleSetting(style, sKey, sValue, replace);
|
||||
}
|
||||
|
||||
public any Native_SetStyleSettingFloat(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[SS_KEY_SZ];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
float fValue = GetNativeCell(3);
|
||||
|
||||
bool replace = GetNativeCell(4);
|
||||
|
||||
return SetStyleSettingFloat(style, sKey, fValue, replace);
|
||||
}
|
||||
|
||||
bool SetStyleSettingFloat(int style, char[] key, float value, bool replace=true)
|
||||
{
|
||||
style_setting_t ss;
|
||||
ss.f = value;
|
||||
int strcells = FloatToString(value, ss.str, sizeof(ss.str));
|
||||
return gSM_StyleKeys[style].SetArray(key, ss, strcells+1, replace);
|
||||
}
|
||||
|
||||
public any Native_SetStyleSettingBool(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[SS_KEY_SZ];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
bool value = GetNativeCell(3);
|
||||
|
||||
bool replace = GetNativeCell(4);
|
||||
|
||||
return SetStyleSettingBool(style, sKey, value, replace);
|
||||
}
|
||||
|
||||
bool SetStyleSettingBool(int style, char[] key, bool value, bool replace=true)
|
||||
{
|
||||
return SetStyleSettingFloat(style, key, value ? 1.0 : 0.0, replace);
|
||||
}
|
||||
|
||||
public any Native_SetStyleSettingInt(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
char sKey[SS_KEY_SZ];
|
||||
GetNativeString(2, sKey, sizeof(sKey));
|
||||
|
||||
int value = GetNativeCell(3);
|
||||
|
||||
bool replace = GetNativeCell(4);
|
||||
|
||||
return SetStyleSettingInt(style, sKey, value, replace);
|
||||
}
|
||||
|
||||
bool SetStyleSettingInt(int style, char[] key, int value, bool replace=true)
|
||||
{
|
||||
style_setting_t ss;
|
||||
ss.f = float(value);
|
||||
int strcells = IntToString(value, ss.str, sizeof(ss.str));
|
||||
return gSM_StyleKeys[style].SetArray(key, ss, strcells+1, replace);
|
||||
}
|
||||
|
||||
public int Native_GetStyleStrings(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
int type = GetNativeCell(2);
|
||||
int size = GetNativeCell(4);
|
||||
char sValue[SS_VAL_SZ];
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case sStyleName:
|
||||
{
|
||||
GetStyleSetting(style, "name", sValue, sizeof(stylestrings_t::sStyleName));
|
||||
}
|
||||
case sShortName:
|
||||
{
|
||||
GetStyleSetting(style, "shortname", sValue, sizeof(stylestrings_t::sShortName));
|
||||
}
|
||||
case sHTMLColor:
|
||||
{
|
||||
GetStyleSetting(style, "htmlcolor", sValue, sizeof(stylestrings_t::sHTMLColor));
|
||||
}
|
||||
case sChangeCommand:
|
||||
{
|
||||
GetStyleSetting(style, "command", sValue, sizeof(stylestrings_t::sChangeCommand));
|
||||
}
|
||||
case sClanTag:
|
||||
{
|
||||
GetStyleSetting(style, "clantag", sValue, sizeof(stylestrings_t::sClanTag));
|
||||
}
|
||||
case sSpecialString:
|
||||
{
|
||||
GetStyleSetting(style, "specialstring", sValue, sizeof(stylestrings_t::sSpecialString));
|
||||
}
|
||||
case sStylePermission:
|
||||
{
|
||||
GetStyleSetting(style, "permission", sValue, sizeof(stylestrings_t::sStylePermission));
|
||||
}
|
||||
default:
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return SetNativeString(3, sValue, size);
|
||||
}
|
||||
|
||||
public int Native_GetStyleStringsStruct(Handle plugin, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(1);
|
||||
|
||||
if (GetNativeCell(3) != sizeof(stylestrings_t))
|
||||
{
|
||||
return ThrowNativeError(200, "stylestrings_t does not match latest(got %i expected %i). Please update your includes and recompile your plugins", GetNativeCell(3), sizeof(stylestrings_t));
|
||||
}
|
||||
|
||||
stylestrings_t strings;
|
||||
GetStyleSetting(style, "name", strings.sStyleName, sizeof(strings.sStyleName));
|
||||
GetStyleSetting(style, "shortname", strings.sShortName, sizeof(strings.sShortName));
|
||||
GetStyleSetting(style, "htmlcolor", strings.sHTMLColor, sizeof(strings.sHTMLColor));
|
||||
GetStyleSetting(style, "command", strings.sChangeCommand, sizeof(strings.sChangeCommand));
|
||||
GetStyleSetting(style, "clantag", strings.sClanTag, sizeof(strings.sClanTag));
|
||||
GetStyleSetting(style, "specialstring", strings.sSpecialString, sizeof(strings.sSpecialString));
|
||||
GetStyleSetting(style, "permission", strings.sStylePermission, sizeof(strings.sStylePermission));
|
||||
|
||||
return SetNativeArray(2, strings, sizeof(stylestrings_t));
|
||||
}
|
||||
|
||||
public int Native_HasStyleAccess(Handle handler, int numParams)
|
||||
{
|
||||
int style = GetNativeCell(2);
|
||||
|
||||
if (GetStyleSettingBool(style, "inaccessible") || GetStyleSettingInt(style, "enabled") <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckCommandAccess(GetNativeCell(1), (strlen(gS_StyleOverride[style]) > 0)? gS_StyleOverride[style]:"<none>", gI_StyleFlag[style]);
|
||||
}
|
||||
269
addons/sourcemod/scripting/include/shavit/tas-oblivious.inc
Normal file
269
addons/sourcemod/scripting/include/shavit/tas-oblivious.inc
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* tas-oblivious.inc file
|
||||
* by: oblivious
|
||||
*
|
||||
* Originally from autogain (https://github.com/defiy/autogain) Mirror: https://github.com/PMArkive/autogain
|
||||
* and edited to be part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_tas_oblivious_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_tas_oblivious_included
|
||||
|
||||
|
||||
stock float normalize_yaw(float _yaw)
|
||||
{
|
||||
while (_yaw > 180.0) _yaw -= 360.0;
|
||||
while (_yaw < -180.0) _yaw += 360.0; return _yaw;
|
||||
}
|
||||
|
||||
stock float get_length_2d(float vec[3])
|
||||
{
|
||||
return SquareRoot(vec[0] * vec[0] + vec[1] * vec[1]);
|
||||
}
|
||||
|
||||
stock float ground_delta_opt(int client, float angles[3], float move[3], float surface_friction,
|
||||
float accelerate, float friction, float stopspeed)
|
||||
{
|
||||
float fore[3], side[3], wishvel[3];
|
||||
float wishspeed;
|
||||
|
||||
GetAngleVectors(angles, fore, side, ZERO_VECTOR);
|
||||
|
||||
fore[2] = 0.0;
|
||||
side[2] = 0.0;
|
||||
NormalizeVector(fore, fore);
|
||||
NormalizeVector(side, side);
|
||||
|
||||
wishvel[2] = 0.0;
|
||||
for(int i = 0; i < 2; i++)
|
||||
wishvel[i] = fore[i] * move[0] + side[i] * move[1];
|
||||
|
||||
wishspeed = GetVectorLength(wishvel);
|
||||
|
||||
float flMaxSpeed = Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "runspeed");
|
||||
if(wishspeed > flMaxSpeed && flMaxSpeed != 0.0) wishspeed = flMaxSpeed;
|
||||
|
||||
float velocity[3];
|
||||
GetEntPropVector(client, Prop_Data, "m_vecVelocity", velocity);
|
||||
float speed = GetVectorLength(velocity);
|
||||
|
||||
float interval_per_tick = GetTickInterval();
|
||||
|
||||
float accelspeed = accelerate * wishspeed * interval_per_tick * surface_friction;
|
||||
|
||||
float control = speed;
|
||||
if (control < stopspeed) control = stopspeed;
|
||||
float drop = control * friction * interval_per_tick * surface_friction;
|
||||
|
||||
float newspeed = speed - drop;
|
||||
if (newspeed < 0.0) newspeed = 0.0;
|
||||
|
||||
float tmp = wishspeed - accelspeed;
|
||||
|
||||
if (tmp <= newspeed)
|
||||
{
|
||||
float gamma = RadToDeg(ArcCosine(tmp / newspeed));
|
||||
float vel_dir_ang = RadToDeg(ArcTangent2(velocity[1], velocity[0]));
|
||||
|
||||
vel_dir_ang = normalize_yaw(vel_dir_ang);
|
||||
|
||||
float accel_yaw = RadToDeg(ArcTangent2(wishvel[1], wishvel[0]));
|
||||
|
||||
float diffm = vel_dir_ang - gamma;
|
||||
float diffp = vel_dir_ang + gamma;
|
||||
|
||||
diffm = normalize_yaw(diffm - accel_yaw);
|
||||
diffp = normalize_yaw(diffp - accel_yaw);
|
||||
|
||||
float delta_opt = 0.0;
|
||||
if (FloatAbs(diffm) <= FloatAbs(diffp))
|
||||
delta_opt = -diffm;
|
||||
else
|
||||
delta_opt = -diffp;
|
||||
delta_opt = normalize_yaw(delta_opt);
|
||||
|
||||
return delta_opt;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
stock Action ObliviousOnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2],
|
||||
float air_accelerate, float surface_friction, float flAirSpeedCap, float flMaxMove,
|
||||
bool no_speed_loss)
|
||||
{
|
||||
float flMaxSpeed = Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "runspeed");
|
||||
|
||||
bool set_back = true;
|
||||
if (vel[0] != 0.0 || vel[1] != 0.0)
|
||||
set_back = false;
|
||||
if (set_back)
|
||||
vel[1] = flMaxMove;
|
||||
|
||||
float velocity[3], velocity_opt[3];
|
||||
GetEntPropVector(client, Prop_Data, "m_vecVelocity", velocity);
|
||||
|
||||
velocity_opt[0] = velocity[0]; velocity_opt[1] = velocity[1]; velocity_opt[2] = velocity[2];
|
||||
|
||||
float vel_yaw = ArcTangent2(velocity[1], velocity[0]) * 180.0 / FLOAT_PI;
|
||||
|
||||
float delta_opt = -normalize_yaw(angles[1] - vel_yaw);
|
||||
|
||||
if (get_length_2d(velocity) == 0.0)
|
||||
delta_opt = 90.0;
|
||||
|
||||
if (vel[0] != 0.0 && vel[1] == 0.0)
|
||||
{
|
||||
float sign = vel[0] > 0.0 ? -1.0 : 1.0;
|
||||
delta_opt = -normalize_yaw(angles[1] - (vel_yaw + (90.0 * sign)));
|
||||
}
|
||||
if (vel[0] != 0.0 && vel[1] != 0.0)
|
||||
{
|
||||
float sign = vel[1] > 0.0 ? -1.0 : 1.0;
|
||||
if (vel[0] < 0.0)
|
||||
sign = -sign;
|
||||
delta_opt = -normalize_yaw(angles[1] - (vel_yaw + (45.0 * sign)));
|
||||
}
|
||||
|
||||
float frac = 1.0;
|
||||
|
||||
if (buttons & IN_DUCK && no_speed_loss)
|
||||
frac = 0.34;
|
||||
|
||||
float _addspeed = 0.0;
|
||||
if (!set_back)
|
||||
{
|
||||
float _fore[3], _side[3], _wishvel[3], _wishdir[3];
|
||||
float _wishspeed, _wishspd, _currentspeed;
|
||||
|
||||
GetAngleVectors(angles, _fore, _side, ZERO_VECTOR);
|
||||
|
||||
_fore[2] = 0.0; _side[2] = 0.0;
|
||||
NormalizeVector(_fore, _fore); NormalizeVector(_side, _side);
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
_wishvel[i] = _fore[i] * vel[0] * frac + _side[i] * vel[1] * frac;
|
||||
|
||||
_wishspeed = NormalizeVector(_wishvel, _wishdir);
|
||||
|
||||
if(_wishspeed > flMaxSpeed && flMaxSpeed != 0.0) _wishspeed = flMaxSpeed;
|
||||
|
||||
_wishspd = _wishspeed;
|
||||
if (_wishspd > flAirSpeedCap)
|
||||
_wishspd = flAirSpeedCap;
|
||||
|
||||
_currentspeed = GetVectorDotProduct(velocity, _wishdir);
|
||||
_addspeed = _wishspd - _currentspeed;
|
||||
if (_addspeed < 0.0)
|
||||
_addspeed = 0.0;
|
||||
}
|
||||
|
||||
float fore[3], side[3], wishvel[3], wishdir[3];
|
||||
float wishspeed, wishspd, addspeed, currentspeed;
|
||||
|
||||
float tmp[3];
|
||||
tmp[0] = 0.0; tmp[2] = 0.0;
|
||||
tmp[1] = normalize_yaw(angles[1] + delta_opt);
|
||||
GetAngleVectors(tmp, fore, side, ZERO_VECTOR);
|
||||
|
||||
fore[2] = 0.0; side[2] = 0.0;
|
||||
NormalizeVector(fore, fore); NormalizeVector(side, side);
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
wishvel[i] = fore[i] * vel[0] * frac + side[i] * vel[1] * frac;
|
||||
|
||||
wishspeed = NormalizeVector(wishvel, wishdir);
|
||||
|
||||
if(wishspeed > flMaxSpeed && wishspeed != 0.0) wishspeed = flMaxSpeed;
|
||||
|
||||
wishspd = wishspeed;
|
||||
if (wishspd > flAirSpeedCap)
|
||||
wishspd = flAirSpeedCap;
|
||||
|
||||
currentspeed = GetVectorDotProduct(velocity, wishdir);
|
||||
addspeed = wishspd - currentspeed;
|
||||
|
||||
if (no_speed_loss)
|
||||
{
|
||||
if (_addspeed > addspeed)
|
||||
{
|
||||
addspeed = _addspeed - addspeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
addspeed -= _addspeed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
addspeed = addspeed - _addspeed;
|
||||
|
||||
if (addspeed > flAirSpeedCap)
|
||||
addspeed = flAirSpeedCap;
|
||||
}
|
||||
|
||||
if (buttons & IN_DUCK)
|
||||
{
|
||||
float vel2d[3]; vel2d[0] = velocity[0]; vel2d[1] = velocity[1];
|
||||
//PrintToChat(client, "%f %f\n", GetVectorLength(vel2d), addspeed);
|
||||
}
|
||||
|
||||
if (addspeed < 0.0)
|
||||
addspeed = 0.0;
|
||||
|
||||
float accelspeed = wishspeed * air_accelerate * GetTickInterval() * surface_friction;
|
||||
|
||||
if (accelspeed > addspeed)
|
||||
accelspeed = addspeed;
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
velocity_opt[i] += accelspeed * wishdir[i];
|
||||
|
||||
float new_vel[3];
|
||||
|
||||
float numer = velocity_opt[0] * velocity[0] + velocity_opt[1] * velocity[1];
|
||||
//float denom = SquareRoot(velocity_opt[0] * velocity_opt[0] + velocity_opt[1] * velocity_opt[1]) * SquareRoot(velocity[0] * velocity[0] + velocity[1] * velocity[1]);
|
||||
float denom = get_length_2d(velocity_opt) * get_length_2d(velocity);
|
||||
float ang = 0.0;
|
||||
if (denom > numer)
|
||||
ang = ArcCosine(numer / denom) * 180.0 / FLOAT_PI;
|
||||
if (vel[1] < 0.0) ang = -ang;
|
||||
|
||||
float st = Sine(ang * FLOAT_PI / 180.0);
|
||||
float ct = Cosine(ang * FLOAT_PI / 180.0);
|
||||
|
||||
new_vel[0] = (velocity_opt[0] * ct) - (velocity_opt[1] * st);
|
||||
new_vel[1] = (velocity_opt[0] * st) + (velocity_opt[1] * ct);
|
||||
new_vel[2] = velocity_opt[2];
|
||||
|
||||
float base_vel[3];
|
||||
GetEntPropVector(client, Prop_Data, "m_vecBaseVelocity", base_vel);
|
||||
|
||||
//PrintToChat(client, "%.2f, %.2f, %.2f", base_vel[0], base_vel[1], base_vel[2]);
|
||||
|
||||
if (GetVectorLength(new_vel) < 99999.0 && GetVectorLength(new_vel) > 0.0)
|
||||
{
|
||||
SetEntPropVector(client, Prop_Data, "m_vecVelocity", new_vel);
|
||||
SetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", new_vel);
|
||||
}
|
||||
|
||||
if (set_back)
|
||||
vel[1] = 0.0;
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
415
addons/sourcemod/scripting/include/shavit/tas-xutax.inc
Normal file
415
addons/sourcemod/scripting/include/shavit/tas-xutax.inc
Normal file
@ -0,0 +1,415 @@
|
||||
/*
|
||||
* tas-xutax.inc file
|
||||
* by: xutaxkamay, KiD Fearless
|
||||
*
|
||||
* Retrieved from KiD-TAS (https://github.com/kidfearless/KiD-TAS)
|
||||
* and edited to be part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_tas_xutax_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_tas_xutax_included
|
||||
|
||||
// reference code for CGameMovement::AirAccelerate & CGameMovement::AirMove at:
|
||||
// https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/shared/gamemovement.cpp#L1707-L1799
|
||||
|
||||
|
||||
stock float AngleNormalize(float flAngle)
|
||||
{
|
||||
if (flAngle > 180.0)
|
||||
flAngle -= 360.0;
|
||||
else if (flAngle < -180.0)
|
||||
flAngle += 360.0;
|
||||
|
||||
return flAngle;
|
||||
}
|
||||
|
||||
stock float Vec2DToYaw(float vec[2])
|
||||
{
|
||||
float flYaw = 0.0;
|
||||
|
||||
if (vec[0] != 0.0 || vec[1] != 0.0)
|
||||
{
|
||||
float vecNormalized[2];
|
||||
|
||||
float flLength = SquareRoot(vec[0] * vec[0] + vec[1] * vec[1]);
|
||||
|
||||
vecNormalized[0] = vec[0] / flLength;
|
||||
vecNormalized[1] = vec[1] / flLength;
|
||||
|
||||
// Credits to Valve.
|
||||
flYaw = ArcTangent2(vecNormalized[1], vecNormalized[0]) * (180.0 / FLOAT_PI);
|
||||
|
||||
flYaw = AngleNormalize(flYaw);
|
||||
}
|
||||
|
||||
return flYaw;
|
||||
}
|
||||
|
||||
/*
|
||||
* So our problem here is to find a wishdir that no matter the angles we choose, it should go to the direction we want.
|
||||
* So forward/right vector changing but not sidemove and forwardmove for the case where we modify our angles. (1)
|
||||
* But in our case we want sidemove and forwardmove values changing and not the forward/right vectors. (2)
|
||||
* So our unknown variables is fmove and smove to know the (2) case. But we know the (1) case so we can solve this into a linear equation.
|
||||
* To make it more simplier, we know the wishdir values and forward/right vectors, but we do not know the fowardmove and sidemove variables
|
||||
* and that's what we want to solve.
|
||||
* That's what is doing this function, but only in 2D since we can only move forward or side.
|
||||
* But, for noclip (3D) it's a different story that I will let you discover, same method, but 3 equations and 3 unknown variables (forwardmove, sidemove, upmove).
|
||||
*/
|
||||
|
||||
stock void Solve2DMovementsVars(float vecWishDir[2], float vecForward[2], float vecRight[2], float &flForwardMove, float &flSideMove, float flMaxMove)
|
||||
{
|
||||
// wishdir[0] = foward[0] * forwardmove + right[0] * sidemove;
|
||||
// wishdir[1] = foward[1] * forwardmove + right[1] * sidemove;
|
||||
|
||||
// Let's translate this to letters.
|
||||
// v = a * b + c * d
|
||||
// w = e * b + f * d
|
||||
// v = wishdir[0]; w = wishdir[1]...
|
||||
|
||||
// Now let's solve it with online solver https://quickmath.com/webMathematica3/quickmath/equations/solve/advanced.jsp
|
||||
// https://cdn.discordapp.com/attachments/609163806085742622/675477245178937385/c3ca4165c30b3b342e57b903a3ded367-3.png
|
||||
|
||||
float v = vecWishDir[0];
|
||||
float w = vecWishDir[1];
|
||||
float a = vecForward[0];
|
||||
float c = vecRight[0];
|
||||
float e = vecForward[1];
|
||||
float f = vecRight[1];
|
||||
|
||||
float flDivide = (c * e - a * f);
|
||||
if(flDivide == 0.0)
|
||||
{
|
||||
flForwardMove = flMaxMove;
|
||||
flSideMove = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
flForwardMove = (c * w - f * v) / flDivide;
|
||||
flSideMove = (e * v - a * w) / flDivide;
|
||||
}
|
||||
}
|
||||
|
||||
stock float GetThetaAngleInAir(float flVelocity[2], float flAirAccelerate, float flMaxSpeed, float flSurfaceFriction, float flFrametime, float flAirSpeedCap)
|
||||
{
|
||||
// In order to solve this, we must check that accelspeed < 30
|
||||
// so it applies the correct strafing method.
|
||||
// So there is basically two cases:
|
||||
// if 30 - accelspeed <= 0 -> We use the perpendicular of velocity.
|
||||
// but if 30 - accelspeed > 0 the dot product must be equal to = 30 - accelspeed
|
||||
// in order to get the best gain.
|
||||
// First case is theta == 90
|
||||
// How to solve the second case?
|
||||
// here we go
|
||||
// d = velocity2DLength * cos(theta)
|
||||
// cos(theta) = d / velocity2D
|
||||
// theta = arcos(d / velocity2D)
|
||||
|
||||
float flAccelSpeed = flAirAccelerate * flMaxSpeed * flSurfaceFriction * flFrametime;
|
||||
|
||||
float flWantedDotProduct = flAirSpeedCap - flAccelSpeed;
|
||||
|
||||
if (flWantedDotProduct > 0.0)
|
||||
{
|
||||
float flVelLength2D = SquareRoot(flVelocity[0] * flVelocity[0] + flVelocity[1] * flVelocity[1]);
|
||||
if(flVelLength2D == 0.0)
|
||||
{
|
||||
return 90.0;
|
||||
}
|
||||
float flCosTheta = flWantedDotProduct / flVelLength2D;
|
||||
|
||||
if (flCosTheta > 1.0)
|
||||
{
|
||||
flCosTheta = 1.0;
|
||||
}
|
||||
else if(flCosTheta < -1.0)
|
||||
{
|
||||
flCosTheta = -1.0;
|
||||
}
|
||||
|
||||
|
||||
float flTheta = ArcCosine(flCosTheta) * (180.0 / FLOAT_PI);
|
||||
|
||||
return flTheta;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 90.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Same as above, but this time we calculate max delta angle
|
||||
// so we can change between normal strafer and autostrafer depending on the player's viewangles difference.
|
||||
/*float GetMaxDeltaInAir(float flVelocity[2], float flAirAccelerate, float flMaxSpeed, float flSurfaceFriction, float flFrametime)
|
||||
{
|
||||
float flAccelSpeed = flAirAccelerate * flMaxSpeed * flSurfaceFriction * flFrametime;
|
||||
|
||||
if (flAccelSpeed >= g_flAirSpeedCap)
|
||||
{
|
||||
flAccelSpeed = g_flAirSpeedCap;
|
||||
}
|
||||
|
||||
float flVelLength2D = SquareRoot(flVelocity[0] * flVelocity[0] + flVelocity[1] * flVelocity[1]);
|
||||
|
||||
float flMaxDelta = ArcTangent2(flAccelSpeed, flVelLength2D) * (180 / FLOAT_PI);
|
||||
|
||||
return flMaxDelta;
|
||||
}*/
|
||||
|
||||
stock void SimulateAirAccelerate(float flVelocity[2], float flWishDir[2], float flAirAccelerate, float flMaxSpeed, float flSurfaceFriction, float flFrametime, float flVelocityOutput[2], float flAirSpeedCap)
|
||||
{
|
||||
float flWishSpeedCapped = flMaxSpeed;
|
||||
|
||||
// Cap speed
|
||||
if( flWishSpeedCapped > flAirSpeedCap )
|
||||
flWishSpeedCapped = flAirSpeedCap;
|
||||
|
||||
// Determine veer amount
|
||||
float flCurrentSpeed = flVelocity[0] * flWishDir[0] + flVelocity[1] * flWishDir[1];
|
||||
|
||||
// See how much to add
|
||||
float flAddSpeed = flWishSpeedCapped - flCurrentSpeed;
|
||||
|
||||
// If not adding any, done.
|
||||
if( flAddSpeed <= 0.0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine acceleration speed after acceleration
|
||||
float flAccelSpeed = flAirAccelerate * flMaxSpeed * flFrametime * flSurfaceFriction;
|
||||
|
||||
// Cap it
|
||||
if( flAccelSpeed > flAddSpeed )
|
||||
{
|
||||
flAccelSpeed = flAddSpeed;
|
||||
}
|
||||
|
||||
flVelocityOutput[0] = flVelocity[0] + flAccelSpeed * flWishDir[0];
|
||||
flVelocityOutput[1] = flVelocity[1] + flAccelSpeed * flWishDir[1];
|
||||
}
|
||||
|
||||
// The idea is to get the maximum angle
|
||||
stock float GetMaxDeltaInAir(float flVelocity[2], float flMaxSpeed, float flSurfaceFriction, bool bLeft, float flAirAccelerate, float flAirSpeedCap)
|
||||
{
|
||||
float flFrametime = GetTickInterval();
|
||||
|
||||
float flTheta = GetThetaAngleInAir(flVelocity, flAirAccelerate, flMaxSpeed, flSurfaceFriction, flFrametime, flAirSpeedCap);
|
||||
|
||||
// Convert velocity 2D to angle.
|
||||
float flYawVelocity = Vec2DToYaw(flVelocity);
|
||||
|
||||
// Get the best yaw direction on the right.
|
||||
float flBestYawRight = AngleNormalize(flYawVelocity + flTheta);
|
||||
|
||||
// Get the best yaw direction on the left.
|
||||
float flBestYawLeft = AngleNormalize(flYawVelocity - flTheta);
|
||||
|
||||
float flTemp[3], vecBestLeft3D[3], vecBestRight3D[3];
|
||||
|
||||
flTemp[0] = 0.0;
|
||||
flTemp[1] = flBestYawLeft;
|
||||
flTemp[2] = 0.0;
|
||||
|
||||
GetAngleVectors(flTemp, vecBestLeft3D, ZERO_VECTOR, ZERO_VECTOR);
|
||||
|
||||
flTemp[0] = 0.0;
|
||||
flTemp[1] = flBestYawRight;
|
||||
flTemp[2] = 0.0;
|
||||
|
||||
GetAngleVectors(flTemp, vecBestRight3D, ZERO_VECTOR, ZERO_VECTOR);
|
||||
|
||||
float vecBestRight[2], vecBestLeft[2];
|
||||
|
||||
vecBestRight[0] = vecBestRight3D[0];
|
||||
vecBestRight[1] = vecBestRight3D[1];
|
||||
|
||||
vecBestLeft[0] = vecBestLeft3D[0];
|
||||
vecBestLeft[1] = vecBestLeft3D[1];
|
||||
|
||||
float flCalcVelocityLeft[2], flCalcVelocityRight[2];
|
||||
|
||||
// Simulate air accelerate function in order to get the new max gain possible on both side.
|
||||
SimulateAirAccelerate(flVelocity, vecBestLeft, flAirAccelerate, flMaxSpeed, flFrametime, flSurfaceFriction, flCalcVelocityLeft, flAirSpeedCap);
|
||||
SimulateAirAccelerate(flVelocity, vecBestRight, flAirAccelerate, flMaxSpeed, flFrametime, flSurfaceFriction, flCalcVelocityRight, flAirSpeedCap);
|
||||
|
||||
float flNewBestYawLeft = Vec2DToYaw(flCalcVelocityLeft);
|
||||
float flNewBestYawRight = Vec2DToYaw(flCalcVelocityRight);
|
||||
|
||||
// Then get the difference in order to find the maximum angle.
|
||||
if (bLeft)
|
||||
{
|
||||
return FloatAbs(AngleNormalize(flYawVelocity - flNewBestYawLeft));
|
||||
}
|
||||
else
|
||||
{
|
||||
return FloatAbs(AngleNormalize(flYawVelocity - flNewBestYawRight));
|
||||
}
|
||||
|
||||
// Do an estimate otherwhise.
|
||||
// return FloatAbs(AngleNormalize(flNewBestYawLeft - flNewBestYawRight) / 2.0);
|
||||
}
|
||||
|
||||
stock void GetIdealMovementsInAir(float flYawWantedDir, float flVelocity[2], float flMaxSpeed, float flSurfaceFriction, float &flForwardMove, float &flSideMove, bool bPreferRight, float flAirAccelerate, float flMaxMove, float flAirSpeedCap)
|
||||
{
|
||||
float flFrametime = GetTickInterval();
|
||||
float flYawVelocity = Vec2DToYaw(flVelocity);
|
||||
|
||||
// Get theta angle
|
||||
float flTheta = GetThetaAngleInAir(flVelocity, flAirAccelerate, flMaxSpeed, flSurfaceFriction, flFrametime, flAirSpeedCap);
|
||||
|
||||
// Get the best yaw direction on the right.
|
||||
float flBestYawRight = AngleNormalize(flYawVelocity + flTheta);
|
||||
|
||||
// Get the best yaw direction on the left.
|
||||
float flBestYawLeft = AngleNormalize(flYawVelocity - flTheta);
|
||||
|
||||
float vecBestDirLeft[3], vecBestDirRight[3];
|
||||
float tempAngle[3];
|
||||
|
||||
tempAngle[0] = 0.0;
|
||||
tempAngle[1] = flBestYawRight;
|
||||
tempAngle[2] = 0.0;
|
||||
|
||||
GetAngleVectors(tempAngle, vecBestDirRight, ZERO_VECTOR, ZERO_VECTOR);
|
||||
|
||||
tempAngle[0] = 0.0;
|
||||
tempAngle[1] = flBestYawLeft;
|
||||
tempAngle[2] = 0.0;
|
||||
|
||||
GetAngleVectors(tempAngle, vecBestDirLeft, ZERO_VECTOR, ZERO_VECTOR);
|
||||
|
||||
// Our wanted direction.
|
||||
float vecBestDir[2];
|
||||
|
||||
// Let's follow the most the wanted direction now with max possible gain.
|
||||
float flDiffYaw = AngleNormalize(flYawWantedDir - flYawVelocity);
|
||||
|
||||
if (flDiffYaw > 0.0)
|
||||
{
|
||||
vecBestDir[0] = vecBestDirRight[0];
|
||||
vecBestDir[1] = vecBestDirRight[1];
|
||||
}
|
||||
else if(flDiffYaw < 0.0)
|
||||
{
|
||||
vecBestDir[0] = vecBestDirLeft[0];
|
||||
vecBestDir[1] = vecBestDirLeft[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Going straight.
|
||||
if (bPreferRight)
|
||||
{
|
||||
vecBestDir[0] = vecBestDirRight[0];
|
||||
vecBestDir[1] = vecBestDirRight[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
vecBestDir[0] = vecBestDirLeft[0];
|
||||
vecBestDir[1] = vecBestDirLeft[1];
|
||||
}
|
||||
}
|
||||
|
||||
float vecForwardWantedDir3D[3], vecRightWantedDir3D[3];
|
||||
float vecForwardWantedDir[2], vecRightWantedDir[2];
|
||||
|
||||
tempAngle[0] = 0.0;
|
||||
tempAngle[1] = flYawWantedDir;
|
||||
tempAngle[2] = 0.0;
|
||||
|
||||
// Convert our yaw wanted direction to vectors.
|
||||
GetAngleVectors(tempAngle, vecForwardWantedDir3D, vecRightWantedDir3D, ZERO_VECTOR);
|
||||
|
||||
vecForwardWantedDir[0] = vecForwardWantedDir3D[0];
|
||||
vecForwardWantedDir[1] = vecForwardWantedDir3D[1];
|
||||
|
||||
vecRightWantedDir[0] = vecRightWantedDir3D[0];
|
||||
vecRightWantedDir[1] = vecRightWantedDir3D[1];
|
||||
|
||||
// Solve the movement variables from our wanted direction and the best gain direction.
|
||||
Solve2DMovementsVars(vecBestDir, vecForwardWantedDir, vecRightWantedDir, flForwardMove, flSideMove, flMaxMove);
|
||||
|
||||
float flLengthMovements = SquareRoot(flForwardMove * flForwardMove + flSideMove * flSideMove);
|
||||
|
||||
if(flLengthMovements != 0.0)
|
||||
{
|
||||
flForwardMove /= flLengthMovements;
|
||||
flSideMove /= flLengthMovements;
|
||||
}
|
||||
}
|
||||
|
||||
stock Action XutaxOnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2],
|
||||
float flAirAccelerate, float flSurfaceFriction, float flAirSpeedCap, float flMaxMove, float flOldYawAngle, float fPower)
|
||||
{
|
||||
// clear out forward because Surf_W_Okay is nice...
|
||||
vel[0] = 0.0;
|
||||
|
||||
float flFowardMove, flSideMove;
|
||||
float flMaxSpeed = Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "runspeed");
|
||||
float flVelocity[3], flVelocity2D[2];
|
||||
|
||||
GetEntPropVector(client, Prop_Data, "m_vecVelocity", flVelocity);
|
||||
|
||||
flVelocity2D[0] = flVelocity[0];
|
||||
flVelocity2D[1] = flVelocity[1];
|
||||
|
||||
// PrintToChat(client, "%f", SquareRoot(flVelocity2D[0] * flVelocity2D[0] + flVelocity2D[1] * flVelocity2D[1]));
|
||||
|
||||
GetIdealMovementsInAir(angles[1], flVelocity2D, flMaxSpeed, flSurfaceFriction, flFowardMove, flSideMove, true, flAirAccelerate, flMaxMove, flAirSpeedCap);
|
||||
|
||||
float flAngleDifference = AngleNormalize(angles[1] - flOldYawAngle);
|
||||
float flCurrentAngles = FloatAbs(flAngleDifference);
|
||||
|
||||
|
||||
// Right
|
||||
if (flAngleDifference < 0.0)
|
||||
{
|
||||
float flMaxDelta = GetMaxDeltaInAir(flVelocity2D, flMaxSpeed, flSurfaceFriction, true, flAirAccelerate, flAirSpeedCap);
|
||||
|
||||
if (flCurrentAngles <= flMaxDelta * fPower)
|
||||
{
|
||||
vel[0] = flFowardMove * flMaxMove;
|
||||
vel[1] = flSideMove * flMaxMove;
|
||||
}
|
||||
else
|
||||
{
|
||||
vel[1] = flMaxMove;
|
||||
}
|
||||
}
|
||||
else if (flAngleDifference > 0.0)
|
||||
{
|
||||
float flMaxDelta = GetMaxDeltaInAir(flVelocity2D, flMaxSpeed, flSurfaceFriction, false, flAirAccelerate, flAirSpeedCap);
|
||||
|
||||
if (flCurrentAngles <= flMaxDelta * fPower)
|
||||
{
|
||||
vel[0] = flFowardMove * flMaxMove;
|
||||
vel[1] = flSideMove * flMaxMove;
|
||||
}
|
||||
else
|
||||
{
|
||||
vel[1] = -flMaxMove;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vel[0] = flFowardMove * flMaxMove;
|
||||
vel[1] = flSideMove * flMaxMove;
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
242
addons/sourcemod/scripting/include/shavit/tas.inc
Normal file
242
addons/sourcemod/scripting/include/shavit/tas.inc
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* shavit's Timer - tas.inc file
|
||||
* by: xutaxkamay, shavit, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_tas_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_tas_included
|
||||
|
||||
enum AutostrafeOverride
|
||||
{
|
||||
AutostrafeOverride_Normal, // only w/s disables autostrafe
|
||||
AutostrafeOverride_Surf, // w/s always disables, a/d only over surf ramps
|
||||
AutostrafeOverride_Surf_W_Okay, // s always disables, a/d only over surf ramps
|
||||
AutostrafeOverride_All, // all keys disable
|
||||
AutostrafeOverride_Size // size
|
||||
};
|
||||
|
||||
enum AutostrafeType
|
||||
{
|
||||
AutostrafeType_Any = -1,
|
||||
AutostrafeType_Disabled = 0,
|
||||
AutostrafeType_1Tick = 1, // xutaxkamay
|
||||
AutostrafeType_Autogain, // oblivious
|
||||
AutostrafeType_AutogainNoSpeedLoss, // oblivious
|
||||
AutostrafeType_Basic, //
|
||||
AutostrafeType_Size
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets whether the client has the autostrafe/strafehack enabled.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param value New value to set the autostrafe/strafehack to.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutostrafeEnabled(int client, bool value);
|
||||
|
||||
/**
|
||||
* Retrieves whether the client has the autostrafe/strafehack enabled.
|
||||
*
|
||||
* @param client Client index
|
||||
* @return The current autostrafe/strafehack enabled value.
|
||||
*/
|
||||
native bool Shavit_GetAutostrafeEnabled(int client);
|
||||
|
||||
/**
|
||||
* Sets the autostrafe/strafehack type on the given client index.
|
||||
*
|
||||
* @param client Client index of the player to set the autostrafe/strafehack on.
|
||||
* @param value New type to set the strafehack to.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutostrafeType(int client, AutostrafeType value);
|
||||
|
||||
/**
|
||||
* Retrieves the current strafehack type for the given client index.
|
||||
*
|
||||
* @param client Client index of the player to get the strafehack type from.
|
||||
* @return The current strafehack type.
|
||||
*/
|
||||
native AutostrafeType Shavit_GetAutostrafeType(int client);
|
||||
|
||||
/**
|
||||
* Sets the strafehack power on the given client index. Power is the cut off point before it will turn into an autostrafe. 1.0 is the default.
|
||||
*
|
||||
* @param client Client index of the player to set the power on.
|
||||
* @param value New power setting.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutostrafePower(int client, float value);
|
||||
|
||||
/**
|
||||
* Retrieves the current strafehack power for the given client index. Default is 1.0
|
||||
*
|
||||
* @param client Client index of the player to get the strafehack power.
|
||||
* @return The current strafehack power.
|
||||
*/
|
||||
native float Shavit_GetAutostrafePower(int client);
|
||||
|
||||
/**
|
||||
* Sets the key override type on the given client index.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param value New type to set the key override to.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutostrafeKeyOverride(int client, AutostrafeOverride value);
|
||||
|
||||
/**
|
||||
* Retrieves the current key override type for the given client index.
|
||||
*
|
||||
* @param client Client index
|
||||
* @return The current key override type.
|
||||
*/
|
||||
native AutostrafeOverride Shavit_GetAutostrafeKeyOverride(int client);
|
||||
|
||||
/**
|
||||
* Sets whether the client has automatic prestrafe enabled.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param value New value to set the automatic prestrafe to.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutoPrestrafe(int client, bool value);
|
||||
|
||||
/**
|
||||
* Retrieves whether the client has automatic prestrafe enabled.
|
||||
*
|
||||
* @param client Client index
|
||||
* @return The current auto prestrafe value.
|
||||
*/
|
||||
native bool Shavit_GetAutoPrestrafe(int client);
|
||||
|
||||
/**
|
||||
* Sets whether the client automatically jumps when they leave the start zone.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param value New value to set the automatic jump to.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutoJumpOnStart(int client, bool value);
|
||||
|
||||
/**
|
||||
* Retrieves whether the client automatically jumps when they leave the start zone.
|
||||
*
|
||||
* @param client Client index
|
||||
* @return The current auto jump value.
|
||||
*/
|
||||
native bool Shavit_GetAutoJumpOnStart(int client);
|
||||
|
||||
/**
|
||||
* Sets whether the client uses the autogain basic strafer.
|
||||
*
|
||||
* @param client Client index
|
||||
* @param value New value to set the autogain basic strafer to.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetAutogainBasicStrafer(int client, bool value);
|
||||
|
||||
/**
|
||||
* Retrieves whether the client has has enabled the autogain basic strafer :tm:
|
||||
*
|
||||
* @param client Client index
|
||||
* @return The current autogain basic strafer setting.
|
||||
*/
|
||||
native bool Shavit_GetAutogainBasicStrafer(int client);
|
||||
|
||||
|
||||
|
||||
// taken from shavit's oryx
|
||||
stock bool IsSurfing(int client)
|
||||
{
|
||||
float fPosition[3];
|
||||
GetClientAbsOrigin(client, fPosition);
|
||||
|
||||
float fEnd[3];
|
||||
fEnd = fPosition;
|
||||
fEnd[2] -= 64.0;
|
||||
|
||||
float fMins[3];
|
||||
GetEntPropVector(client, Prop_Send, "m_vecMins", fMins);
|
||||
|
||||
float fMaxs[3];
|
||||
GetEntPropVector(client, Prop_Send, "m_vecMaxs", fMaxs);
|
||||
|
||||
Handle hTR = TR_TraceHullFilterEx(fPosition, fEnd, fMins, fMaxs, MASK_PLAYERSOLID, TRFilter_NoPlayers, client);
|
||||
|
||||
if(TR_DidHit(hTR))
|
||||
{
|
||||
float fNormal[3];
|
||||
TR_GetPlaneNormal(hTR, fNormal);
|
||||
|
||||
delete hTR;
|
||||
|
||||
// If the plane normal's Z axis is 0.7 or below (alternatively, -0.7 when upside-down) then it's a surf ramp.
|
||||
// https://github.com/alliedmodders/hl2sdk/blob/92dcf04225a278b75170cc84917f04e98f5d08ec/game/server/physics_main.cpp#L1059
|
||||
// https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/server/physics_main.cpp#L1065
|
||||
|
||||
return (-0.7 <= fNormal[2] <= 0.7);
|
||||
}
|
||||
|
||||
delete hTR;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
stock bool TRFilter_NoPlayers(int entity, int mask, any data)
|
||||
{
|
||||
return !(1 <= entity <= MaxClients);
|
||||
}
|
||||
|
||||
|
||||
public SharedPlugin __pl_shavit_tas =
|
||||
{
|
||||
name = "shavit-tas",
|
||||
file = "shavit-tas.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_tas_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_SetAutostrafeEnabled");
|
||||
MarkNativeAsOptional("Shavit_GetAutostrafeEnabled");
|
||||
MarkNativeAsOptional("Shavit_SetAutostrafeType");
|
||||
MarkNativeAsOptional("Shavit_GetAutostrafeType");
|
||||
MarkNativeAsOptional("Shavit_SetAutostrafePower");
|
||||
MarkNativeAsOptional("Shavit_GetAutostrafePower");
|
||||
MarkNativeAsOptional("Shavit_SetAutostrafeKeyOverride");
|
||||
MarkNativeAsOptional("Shavit_GetAutostrafeKeyOverride");
|
||||
MarkNativeAsOptional("Shavit_SetAutoPrestrafe");
|
||||
MarkNativeAsOptional("Shavit_GetAutoPrestrafe");
|
||||
MarkNativeAsOptional("Shavit_SetAutoJumpOnStart");
|
||||
MarkNativeAsOptional("Shavit_GetAutoJumpOnStart");
|
||||
MarkNativeAsOptional("Shavit_SetEdgeJump");
|
||||
MarkNativeAsOptional("Shavit_GetEdgeJump");
|
||||
MarkNativeAsOptional("Shavit_SetAutogainBasicStrafer");
|
||||
MarkNativeAsOptional("Shavit_GetAutogainBasicStrafer");
|
||||
}
|
||||
#endif
|
||||
116
addons/sourcemod/scripting/include/shavit/weapon-stocks.inc
Normal file
116
addons/sourcemod/scripting/include/shavit/weapon-stocks.inc
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* shavit's Timer - weapon stocks
|
||||
* by: shavit, psychonic, Kxnrl, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_weapon_stocks_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_weapon_stocks_included
|
||||
|
||||
// based on code by Kxnrl in SurfTimer
|
||||
// which is based on code by splewis from csgo-deathmatch?
|
||||
// https://github.com/Maxximou5/csgo-deathmatch/pull/24/commits/207cbfe3f1b9a1082c4a710841c190bb753485dc#diff-2c9694977d0a3fe527ca8b484add6a58f53bab303e5dcaa583cb2917ec04d89cR3122-R3130
|
||||
// https://github.com/surftimer/SurfTimer/commit/134887a29a396e01a721a78ab69e81a80593411a#diff-0b2bae39ae9de87ea2952bfd12c8777c7301e06ce683acc518229704cf024c33R4894-R4910
|
||||
stock int GiveSkinnedWeapon(int client, const char[] classname)
|
||||
{
|
||||
int target_team = 0;
|
||||
int current_team = 0;
|
||||
|
||||
if (StrContains(classname, "usp") != -1)
|
||||
{
|
||||
target_team = 3;
|
||||
}
|
||||
else if (StrContains(classname, "glock") != -1)
|
||||
{
|
||||
target_team = 2;
|
||||
}
|
||||
|
||||
if (target_team != 0)
|
||||
{
|
||||
current_team = GetEntProp(client, Prop_Send, "m_iTeamNum");
|
||||
|
||||
if (current_team != target_team)
|
||||
{
|
||||
SetEntProp(client, Prop_Send, "m_iTeamNum", target_team);
|
||||
}
|
||||
}
|
||||
|
||||
int weapon = GivePlayerItem(client, classname);
|
||||
|
||||
if (current_team != target_team)
|
||||
{
|
||||
SetEntProp(client, Prop_Send, "m_iTeamNum", current_team);
|
||||
}
|
||||
|
||||
return weapon;
|
||||
}
|
||||
|
||||
// based on testsuite code from psychonic
|
||||
// https://github.com/alliedmodders/sourcemod/blob/c5701503185d7e1cb8411c7347abdd31eee75c4e/plugins/testsuite/entpropelements.sp#L88-L96
|
||||
stock void RemoveAllWeapons(int client)
|
||||
{
|
||||
int weapon = -1, max = GetEntPropArraySize(client, Prop_Send, "m_hMyWeapons");
|
||||
for (int i = 0; i < max; i++)
|
||||
{
|
||||
if ((weapon = GetEntPropEnt(client, Prop_Send, "m_hMyWeapons", i)) == -1)
|
||||
continue;
|
||||
|
||||
if (RemovePlayerItem(client, weapon))
|
||||
{
|
||||
AcceptEntityInput(weapon, "Kill");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stock void SetMaxWeaponAmmo(int client, int weapon, bool setClip1)
|
||||
{
|
||||
static EngineVersion engine = Engine_Unknown;
|
||||
|
||||
if (engine == Engine_Unknown)
|
||||
{
|
||||
engine = GetEngineVersion();
|
||||
}
|
||||
|
||||
int iAmmo = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType");
|
||||
|
||||
if (iAmmo < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetEntProp(client, Prop_Send, "m_iAmmo", 255, 4, iAmmo);
|
||||
|
||||
if (engine == Engine_CSGO)
|
||||
{
|
||||
SetEntProp(weapon, Prop_Send, "m_iPrimaryReserveAmmoCount", 255);
|
||||
}
|
||||
|
||||
if (setClip1)
|
||||
{
|
||||
int amount = GetEntProp(weapon, Prop_Send, "m_iClip1") + 1;
|
||||
|
||||
if (HasEntProp(weapon, Prop_Send, "m_bBurstMode") && GetEntProp(weapon, Prop_Send, "m_bBurstMode"))
|
||||
{
|
||||
amount += 2;
|
||||
}
|
||||
|
||||
SetEntProp(weapon, Prop_Data, "m_iClip1", amount);
|
||||
}
|
||||
}
|
||||
279
addons/sourcemod/scripting/include/shavit/wr.inc
Normal file
279
addons/sourcemod/scripting/include/shavit/wr.inc
Normal file
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* shavit's Timer - wr.inc file
|
||||
* by: shavit, SaengerItsWar, rtldg, KiD Fearless, rtldg, BoomShotKapow
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_wr_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_wr_included
|
||||
|
||||
/**
|
||||
* Like Shavit_OnFinish, but after the insertion query was called.
|
||||
* Called from shavit-wr
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style the record was done on.
|
||||
* @param time Record time.
|
||||
* @param jumps Jumps amount.
|
||||
* @param strafes Amount of strafes.
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param rank Rank on map.
|
||||
* @param overwrite 1 - brand new record. 2 - update.
|
||||
* @param track Timer track.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @param avgvel Player's average velocity throughout the run.
|
||||
* @param maxvel Player's highest reached velocity.
|
||||
* @param timestamp System time of when player finished.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank, int overwrite, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp);
|
||||
|
||||
/**
|
||||
* Called when there's a new WR on the map.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style the record was done on.
|
||||
* @param time Record time.
|
||||
* @param jumps Jumps amount.
|
||||
* @param strafes Amount of strafes.
|
||||
* @param sync Sync percentage (0.0 to 100.0) or -1.0 when not measured.
|
||||
* @param track Timer track.
|
||||
* @param oldwr Time of the old WR. 0.0 if there's none.
|
||||
* @param oldtime The player's best time on the map before this finish.
|
||||
* @param perfs Perfect jump percentage (0.0 to 100.0) or 100.0 when not measured.
|
||||
* @param avgvel Player's average velocity throughout the run.
|
||||
* @param maxvel Player's highest reached velocity.
|
||||
* @param timestamp System time of when player finished.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnWorldRecord(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldwr, float oldtime, float perfs, float avgvel, float maxvel, int timestamp);
|
||||
|
||||
/**
|
||||
* Called when an admin deletes a WR.
|
||||
*
|
||||
* @param style Style the record was done on.
|
||||
* @param id Record ID. -1 if mass deletion.
|
||||
* @param track Timer track.
|
||||
* @param accountid The account ID of the wr holder
|
||||
* @param mapname The map name.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnWRDeleted(int style, int id, int track, int accountid, const char[] mapname);
|
||||
|
||||
/**
|
||||
* Called after shavit-wr caches the current map's WRs.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnWorldRecordsCached();
|
||||
|
||||
/**
|
||||
* Called before the timer finish message is printed to the users.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param everyone Is the message printed to everyone, or just the client?
|
||||
* @param snapshot A snapshot of the client's timer when printing the message.
|
||||
* @param overwrite Modify the database? 0 - no. 1 - brand new record. 2 - new personal best.
|
||||
* @param rank Rank on map.
|
||||
* @param message The finish message.
|
||||
* @param maxlen Buffer size of message.
|
||||
* @param message2 A second line of info that is printed on finish.
|
||||
* @param maxlen2 Buffer size of message2.
|
||||
*
|
||||
* @return Plugin_Handled or Plugin_Stop to stop the message. Anything else to use new values.
|
||||
*/
|
||||
forward Action Shavit_OnFinishMessage(int client, bool &everyone, timer_snapshot_t snapshot, int overwrite, int rank, char[] message, int maxlen, char[] message2, int maxlen2);
|
||||
|
||||
/**
|
||||
* Retrieves the world record for the given style/track.
|
||||
*
|
||||
* @param style Style to get the WR for.
|
||||
* @param track Timer track.
|
||||
* @return World record for the specified settings.
|
||||
*/
|
||||
native float Shavit_GetWorldRecord(int style, int track);
|
||||
|
||||
/**
|
||||
* Reloads WR leaderboards cache for the current map.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_ReloadLeaderboards();
|
||||
|
||||
/**
|
||||
* Saves the WR's record ID for the current map on a variable.
|
||||
* Unused in base plugins, as of pre-1.4b.
|
||||
*
|
||||
* @param style Style to get the WR for.
|
||||
* @param time Reference to the time variable. 0.0 will be returned if no records.
|
||||
* @param track Timer track.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetWRRecordID(int style, int &recordid, int track);
|
||||
|
||||
/**
|
||||
* Saves the WR's player name on the map on a variable.
|
||||
*
|
||||
* @param style Style to get the WR for.
|
||||
* @param wrname Reference to the name variable.
|
||||
* @param wrmaxlength Max length for the string.
|
||||
* @param track Timer track.
|
||||
* @return Returns true if the player's name has been cached. False if it hasn't. `wrname` is filled with the player's name if available, otherwise the steamid if the name isn't cached, and lastly the string "none" if neither the name or steamid is available.
|
||||
*/
|
||||
native bool Shavit_GetWRName(int style, char[] wrname, int wrmaxlength, int track);
|
||||
|
||||
/**
|
||||
* Retrieves the best time of a player.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style to get the PB for.
|
||||
* @param track Timer track.
|
||||
* @return Floating number of the player's best time for given style/track.
|
||||
*/
|
||||
native float Shavit_GetClientPB(int client, int style, int track);
|
||||
|
||||
/**
|
||||
* Sets the cached pb directly for the given client, style and track.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style to get the PB for.
|
||||
* @param track Timer track.
|
||||
* @param time Time to set
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetClientPB(int client, int style, int track, float time);
|
||||
|
||||
/**
|
||||
* Retrieves the completions of a player.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param style Style to get the Completions for.
|
||||
* @param track Timer track.
|
||||
* @return Number of the player's Completions for given style/track.
|
||||
*/
|
||||
native int Shavit_GetClientCompletions(int client, int style, int track);
|
||||
|
||||
/**
|
||||
* Get the amount of records on the current map/style on a track.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param track Timer track.
|
||||
* @return Amount of records.
|
||||
*/
|
||||
native int Shavit_GetRecordAmount(int style, int track);
|
||||
|
||||
/**
|
||||
* Calculate potential rank for a given style and time.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param time Time to check for.
|
||||
* @param track Timer track.
|
||||
* @return Map rank.
|
||||
*/
|
||||
native int Shavit_GetRankForTime(int style, float time, int track);
|
||||
|
||||
/**
|
||||
* Retrieves the time of a record from a specified rank.
|
||||
*
|
||||
* @param style Style.
|
||||
* @param rank Rank to retrieve the time from.
|
||||
* @param track Timer track.
|
||||
* @return Record time. 0.0 if none.
|
||||
*/
|
||||
native float Shavit_GetTimeForRank(int style, int rank, int track);
|
||||
|
||||
/**
|
||||
* Retrieve the WR's stage time.
|
||||
*
|
||||
* @param track Track index.
|
||||
* @param style Style index.
|
||||
* @param stage Stage number.
|
||||
* @return The stage time of the WR run. Can be 0.0 if the WR run didn't hit the stage or if the stage doesn't exist.
|
||||
*/
|
||||
native float Shavit_GetStageWR(int track, int style, int stage);
|
||||
|
||||
/**
|
||||
* Retrieve the client's PB stage time.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param track Track index.
|
||||
* @param style Style index.
|
||||
* @param stage Stage number.
|
||||
* @return The stage time of the PB run. Can be 0.0 if the PB run didn't hit the stage or if the stage doesn't exist.
|
||||
*/
|
||||
//native float Shavit_GetStagePB(int client, int track, int style, int stage);
|
||||
|
||||
//native float Shavit_GetStageWRCP(int track, int style, int stage);
|
||||
//native float Shavit_GetStagePBCP(int client, int track, int style, int stage);
|
||||
|
||||
/*
|
||||
* Used to delete a WR. Used to ensure Shavit_OnWRDeleted is ran.
|
||||
*
|
||||
* @param style Record style.
|
||||
* @param track Record track.
|
||||
* @param map Record map.
|
||||
* @param accountid -1 if recordid is -1. Otherwise you need the WR holder's Steam account ID. ([U:1:x])
|
||||
* @param recordid -1 to pull ID & accountid from the database.
|
||||
* @param delete_sql If this function should delete the record from the database. False might be useful if you're deleting things in bulk like sm_wipeplayer does.
|
||||
* @param update_cache If this function should update the WR cache & record info. False might be useful if you're deleting things in bulk like sm_wipeplayer does.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_DeleteWR(int style, int track, const char[] map, int accountid, int recordid, bool delete_sql, bool update_cache);
|
||||
|
||||
/**
|
||||
* Deletes all map records for the specified map.
|
||||
* Plugin will refresh if map is currently on.
|
||||
*
|
||||
* @param map Map name.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_WR_DeleteMap(const char[] map);
|
||||
|
||||
public SharedPlugin __pl_shavit_wr =
|
||||
{
|
||||
name = "shavit-wr",
|
||||
file = "shavit-wr.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_wr_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetClientCompletions");
|
||||
MarkNativeAsOptional("Shavit_GetClientPB");
|
||||
MarkNativeAsOptional("Shavit_SetClientPB");
|
||||
MarkNativeAsOptional("Shavit_GetRankForTime");
|
||||
MarkNativeAsOptional("Shavit_GetRecordAmount");
|
||||
MarkNativeAsOptional("Shavit_GetWorldRecord");
|
||||
MarkNativeAsOptional("Shavit_GetWRName");
|
||||
MarkNativeAsOptional("Shavit_GetWRRecordID");
|
||||
MarkNativeAsOptional("Shavit_ReloadLeaderboards");
|
||||
MarkNativeAsOptional("Shavit_WR_DeleteMap");
|
||||
MarkNativeAsOptional("Shavit_GetTimeForRank");
|
||||
MarkNativeAsOptional("Shavit_DeleteWR");
|
||||
MarkNativeAsOptional("Shavit_GetStageWR");
|
||||
MarkNativeAsOptional("Shavit_GetStagePB");
|
||||
}
|
||||
#endif
|
||||
500
addons/sourcemod/scripting/include/shavit/zones.inc
Normal file
500
addons/sourcemod/scripting/include/shavit/zones.inc
Normal file
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* shavit's Timer - zones.inc file
|
||||
* by: shavit,
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined _shavit_zones_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _shavit_zones_included
|
||||
|
||||
#define MAX_ZONES 128
|
||||
#define MAX_STAGES 69
|
||||
|
||||
enum
|
||||
{
|
||||
Zone_Start, // starts timer
|
||||
Zone_End, // stops timer
|
||||
Zone_Respawn, // respawns the player
|
||||
Zone_Stop, // stops the player's timer
|
||||
Zone_Slay, // slays (kills) players which come to this zone
|
||||
Zone_Freestyle, // ignores style physics when at this zone. e.g. WASD when SWing
|
||||
Zone_CustomSpeedLimit, // overwrites velocity limit in the zone
|
||||
Zone_Teleport, // teleports to a defined point
|
||||
Zone_CustomSpawn, // spawn position for a track. not a physical zone.
|
||||
Zone_Easybhop, // forces easybhop whether if the player is in non-easy styles or if the server has different settings
|
||||
Zone_Slide, // allows players to slide, in order to fix parts like the 5th stage of bhop_arcane
|
||||
Zone_Airaccelerate, // custom sv_airaccelerate inside this,
|
||||
Zone_Stage, // shows time when entering zone
|
||||
Zone_NoTimerGravity, // prevents the timer from setting gravity while inside this zone
|
||||
Zone_Gravity, // lets you set a specific gravity while inside this zone
|
||||
Zone_Speedmod, // creates a player_speedmod
|
||||
Zone_NoJump, // blocks the player from jumping while inside the zone
|
||||
Zone_Autobhop, // forces autobhop for the player
|
||||
ZONETYPES_SIZE
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ZF_ForceRender = (1 << 0),
|
||||
ZF_Hammerid = (1 << 1), // used by ZoneForm_{trigger_{multiple, teleport}, func_[rot_]button} sometimes
|
||||
ZF_Solid = (1 << 2), // forces the zone to physically block people...
|
||||
ZF_Origin = (1 << 4), // sTarget is the entity's origin formatted as "%X %X %X"
|
||||
};
|
||||
|
||||
// Zone Display type
|
||||
enum
|
||||
{
|
||||
ZoneDisplay_Default,
|
||||
ZoneDisplay_Flat,
|
||||
ZoneDisplay_Box,
|
||||
ZoneDisplay_None,
|
||||
ZoneDisplay_Size
|
||||
};
|
||||
|
||||
// Zone Color, maybe we just let the user decide what color they actually want..? maybe store rgba as hex string but that would be mega long for each track
|
||||
enum
|
||||
{
|
||||
ZoneColor_Default,
|
||||
ZoneColor_White,
|
||||
ZoneColor_Red,
|
||||
ZoneColor_Orange,
|
||||
ZoneColor_Yellow,
|
||||
ZoneColor_Green,
|
||||
ZoneColor_Cyan,
|
||||
ZoneColor_Blue,
|
||||
ZoneColor_Purple,
|
||||
ZoneColor_Pink,
|
||||
ZoneColor_Size
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ZoneWidth_Default,
|
||||
ZoneWidth_UltraThin,
|
||||
ZoneWidth_Thin,
|
||||
ZoneWidth_Normal,
|
||||
ZoneWidth_Thick,
|
||||
ZoneWidth_Size
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ZoneForm_Box,
|
||||
ZoneForm_trigger_multiple,
|
||||
ZoneForm_trigger_teleport,
|
||||
ZoneForm_func_button,
|
||||
ZoneForm_AreasAndClusters,
|
||||
};
|
||||
|
||||
enum struct zone_cache_t
|
||||
{
|
||||
int iType; // The type of zone. Zone_Start, Zone_End, etc...
|
||||
int iTrack; // 0 - main, 1 - bonus1 etc
|
||||
int iEntity; // Filled by Shavit_GetZone() if applicable.
|
||||
int iDatabaseID; // Can be the database ID (> 0) for "sql" sources. Non-sql sources can fill this with whatever.
|
||||
int iFlags; // The ZF_* flags.
|
||||
int iData; // Depends on the zone. Zone_Stage stores the stage number in this for example.
|
||||
float fCorner1[3]; // the hull mins. (or unused if ZoneForm_AreasAndClusters) // TODO, maybe reuse for cluster & areas?
|
||||
float fCorner2[3]; // the hull maxs. (or unused if ZoneForm_AreasAndClusters)
|
||||
float fDestination[3]; // Used by Zone_CustomSpawn, Zone_Teleport, and Zone_Stage.
|
||||
int iForm; // ZoneForm_*
|
||||
char sSource[16]; // "sql", "autobutton", "autozone", "sourcejump", "http", etc...
|
||||
char sTarget[64]; // either the hammerid or the targetname
|
||||
}
|
||||
|
||||
stock void GetZoneName(int client, int zoneType, char[] output, int size)
|
||||
{
|
||||
static char sTranslationStrings[ZONETYPES_SIZE][] = {
|
||||
"Zone_Start",
|
||||
"Zone_End",
|
||||
"Zone_Respawn",
|
||||
"Zone_Stop",
|
||||
"Zone_Slay",
|
||||
"Zone_Freestyle",
|
||||
"Zone_CustomSpeedLimit",
|
||||
"Zone_Teleport",
|
||||
"Zone_CustomSpawn",
|
||||
"Zone_Easybhop",
|
||||
"Zone_Slide",
|
||||
"Zone_Airaccelerate",
|
||||
"Zone_Stage",
|
||||
"Zone_NoTimerGravity",
|
||||
"Zone_Gravity",
|
||||
"Zone_Speedmod",
|
||||
"Zone_NoJump",
|
||||
"Zone_Autobhop",
|
||||
};
|
||||
|
||||
if (zoneType < 0 || zoneType >= ZONETYPES_SIZE)
|
||||
FormatEx(output, size, "%T", "Zone_Unknown", client);
|
||||
else
|
||||
FormatEx(output, size, "%T", sTranslationStrings[zoneType], client);
|
||||
}
|
||||
|
||||
// Please follow something like this:
|
||||
// mod_zone_start
|
||||
// mod_zone_end
|
||||
// mod_zone_checkpoint_X
|
||||
// mod_zone_bonus_X_start
|
||||
// mod_zone_bonus_X_end
|
||||
// mod_zone_bonus_X_checkpoint_X
|
||||
//
|
||||
// climb_startbutton
|
||||
// climb_endbutton
|
||||
// climb_bonusX_startbutton
|
||||
// climb_bonusX_endbutton
|
||||
//
|
||||
// climb_startzone
|
||||
// climb_endzone
|
||||
// climb_bonusX_startzone
|
||||
// climb_bonusX_endzone
|
||||
stock bool Shavit_ParseZoneTargetname(const char[] targetname, bool button, int& type, int& track, int& stage, const char[] mapname_for_log="")
|
||||
{
|
||||
track = Track_Main;
|
||||
type = -1;
|
||||
stage = 0;
|
||||
|
||||
if (strncmp(targetname, "climb_", 6) != 0
|
||||
&& (button || strncmp(targetname, "mod_zone_", 9) != 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrContains(targetname, "start") != -1)
|
||||
{
|
||||
type = Zone_Start;
|
||||
}
|
||||
else if (StrContains(targetname, "end") != -1)
|
||||
{
|
||||
type = Zone_End;
|
||||
}
|
||||
|
||||
int bonus = StrContains(targetname, "bonus");
|
||||
|
||||
if (bonus != -1)
|
||||
{
|
||||
track = Track_Bonus;
|
||||
bonus += 5; // skip past "bonus"
|
||||
if (targetname[bonus] == '_') bonus += 1;
|
||||
|
||||
if ('1' <= targetname[bonus] <= '9')
|
||||
{
|
||||
track = StringToInt(targetname[bonus]);
|
||||
|
||||
if (track < Track_Bonus || track > Track_Bonus_Last)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid track in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int checkpoint = StrContains(targetname, "checkpoint");
|
||||
|
||||
if (checkpoint != -1)
|
||||
{
|
||||
if (button)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid button (%s) (has checkpoint) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type != -1)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid type (start/end + checkpoint) in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false; // end/start & checkpoint...
|
||||
}
|
||||
|
||||
type = Zone_Stage;
|
||||
checkpoint += 10; // skip past "checkpoint"
|
||||
if (targetname[checkpoint] == '_') checkpoint += 1;
|
||||
|
||||
if ('1' <= targetname[checkpoint] <= '9')
|
||||
{
|
||||
stage = StringToInt(targetname[checkpoint]);
|
||||
|
||||
if (stage <= 0 || stage > MAX_STAGES)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid stage number in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == -1)
|
||||
{
|
||||
if (mapname_for_log[0]) LogError("invalid zone type in prebuilt map zone (%s) on %s", targetname, mapname_for_log);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player enters a zone.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param type Zone type.
|
||||
* @param track Zone track.
|
||||
* @param id Zone ID.
|
||||
* @param entity Zone trigger entity index.
|
||||
* @param data Zone data if any.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnEnterZone(int client, int type, int track, int id, int entity, int data);
|
||||
|
||||
/**
|
||||
* Called when a player leaves a zone.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param type Zone type.
|
||||
* @param track Zone track.
|
||||
* @param id Zone ID.
|
||||
* @param entity Zone trigger entity index.
|
||||
* @param data Zone data if any.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void Shavit_OnLeaveZone(int client, int type, int track, int id, int entity, int data);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
forward void Shavit_LoadZonesHere();
|
||||
|
||||
/**
|
||||
* Called when a player leaves a zone.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param stageNumber Stage number.
|
||||
* @param message The stage time message that will be printed.
|
||||
* @param maxlen The buffer size of message.
|
||||
* @return Plugin_Handled to block the timer from printing msg to the client. Plugin_Continue to let the timer print msg.
|
||||
*/
|
||||
forward Action Shavit_OnStageMessage(int client, int stageNumber, char[] message, int maxlen);
|
||||
|
||||
/**
|
||||
* Checks if a mapzone exists.
|
||||
*
|
||||
* @param type Mapzone type.
|
||||
* @param track Mapzone track, -1 to ignore track.
|
||||
* @return Boolean value.
|
||||
*/
|
||||
native bool Shavit_ZoneExists(int type, int track);
|
||||
|
||||
/**
|
||||
* Checks if a player is inside a mapzone.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param type Mapzone type.
|
||||
* @param track Mapzone track, -1 to ignore track.
|
||||
* @return Boolean value.
|
||||
*/
|
||||
native bool Shavit_InsideZone(int client, int type, int track);
|
||||
|
||||
/**
|
||||
* Gets the specified zone's data.
|
||||
*
|
||||
* @param zoneid ID of the zone we query the data of.
|
||||
* @return Zone data. 0 if none is specified.
|
||||
*/
|
||||
native int Shavit_GetZoneData(int zoneid);
|
||||
|
||||
/**
|
||||
* Gets the specified zone's flags.
|
||||
*
|
||||
* @param zoneid ID of the zone we query the flags of.
|
||||
* @return Zone flags. 0 if none is specified.
|
||||
*/
|
||||
native int Shavit_GetZoneFlags(int zoneid);
|
||||
|
||||
/**
|
||||
* Deletes all map zones for the specified map.
|
||||
* Plugin will refresh if map is currently on.
|
||||
*
|
||||
* @param map Map name.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_Zones_DeleteMap(const char[] map);
|
||||
|
||||
/**
|
||||
* Checks if a player is inside a mapzone.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param type Mapzone type.
|
||||
* @param track Mapzone track, -1 to ignore track.
|
||||
* @param zoneid Reference to variable that will hold the zone's ID.
|
||||
* @return Boolean value.
|
||||
*/
|
||||
native bool Shavit_InsideZoneGetID(int client, int type, int track, int &zoneid);
|
||||
|
||||
/**
|
||||
* Checks if a player is in the process of creating a mapzone.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return Boolean value.
|
||||
*/
|
||||
native bool Shavit_IsClientCreatingZone(int client);
|
||||
|
||||
/**
|
||||
* Retrieve the highest stage number for a given track.
|
||||
*
|
||||
* @param track Track number.
|
||||
* @return Highest stage number...
|
||||
*/
|
||||
native int Shavit_GetHighestStage(int track);
|
||||
|
||||
/**
|
||||
* Retrieve the client's current stage number.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @return The client's current stage number.
|
||||
*/
|
||||
native int Shavit_GetClientLastStage(int client);
|
||||
|
||||
/**
|
||||
* Returns the zone index for the entity if available.
|
||||
*
|
||||
* @param entity Client index.
|
||||
* @return -1 if not a zone entity. >=0 for a zone index.
|
||||
*/
|
||||
native int Shavit_GetZoneID(int entity);
|
||||
|
||||
/**
|
||||
* Returns the zone track.
|
||||
*
|
||||
* @param zoneid Zone index.
|
||||
* @return Zone track.
|
||||
*/
|
||||
native int Shavit_GetZoneTrack(int zoneid);
|
||||
|
||||
/**
|
||||
* Returns the zone type.
|
||||
*
|
||||
* @param zoneid Zone index.
|
||||
* @return Zone type.
|
||||
*/
|
||||
native int Shavit_GetZoneType(int zoneid);
|
||||
|
||||
/**
|
||||
* Sets the player's current location as their spawn location for the specified track.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param track Timer track.
|
||||
* @param anglesonly Whether to save angles only.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_SetStart(int client, int track, bool anglesonly);
|
||||
|
||||
/**
|
||||
* Deletes the player's current set start position for the specified track.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param track Timer track.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_DeleteSetStart(int client, int track);
|
||||
|
||||
/**
|
||||
* Removes all zones from memory and then reloads zones from the database & any plugins.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_ReloadZones();
|
||||
|
||||
/**
|
||||
* Removes all zones from memory and unhooks any zones and kills any created entities.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_UnloadZones();
|
||||
|
||||
/**
|
||||
* Returns the number of zones that are currently loaded in memory.
|
||||
*
|
||||
* @return The number of zones currently loaded in memory.
|
||||
*/
|
||||
native int Shavit_GetZoneCount();
|
||||
|
||||
/**
|
||||
* Retrieves the zone_cache_t for a zone.
|
||||
*
|
||||
* @param index The zone index. 0 through Shavit_GetZoneCount()-1.
|
||||
* @param zonecache The zone_cache_t struct that is retrieved from the zone.
|
||||
* @param size sizeof(zone_cache_t) to make sure the caller has a matching struct version.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_GetZone(int index, any[] zonecache, int size = sizeof(zone_cache_t));
|
||||
|
||||
/**
|
||||
* Adds a zone to memory. (Does NOT insert into DB).
|
||||
*
|
||||
* @param zonecache The zone_cache_t struct that is used to create or hook a zone.
|
||||
* @param size sizeof(zone_cache_t) to make sure the caller has a matching struct version.
|
||||
*
|
||||
* @return The zone index on success (index for a particular zone can change). <0 on failure.
|
||||
*/
|
||||
native int Shavit_AddZone(any[] zonecache, int size = sizeof(zone_cache_t));
|
||||
|
||||
/**
|
||||
* Removes a zone from memory. (Does NOT delete from DB).
|
||||
* WARNING: If there are zones after `index`, then they will be moved down in memory to fill this slot after removal.
|
||||
* This unhooks the zone's entity too.
|
||||
*
|
||||
* @param index The zone's index.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_RemoveZone(int index);
|
||||
|
||||
public SharedPlugin __pl_shavit_zones =
|
||||
{
|
||||
name = "shavit-zones",
|
||||
file = "shavit-zones.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1
|
||||
#else
|
||||
required = 0
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_shavit_zones_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("Shavit_GetZoneData");
|
||||
MarkNativeAsOptional("Shavit_GetZoneFlags");
|
||||
MarkNativeAsOptional("Shavit_GetHighestStage");
|
||||
MarkNativeAsOptional("Shavit_InsideZone");
|
||||
MarkNativeAsOptional("Shavit_InsideZoneGetID");
|
||||
MarkNativeAsOptional("Shavit_IsClientCreatingZone");
|
||||
MarkNativeAsOptional("Shavit_ZoneExists");
|
||||
MarkNativeAsOptional("Shavit_Zones_DeleteMap");
|
||||
MarkNativeAsOptional("Shavit_SetStart");
|
||||
MarkNativeAsOptional("Shavit_DeleteSetStart");
|
||||
MarkNativeAsOptional("Shavit_GetClientLastStage");
|
||||
MarkNativeAsOptional("Shavit_GetZoneTrack");
|
||||
MarkNativeAsOptional("Shavit_GetZoneType");
|
||||
MarkNativeAsOptional("Shavit_GetZoneID");
|
||||
MarkNativeAsOptional("Shavit_ReloadZones");
|
||||
MarkNativeAsOptional("Shavit_UnloadZones");
|
||||
MarkNativeAsOptional("Shavit_GetZoneCount");
|
||||
MarkNativeAsOptional("Shavit_GetZone");
|
||||
MarkNativeAsOptional("Shavit_AddZone");
|
||||
MarkNativeAsOptional("Shavit_RemoveZone");
|
||||
}
|
||||
#endif
|
||||
50
addons/sourcemod/scripting/include/srcwr/floppy.inc
Normal file
50
addons/sourcemod/scripting/include/srcwr/floppy.inc
Normal file
@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// Copyright 2025 rtldg <rtldg@protonmail.com>
|
||||
|
||||
#if defined _srcwrfloppy_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _srcwrfloppy_included
|
||||
#pragma semicolon 1
|
||||
|
||||
|
||||
typeset ReplaySavedCallback {
|
||||
function void(bool saved, any value, char[] sPath);
|
||||
}
|
||||
|
||||
|
||||
// Don't modify the `playerrecording` ArrayList until the ReplaySavedCallback is called... OR ELSE!!!!
|
||||
native void SRCWRFloppy_AsyncSaveReplay(
|
||||
ReplaySavedCallback callback // what to call when saved
|
||||
, any value // what to pass along to the callback
|
||||
, char[] wrpath
|
||||
, char[] copypath
|
||||
, char[] header
|
||||
, int headersize
|
||||
, ArrayList playerrecording
|
||||
, int totalframes
|
||||
);
|
||||
|
||||
|
||||
public Extension __ext_srcwrfloppy =
|
||||
{
|
||||
name = "srcwr💾",
|
||||
file = "srcwr💾.ext",
|
||||
#if defined AUTOLOAD_EXTENSIONS
|
||||
autoload = 1,
|
||||
#else
|
||||
autoload = 0,
|
||||
#endif
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_EXTENSIONS
|
||||
public void __ext_srcwrfloppy_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("SRCWRFloppy_AsyncSaveReplay");
|
||||
}
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
2224
addons/sourcemod/scripting/shavit-checkpoints.sp
Normal file
2224
addons/sourcemod/scripting/shavit-checkpoints.sp
Normal file
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
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
File diff suppressed because it is too large
Load Diff
803
addons/sourcemod/scripting/shavit-replay-recorder.sp
Normal file
803
addons/sourcemod/scripting/shavit-replay-recorder.sp
Normal file
@ -0,0 +1,803 @@
|
||||
/*
|
||||
* shavit's Timer - Replay Recorder
|
||||
* by: shavit, rtldg, KiD Fearless, Ciallo-Ani, BoomShotKapow
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <convar_class>
|
||||
|
||||
#include <shavit/replay-recorder>
|
||||
|
||||
#include <shavit/core>
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <shavit/replay-playback>
|
||||
#include <shavit/zones>
|
||||
|
||||
#include <shavit/replay-file>
|
||||
#include <shavit/replay-stocks.sp>
|
||||
|
||||
#undef REQUIRE_EXTENSIONS
|
||||
#include <srcwr/floppy>
|
||||
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] Replay Recorder",
|
||||
author = "shavit, rtldg, KiD Fearless, Ciallo-Ani, BoomShotKapow",
|
||||
description = "A replay recorder for shavit's bhop timer.",
|
||||
version = SHAVIT_VERSION,
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
}
|
||||
|
||||
enum struct finished_run_info
|
||||
{
|
||||
int iSteamID;
|
||||
int style;
|
||||
float time;
|
||||
int jumps;
|
||||
int strafes;
|
||||
float sync;
|
||||
int track;
|
||||
float oldtime;
|
||||
float perfs;
|
||||
float avgvel;
|
||||
float maxvel;
|
||||
int timestamp;
|
||||
float fZoneOffset[2];
|
||||
}
|
||||
|
||||
bool gB_Late = false;
|
||||
char gS_Map[PLATFORM_MAX_PATH];
|
||||
float gF_Tickrate = 0.0;
|
||||
|
||||
int gI_Styles = 0;
|
||||
char gS_ReplayFolder[PLATFORM_MAX_PATH];
|
||||
|
||||
Convar gCV_Enabled = null;
|
||||
Convar gCV_PlaybackPostRunTime = null;
|
||||
Convar gCV_PlaybackPreRunTime = null;
|
||||
Convar gCV_PreRunAlways = null;
|
||||
Convar gCV_TimeLimit = null;
|
||||
|
||||
Handle gH_ShouldSaveReplayCopy = null;
|
||||
Handle gH_OnReplaySaved = null;
|
||||
|
||||
bool gB_RecordingEnabled[MAXPLAYERS+1]; // just a simple thing to prevent plugin reloads from recording half-replays
|
||||
|
||||
// stuff related to postframes
|
||||
finished_run_info gA_FinishedRunInfo[MAXPLAYERS+1];
|
||||
bool gB_GrabbingPostFrames[MAXPLAYERS+1];
|
||||
Handle gH_PostFramesTimer[MAXPLAYERS+1];
|
||||
int gI_PlayerFinishFrame[MAXPLAYERS+1];
|
||||
|
||||
// we use gI_PlayerFrames instead of grabbing gA_PlayerFrames.Length because the ArrayList is resized to handle 2s worth of extra frames to reduce how often we have to resize it
|
||||
int gI_PlayerFrames[MAXPLAYERS+1];
|
||||
int gI_PlayerPrerunFrames[MAXPLAYERS+1];
|
||||
ArrayList gA_PlayerFrames[MAXPLAYERS+1];
|
||||
|
||||
int gI_HijackFrames[MAXPLAYERS+1];
|
||||
float gF_HijackedAngles[MAXPLAYERS+1][2];
|
||||
bool gB_HijackFramesKeepOnStart[MAXPLAYERS+1];
|
||||
|
||||
bool gB_ReplayPlayback = false;
|
||||
bool gB_Floppy = false;
|
||||
|
||||
//#include <TickRateControl>
|
||||
forward void TickRate_OnTickRateChanged(float fOld, float fNew);
|
||||
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||
{
|
||||
CreateNative("Shavit_GetClientFrameCount", Native_GetClientFrameCount);
|
||||
CreateNative("Shavit_GetPlayerPreFrames", Native_GetPlayerPreFrames);
|
||||
CreateNative("Shavit_GetReplayData", Native_GetReplayData);
|
||||
CreateNative("Shavit_HijackAngles", Native_HijackAngles);
|
||||
CreateNative("Shavit_SetReplayData", Native_SetReplayData);
|
||||
CreateNative("Shavit_SetPlayerPreFrames", Native_SetPlayerPreFrames);
|
||||
|
||||
if (!FileExists("cfg/sourcemod/plugin.shavit-replay-recorder.cfg") && FileExists("cfg/sourcemod/plugin.shavit-replay.cfg"))
|
||||
{
|
||||
File source = OpenFile("cfg/sourcemod/plugin.shavit-replay.cfg", "r");
|
||||
File destination = OpenFile("cfg/sourcemod/plugin.shavit-replay-recorder.cfg", "w");
|
||||
|
||||
if (source && destination)
|
||||
{
|
||||
char line[512];
|
||||
|
||||
while (!source.EndOfFile() && source.ReadLine(line, sizeof(line)))
|
||||
{
|
||||
destination.WriteLine("%s", line);
|
||||
}
|
||||
}
|
||||
|
||||
delete destination;
|
||||
delete source;
|
||||
}
|
||||
|
||||
RegPluginLibrary("shavit-replay-recorder");
|
||||
|
||||
gB_Late = late;
|
||||
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
gH_ShouldSaveReplayCopy = CreateGlobalForward("Shavit_ShouldSaveReplayCopy", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
|
||||
gH_OnReplaySaved = CreateGlobalForward("Shavit_OnReplaySaved", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_String, Param_Cell, Param_Cell, Param_Cell, Param_String);
|
||||
|
||||
gCV_Enabled = new Convar("shavit_replay_recording_enabled", "1", "Enable replay bot functionality?", 0, true, 0.0, true, 1.0);
|
||||
gCV_PlaybackPostRunTime = new Convar("shavit_replay_postruntime", "1.5", "Time (in seconds) to record after a player enters the end zone.", 0, true, 0.0, true, 2.0);
|
||||
gCV_PreRunAlways = new Convar("shavit_replay_prerun_always", "1", "Record prerun frames outside the start zone?", 0, true, 0.0, true, 1.0);
|
||||
gCV_PlaybackPreRunTime = new Convar("shavit_replay_preruntime", "1.5", "Time (in seconds) to record before a player leaves start zone.", 0, true, 0.0, true, 2.0);
|
||||
gCV_TimeLimit = new Convar("shavit_replay_timelimit", "7200.0", "Maximum amount of time (in seconds) to allow saving to disk.\nDefault is 7200 (2 hours)\n0 - Disabled (no replays will be recorded)", 0, true, 0.0);
|
||||
|
||||
Convar.AutoExecConfig();
|
||||
|
||||
gF_Tickrate = (1.0 / GetTickInterval());
|
||||
|
||||
gB_ReplayPlayback = LibraryExists("shavit-replay-playback");
|
||||
gB_Floppy = LibraryExists("srcwr💾");
|
||||
|
||||
if (gB_Late)
|
||||
{
|
||||
Shavit_OnStyleConfigLoaded(Shavit_GetStyleCount());
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsValidClient(i) && !IsFakeClient(i))
|
||||
{
|
||||
OnClientPutInServer(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLibraryAdded(const char[] name)
|
||||
{
|
||||
if( StrEqual(name, "shavit-replay-playback"))
|
||||
{
|
||||
gB_ReplayPlayback = true;
|
||||
}
|
||||
else if (StrEqual(name, "srcwr💾"))
|
||||
{
|
||||
gB_Floppy = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLibraryRemoved(const char[] name)
|
||||
{
|
||||
if (StrEqual(name, "shavit-replay-playback"))
|
||||
{
|
||||
gB_ReplayPlayback = false;
|
||||
}
|
||||
else if (StrEqual(name, "srcwr💾"))
|
||||
{
|
||||
gB_Floppy = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMapStart()
|
||||
{
|
||||
GetLowercaseMapName(gS_Map);
|
||||
}
|
||||
|
||||
public void Shavit_OnStyleConfigLoaded(int styles)
|
||||
{
|
||||
if (!Shavit_GetReplayFolderPath_Stock(gS_ReplayFolder))
|
||||
{
|
||||
SetFailState("Could not load the replay bots' configuration file. Make sure it exists (addons/sourcemod/configs/shavit-replay.cfg) and follows the proper syntax!");
|
||||
}
|
||||
|
||||
gI_Styles = styles;
|
||||
|
||||
Shavit_Replay_CreateDirectories(gS_ReplayFolder, gI_Styles);
|
||||
}
|
||||
|
||||
public void OnClientPutInServer(int client)
|
||||
{
|
||||
ClearFrames(client);
|
||||
}
|
||||
|
||||
public void OnClientDisconnect(int client)
|
||||
{
|
||||
gB_RecordingEnabled[client] = false; // reset a little state...
|
||||
|
||||
if (gB_GrabbingPostFrames[client])
|
||||
{
|
||||
FinishGrabbingPostFrames(client, gA_FinishedRunInfo[client]);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClientDisconnect_Post(int client)
|
||||
{
|
||||
// This runs after shavit-misc has cloned the handle
|
||||
delete gA_PlayerFrames[client];
|
||||
}
|
||||
|
||||
public void TickRate_OnTickRateChanged(float fOld, float fNew)
|
||||
{
|
||||
gF_Tickrate = fNew;
|
||||
}
|
||||
|
||||
void ClearFrames(int client)
|
||||
{
|
||||
delete gA_PlayerFrames[client];
|
||||
gA_PlayerFrames[client] = new ArrayList(sizeof(frame_t));
|
||||
gI_PlayerFrames[client] = 0;
|
||||
gI_PlayerPrerunFrames[client] = 0;
|
||||
gI_PlayerFinishFrame[client] = 0;
|
||||
gI_HijackFrames[client] = 0;
|
||||
gB_HijackFramesKeepOnStart[client] = false;
|
||||
}
|
||||
|
||||
public Action Shavit_OnStart(int client)
|
||||
{
|
||||
gB_RecordingEnabled[client] = true;
|
||||
|
||||
if (!gB_HijackFramesKeepOnStart[client])
|
||||
{
|
||||
gI_HijackFrames[client] = 0;
|
||||
}
|
||||
|
||||
if (gB_GrabbingPostFrames[client])
|
||||
{
|
||||
FinishGrabbingPostFrames(client, gA_FinishedRunInfo[client]);
|
||||
}
|
||||
|
||||
int iMaxPreFrames = RoundToFloor(gCV_PlaybackPreRunTime.FloatValue * gF_Tickrate / Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "speed"));
|
||||
bool bInStart = Shavit_InsideZone(client, Zone_Start, Shavit_GetClientTrack(client));
|
||||
|
||||
if (bInStart)
|
||||
{
|
||||
int iFrameDifference = gI_PlayerFrames[client] - iMaxPreFrames;
|
||||
|
||||
if (iFrameDifference > 0)
|
||||
{
|
||||
// For too many extra frames, we'll just shift the preframes to the start of the array.
|
||||
if (iFrameDifference > 100)
|
||||
{
|
||||
for (int i = iFrameDifference; i < gI_PlayerFrames[client]; i++)
|
||||
{
|
||||
gA_PlayerFrames[client].SwapAt(i, i-iFrameDifference);
|
||||
}
|
||||
|
||||
gI_PlayerFrames[client] = iMaxPreFrames;
|
||||
}
|
||||
else // iFrameDifference isn't that bad, just loop through and erase.
|
||||
{
|
||||
while (iFrameDifference--)
|
||||
{
|
||||
gA_PlayerFrames[client].Erase(0);
|
||||
gI_PlayerFrames[client]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!gCV_PreRunAlways.BoolValue)
|
||||
{
|
||||
ClearFrames(client);
|
||||
}
|
||||
}
|
||||
|
||||
gI_PlayerPrerunFrames[client] = gI_PlayerFrames[client];
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public void Shavit_OnStop(int client)
|
||||
{
|
||||
if (gB_GrabbingPostFrames[client])
|
||||
{
|
||||
FinishGrabbingPostFrames(client, gA_FinishedRunInfo[client]);
|
||||
}
|
||||
|
||||
ClearFrames(client);
|
||||
}
|
||||
|
||||
public Action Timer_PostFrames(Handle timer, int client)
|
||||
{
|
||||
gH_PostFramesTimer[client] = null;
|
||||
FinishGrabbingPostFrames(client, gA_FinishedRunInfo[client]);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
void FinishGrabbingPostFrames(int client, finished_run_info info)
|
||||
{
|
||||
gB_GrabbingPostFrames[client] = false;
|
||||
delete gH_PostFramesTimer[client];
|
||||
|
||||
DoReplaySaverCallbacks(info.iSteamID, client, info.style, info.time, info.jumps, info.strafes, info.sync, info.track, info.oldtime, info.perfs, info.avgvel, info.maxvel, info.timestamp, info.fZoneOffset);
|
||||
}
|
||||
|
||||
float ExistingWrReplayLength(int style, int track)
|
||||
{
|
||||
if (gB_ReplayPlayback)
|
||||
{
|
||||
return Shavit_GetReplayLength(style, track);
|
||||
}
|
||||
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
Shavit_GetReplayFilePath(style, track, gS_Map, gS_ReplayFolder, sPath);
|
||||
|
||||
replay_header_t header;
|
||||
File f = ReadReplayHeader(sPath, header, style, track);
|
||||
|
||||
if (f != null)
|
||||
{
|
||||
delete f;
|
||||
return header.fTime;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void DoReplaySaverCallbacks(int iSteamID, int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp, float fZoneOffset[2])
|
||||
{
|
||||
gA_PlayerFrames[client].Resize(gI_PlayerFrames[client]);
|
||||
|
||||
bool isTooLong = (gCV_TimeLimit.FloatValue > 0.0 && time > gCV_TimeLimit.FloatValue);
|
||||
|
||||
float length = ExistingWrReplayLength(style, track);
|
||||
bool isBestReplay = (length == 0.0 || time < length);
|
||||
|
||||
Action action = Plugin_Continue;
|
||||
Call_StartForward(gH_ShouldSaveReplayCopy);
|
||||
Call_PushCell(client);
|
||||
Call_PushCell(style);
|
||||
Call_PushCell(time);
|
||||
Call_PushCell(jumps);
|
||||
Call_PushCell(strafes);
|
||||
Call_PushCell(sync);
|
||||
Call_PushCell(track);
|
||||
Call_PushCell(oldtime);
|
||||
Call_PushCell(perfs);
|
||||
Call_PushCell(avgvel);
|
||||
Call_PushCell(maxvel);
|
||||
Call_PushCell(timestamp);
|
||||
Call_PushCell(isBestReplay);
|
||||
Call_PushCell(isTooLong);
|
||||
Call_Finish(action);
|
||||
|
||||
bool makeCopy = (action != Plugin_Continue);
|
||||
bool makeReplay = (isBestReplay && !isTooLong);
|
||||
|
||||
if (!makeCopy && !makeReplay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char sName[MAX_NAME_LENGTH];
|
||||
GetClientName(client, sName, sizeof(sName));
|
||||
ReplaceString(sName, MAX_NAME_LENGTH, "#", "?");
|
||||
|
||||
int postframes = gI_PlayerFrames[client] - gI_PlayerFinishFrame[client];
|
||||
|
||||
ArrayList playerrecording = view_as<ArrayList>(CloneHandle(gA_PlayerFrames[client]));
|
||||
|
||||
DataPack dp = new DataPack();
|
||||
dp.WriteCell(GetClientSerial(client));
|
||||
dp.WriteCell(style);
|
||||
dp.WriteCell(time);
|
||||
dp.WriteCell(jumps);
|
||||
dp.WriteCell(strafes);
|
||||
dp.WriteCell(sync);
|
||||
dp.WriteCell(track);
|
||||
dp.WriteCell(oldtime);
|
||||
dp.WriteCell(perfs);
|
||||
dp.WriteCell(avgvel);
|
||||
dp.WriteCell(maxvel);
|
||||
dp.WriteCell(timestamp);
|
||||
dp.WriteCell(isBestReplay);
|
||||
dp.WriteCell(isTooLong);
|
||||
dp.WriteCell(makeCopy);
|
||||
dp.WriteCell(playerrecording);
|
||||
dp.WriteCell(gI_PlayerPrerunFrames[client]);
|
||||
dp.WriteCell(postframes);
|
||||
dp.WriteString(sName);
|
||||
|
||||
if (gB_Floppy)
|
||||
{
|
||||
char buf[512];
|
||||
int headersize = WriteReplayHeaderToBuffer(buf, style, track, time, iSteamID, gI_PlayerPrerunFrames[client], postframes, fZoneOffset, gI_PlayerFrames[client], gF_Tickrate, gS_Map);
|
||||
|
||||
char wrpath[PLATFORM_MAX_PATH], copypath[PLATFORM_MAX_PATH];
|
||||
if (makeReplay)
|
||||
FormatEx(wrpath, sizeof(wrpath),
|
||||
track>0?"%s/%d/%s_%d.replay" : "%s/%d/%s.replay",
|
||||
gS_ReplayFolder, style, gS_Map, track
|
||||
);
|
||||
if (makeCopy)
|
||||
FormatEx(copypath, sizeof(copypath), "%s/copy/%d_%d_%s.replay", gS_ReplayFolder, timestamp, iSteamID, gS_Map);
|
||||
|
||||
SRCWRFloppy_AsyncSaveReplay(
|
||||
FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem
|
||||
, dp
|
||||
, wrpath
|
||||
, copypath
|
||||
, buf
|
||||
, headersize
|
||||
, playerrecording
|
||||
, gI_PlayerFrames[client]
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
bool saved = SaveReplay(style, track, time, iSteamID, gI_PlayerPrerunFrames[client], playerrecording, gI_PlayerFrames[client], postframes, timestamp, fZoneOffset, makeCopy, makeReplay, sPath, sizeof(sPath));
|
||||
FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem(saved, dp, sPath)
|
||||
}
|
||||
|
||||
ClearFrames(client);
|
||||
}
|
||||
|
||||
void FloppyAsynchronouslySavedMyReplayWhichWasNiceOfThem(bool saved, any value, char[] sPath)
|
||||
{
|
||||
DataPack dp = value;
|
||||
dp.Reset();
|
||||
|
||||
int client = GetClientFromSerial(dp.ReadCell());
|
||||
int style = dp.ReadCell();
|
||||
float time = dp.ReadCell();
|
||||
int jumps = dp.ReadCell();
|
||||
int strafes = dp.ReadCell();
|
||||
float sync = dp.ReadCell();
|
||||
int track = dp.ReadCell();
|
||||
float oldtime = dp.ReadCell();
|
||||
float perfs = dp.ReadCell();
|
||||
float avgvel = dp.ReadCell();
|
||||
float maxvel = dp.ReadCell();
|
||||
int timestamp = dp.ReadCell();
|
||||
bool isBestReplay = dp.ReadCell();
|
||||
bool isTooLong = dp.ReadCell();
|
||||
bool makeCopy = dp.ReadCell();
|
||||
ArrayList playerrecording = dp.ReadCell();
|
||||
int preframes = dp.ReadCell();
|
||||
int postframes = dp.ReadCell();
|
||||
char sName[MAX_NAME_LENGTH];
|
||||
dp.ReadString(sName, sizeof(sName));
|
||||
|
||||
if (!saved)
|
||||
{
|
||||
LogError("Failed to save replay... Skipping OnReplaySaved");
|
||||
delete playerrecording; // importante!
|
||||
return;
|
||||
}
|
||||
|
||||
Call_StartForward(gH_OnReplaySaved);
|
||||
Call_PushCell(client);
|
||||
Call_PushCell(style);
|
||||
Call_PushCell(time);
|
||||
Call_PushCell(jumps);
|
||||
Call_PushCell(strafes);
|
||||
Call_PushCell(sync);
|
||||
Call_PushCell(track);
|
||||
Call_PushCell(oldtime);
|
||||
Call_PushCell(perfs);
|
||||
Call_PushCell(avgvel);
|
||||
Call_PushCell(maxvel);
|
||||
Call_PushCell(timestamp);
|
||||
Call_PushCell(isBestReplay);
|
||||
Call_PushCell(isTooLong);
|
||||
Call_PushCell(makeCopy);
|
||||
Call_PushString(sPath);
|
||||
Call_PushCell(playerrecording);
|
||||
Call_PushCell(preframes);
|
||||
Call_PushCell(postframes);
|
||||
Call_PushString(sName);
|
||||
Call_Finish();
|
||||
|
||||
delete playerrecording;
|
||||
}
|
||||
|
||||
public void Shavit_OnFinish(int client, int style, float time, int jumps, int strafes, float sync, int track, float oldtime, float perfs, float avgvel, float maxvel, int timestamp)
|
||||
{
|
||||
if (Shavit_IsPracticeMode(client) || !gCV_Enabled.BoolValue || (gI_PlayerFrames[client]-gI_PlayerPrerunFrames[client] <= 10))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Someone using checkpoints presumably
|
||||
if (gB_GrabbingPostFrames[client])
|
||||
{
|
||||
FinishGrabbingPostFrames(client, gA_FinishedRunInfo[client]);
|
||||
}
|
||||
|
||||
gI_PlayerFinishFrame[client] = gI_PlayerFrames[client];
|
||||
|
||||
float fZoneOffset[2];
|
||||
fZoneOffset[0] = Shavit_GetZoneOffset(client, 0);
|
||||
fZoneOffset[1] = Shavit_GetZoneOffset(client, 1);
|
||||
|
||||
if (gCV_PlaybackPostRunTime.FloatValue > 0.0)
|
||||
{
|
||||
finished_run_info info;
|
||||
info.iSteamID = GetSteamAccountID(client);
|
||||
info.style = style;
|
||||
info.time = time;
|
||||
info.jumps = jumps;
|
||||
info.strafes = strafes;
|
||||
info.sync = sync;
|
||||
info.track = track;
|
||||
info.oldtime = oldtime;
|
||||
info.perfs = perfs;
|
||||
info.avgvel = avgvel;
|
||||
info.maxvel = maxvel;
|
||||
info.timestamp = timestamp;
|
||||
info.fZoneOffset = fZoneOffset;
|
||||
|
||||
gA_FinishedRunInfo[client] = info;
|
||||
gB_GrabbingPostFrames[client] = true;
|
||||
delete gH_PostFramesTimer[client];
|
||||
gH_PostFramesTimer[client] = CreateTimer(gCV_PlaybackPostRunTime.FloatValue, Timer_PostFrames, client, TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoReplaySaverCallbacks(GetSteamAccountID(client), client, style, time, jumps, strafes, sync, track, oldtime, perfs, avgvel, maxvel, timestamp, fZoneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
bool SaveReplay(int style, int track, float time, int steamid, int preframes, ArrayList playerrecording, int iSize, int postframes, int timestamp, float fZoneOffset[2], bool saveCopy, bool saveWR, char[] sPath, int sPathLen)
|
||||
{
|
||||
char sTrack[4];
|
||||
FormatEx(sTrack, 4, "_%d", track);
|
||||
|
||||
File fWR = null;
|
||||
File fCopy = null;
|
||||
|
||||
if (saveCopy)
|
||||
{
|
||||
FormatEx(sPath, sPathLen, "%s/copy/%d_%d_%s.replay", gS_ReplayFolder, timestamp, steamid, gS_Map);
|
||||
|
||||
if (!(fCopy = OpenFile(sPath, "wb+")))
|
||||
{
|
||||
LogError("Failed to open 'copy' replay file for writing. ('%s')", sPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (saveWR)
|
||||
{
|
||||
FormatEx(sPath, sPathLen, "%s/%d/%s%s.replay", gS_ReplayFolder, style, gS_Map, (track > 0)? sTrack:"");
|
||||
|
||||
if (!(fWR = OpenFile(sPath, "wb+")))
|
||||
{
|
||||
LogError("Failed to open WR replay file for writing. ('%s')", sPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fWR && !fCopy)
|
||||
{
|
||||
// I want to try and salvage the replay file so let's write it out to a random
|
||||
// file and hope people read the error log to figure out what happened...
|
||||
// I'm not really sure how we could reach this though as
|
||||
// `Shavit_Replay_CreateDirectories` should have failed if it couldn't create
|
||||
// a test file.
|
||||
FormatEx(sPath, sPathLen, "%s/%d_%s%s_%d.replay", gS_ReplayFolder, style, gS_Map, sTrack, iSize-preframes-postframes);
|
||||
|
||||
if (!(fWR = OpenFile(sPath, "wb+")))
|
||||
{
|
||||
LogError("Couldn't open a WR, 'copy', or 'salvage' replay file....");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogError("Couldn't open a WR or 'copy' replay file. Writing 'salvage' replay @ (style %d) '%s'", style, sPath);
|
||||
}
|
||||
|
||||
if (fWR)
|
||||
{
|
||||
WriteReplayHeader(fWR, style, track, time, steamid, preframes, postframes, fZoneOffset, iSize, gF_Tickrate, gS_Map);
|
||||
}
|
||||
|
||||
if (fCopy)
|
||||
{
|
||||
WriteReplayHeader(fCopy, style, track, time, steamid, preframes, postframes, fZoneOffset, iSize, gF_Tickrate, gS_Map);
|
||||
}
|
||||
|
||||
WriteReplayFrames(playerrecording, iSize, fWR, fCopy);
|
||||
|
||||
delete fWR;
|
||||
delete fCopy;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnPlayerRunCmdPost(int client, int buttons, int impulse, const float vel[3], const float angles[3], int weapon, int subtype, int cmdnum, int tickcount, int seed, const int mouse[2])
|
||||
{
|
||||
static bool resizeFailed[MAXPLAYERS+1];
|
||||
|
||||
if (resizeFailed[client]) // rip
|
||||
{
|
||||
resizeFailed[client] = false;
|
||||
gB_RecordingEnabled[client] = false;
|
||||
ClearFrames(client);
|
||||
LogError("failed to resize frames for %N... clearing frames I guess...", client);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFakeClient(client) || !IsPlayerAlive(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gA_PlayerFrames[client] || !gB_RecordingEnabled[client])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gB_GrabbingPostFrames[client] && !(Shavit_ReplayEnabledStyle(Shavit_GetBhopStyle(client)) && Shavit_GetTimerStatus(client) == Timer_Running))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((gI_PlayerFrames[client] / gF_Tickrate) > gCV_TimeLimit.FloatValue)
|
||||
{
|
||||
if (gI_HijackFrames[client])
|
||||
{
|
||||
gI_HijackFrames[client] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Shavit_ShouldProcessFrame(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (gA_PlayerFrames[client].Length <= gI_PlayerFrames[client])
|
||||
{
|
||||
resizeFailed[client] = true;
|
||||
// Add about two seconds worth of frames so we don't have to resize so often
|
||||
gA_PlayerFrames[client].Resize(gI_PlayerFrames[client] + (RoundToCeil(gF_Tickrate) * 2));
|
||||
//PrintToChat(client, "resizing %d -> %d", gI_PlayerFrames[client], gA_PlayerFrames[client].Length);
|
||||
resizeFailed[client] = false;
|
||||
}
|
||||
|
||||
frame_t aFrame;
|
||||
GetClientAbsOrigin(client, aFrame.pos);
|
||||
|
||||
if (!gI_HijackFrames[client])
|
||||
{
|
||||
float vecEyes[3];
|
||||
GetClientEyeAngles(client, vecEyes);
|
||||
aFrame.ang[0] = vecEyes[0];
|
||||
aFrame.ang[1] = vecEyes[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
aFrame.ang = gF_HijackedAngles[client];
|
||||
--gI_HijackFrames[client];
|
||||
}
|
||||
|
||||
aFrame.buttons = buttons;
|
||||
aFrame.flags = GetEntityFlags(client);
|
||||
aFrame.mt = GetEntityMoveType(client);
|
||||
|
||||
aFrame.mousexy = (mouse[0] & 0xFFFF) | ((mouse[1] & 0xFFFF) << 16);
|
||||
aFrame.vel = LimitMoveVelFloat(vel[0]) | (LimitMoveVelFloat(vel[1]) << 16);
|
||||
|
||||
gA_PlayerFrames[client].SetArray(gI_PlayerFrames[client]++, aFrame, sizeof(frame_t));
|
||||
}
|
||||
|
||||
stock int LimitMoveVelFloat(float vel)
|
||||
{
|
||||
int x = RoundToCeil(vel);
|
||||
return ((x < -666) ? -666 : ((x > 666) ? 666 : x)) & 0xFFFF;
|
||||
}
|
||||
|
||||
public int Native_GetClientFrameCount(Handle handler, int numParams)
|
||||
{
|
||||
return gI_PlayerFrames[GetNativeCell(1)];
|
||||
}
|
||||
|
||||
public int Native_GetPlayerPreFrames(Handle handler, int numParams)
|
||||
{
|
||||
return gI_PlayerPrerunFrames[GetNativeCell(1)];
|
||||
}
|
||||
|
||||
public int Native_SetPlayerPreFrames(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
int preframes = GetNativeCell(2);
|
||||
|
||||
gI_PlayerPrerunFrames[client] = preframes;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int Native_GetReplayData(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
bool cheapCloneHandle = view_as<bool>(GetNativeCell(2));
|
||||
Handle cloned = null;
|
||||
|
||||
if(gA_PlayerFrames[client] != null)
|
||||
{
|
||||
ArrayList frames = cheapCloneHandle ? gA_PlayerFrames[client] : gA_PlayerFrames[client].Clone();
|
||||
frames.Resize(gI_PlayerFrames[client]);
|
||||
cloned = CloneHandle(frames, plugin); // set the calling plugin as the handle owner
|
||||
|
||||
if (!cheapCloneHandle)
|
||||
{
|
||||
// Only hit for .Clone()'d handles. .Clone() != CloneHandle()
|
||||
CloseHandle(frames);
|
||||
}
|
||||
}
|
||||
|
||||
return view_as<int>(cloned);
|
||||
}
|
||||
|
||||
public int Native_SetReplayData(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
ArrayList data = view_as<ArrayList>(GetNativeCell(2));
|
||||
bool cheapCloneHandle = view_as<bool>(GetNativeCell(3));
|
||||
|
||||
if (gB_GrabbingPostFrames[client])
|
||||
{
|
||||
FinishGrabbingPostFrames(client, gA_FinishedRunInfo[client]);
|
||||
}
|
||||
|
||||
// Player starts run, reconnects, savestate reloads, and this needs to be true...
|
||||
gB_RecordingEnabled[client] = true;
|
||||
|
||||
if (cheapCloneHandle)
|
||||
{
|
||||
data = view_as<ArrayList>(CloneHandle(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
data = data.Clone();
|
||||
}
|
||||
|
||||
delete gA_PlayerFrames[client];
|
||||
gA_PlayerFrames[client] = data;
|
||||
gI_PlayerFrames[client] = data.Length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int Native_HijackAngles(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
gF_HijackedAngles[client][0] = view_as<float>(GetNativeCell(2));
|
||||
gF_HijackedAngles[client][1] = view_as<float>(GetNativeCell(3));
|
||||
|
||||
int ticks = GetNativeCell(4);
|
||||
|
||||
if (ticks == -1)
|
||||
{
|
||||
float latency = GetClientLatency(client, NetFlow_Both);
|
||||
|
||||
if (latency > 0.0)
|
||||
{
|
||||
ticks = RoundToCeil(latency / GetTickInterval()) + 1;
|
||||
//PrintToChat(client, "%f %f %d", latency, GetTickInterval(), ticks);
|
||||
gI_HijackFrames[client] = ticks;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gI_HijackFrames[client] = ticks;
|
||||
}
|
||||
|
||||
gB_HijackFramesKeepOnStart[client] = (numParams < 5) ? false : view_as<bool>(GetNativeCell(5));
|
||||
return ticks;
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* shavit's Timer - Sounds
|
||||
* by: shavit
|
||||
* by: shavit, KiD Fearless
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This file is part of shavit's Timer.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
@ -16,15 +17,18 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <convar_class>
|
||||
#include <dhooks>
|
||||
|
||||
#include <shavit/core>
|
||||
#include <shavit/wr>
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <shavit>
|
||||
#include <shavit/hud>
|
||||
|
||||
#pragma newdecls required
|
||||
#pragma semicolon 1
|
||||
@ -47,7 +51,7 @@ Handle gH_OnPlaySound = null;
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] Sounds",
|
||||
author = "shavit",
|
||||
author = "shavit, KiD Fearless",
|
||||
description = "Play custom sounds when timer-related events happen.",
|
||||
version = SHAVIT_VERSION,
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
@ -61,14 +65,6 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnAllPluginsLoaded()
|
||||
{
|
||||
if(!LibraryExists("shavit-wr"))
|
||||
{
|
||||
SetFailState("shavit-wr is required for the plugin to work.");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
// cache
|
||||
@ -126,7 +122,6 @@ public void OnMapStart()
|
||||
{
|
||||
SetFailState("Cannot open \"configs/shavit-sounds.cfg\". Make sure this file exists and that the server has read permissions to it.");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
char sLine[PLATFORM_MAX_PATH*2];
|
||||
@ -150,27 +145,22 @@ public void OnMapStart()
|
||||
{
|
||||
gA_FirstSounds.PushString(sExploded[1]);
|
||||
}
|
||||
|
||||
else if(StrEqual(sExploded[0], "personal"))
|
||||
{
|
||||
gA_PersonalSounds.PushString(sExploded[1]);
|
||||
}
|
||||
|
||||
else if(StrEqual(sExploded[0], "world"))
|
||||
{
|
||||
gA_WorldSounds.PushString(sExploded[1]);
|
||||
}
|
||||
|
||||
else if(StrEqual(sExploded[0], "worst"))
|
||||
{
|
||||
gA_WorstSounds.PushString(sExploded[1]);
|
||||
}
|
||||
|
||||
else if(StrEqual(sExploded[0], "worse") || StrEqual(sExploded[0], "noimprovement"))
|
||||
{
|
||||
gA_NoImprovementSounds.PushString(sExploded[1]);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
gSM_RankSounds.SetString(sExploded[0], sExploded[1]);
|
||||
@ -181,7 +171,6 @@ public void OnMapStart()
|
||||
FormatEx(sDownloadString, PLATFORM_MAX_PATH, "sound/%s", sExploded[1]);
|
||||
AddFileToDownloadsTable(sDownloadString);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
LogError("\"sound/%s\" could not be accessed.", sExploded[1]);
|
||||
@ -208,15 +197,13 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
|
||||
}
|
||||
}
|
||||
|
||||
public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank, int overwrite, int track)
|
||||
public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank, int overwrite, int track, float fOldTime)
|
||||
{
|
||||
if(!gCV_Enabled.BoolValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float fOldTime = Shavit_GetClientPB(client, style, track);
|
||||
|
||||
char sSound[PLATFORM_MAX_PATH];
|
||||
bool bEveryone = false;
|
||||
|
||||
@ -227,19 +214,16 @@ public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, i
|
||||
{
|
||||
bEveryone = true;
|
||||
}
|
||||
|
||||
else if(gA_WorldSounds.Length != 0 && rank == 1)
|
||||
{
|
||||
bEveryone = true;
|
||||
|
||||
gA_WorldSounds.GetString(GetRandomInt(0, gA_WorldSounds.Length - 1), sSound, PLATFORM_MAX_PATH);
|
||||
}
|
||||
|
||||
else if(gA_PersonalSounds.Length != 0 && time < fOldTime)
|
||||
{
|
||||
gA_PersonalSounds.GetString(GetRandomInt(0, gA_PersonalSounds.Length - 1), sSound, PLATFORM_MAX_PATH);
|
||||
}
|
||||
|
||||
else if(gA_FirstSounds.Length != 0 && overwrite == 1)
|
||||
{
|
||||
gA_FirstSounds.GetString(GetRandomInt(0, gA_FirstSounds.Length - 1), sSound, PLATFORM_MAX_PATH);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
997
addons/sourcemod/scripting/shavit-tas.sp
Normal file
997
addons/sourcemod/scripting/shavit-tas.sp
Normal file
@ -0,0 +1,997 @@
|
||||
/*
|
||||
* shavit's Timer - TAS
|
||||
* by: xutaxkamay, KiD Fearless, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <sdkhooks>
|
||||
#include <cstrike>
|
||||
#include <convar_class>
|
||||
|
||||
#include <shavit/core>
|
||||
#include <shavit/tas>
|
||||
#include <shavit/tas-oblivious>
|
||||
#include <shavit/tas-xutax>
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <shavit/checkpoints>
|
||||
#include <shavit/replay-recorder>
|
||||
#include <shavit/zones>
|
||||
|
||||
#pragma newdecls required
|
||||
#pragma semicolon 1
|
||||
|
||||
bool gB_Late = false;
|
||||
EngineVersion gEV_Type = Engine_Unknown;
|
||||
|
||||
float g_flAirSpeedCap = 30.0;
|
||||
float g_flOldYawAngle[MAXPLAYERS + 1];
|
||||
int g_iSurfaceFrictionOffset;
|
||||
float g_fMaxMove = 400.0;
|
||||
|
||||
bool gB_Autostrafer[MAXPLAYERS + 1];
|
||||
AutostrafeType gI_Type[MAXPLAYERS + 1];
|
||||
AutostrafeOverride gI_Override[MAXPLAYERS + 1];
|
||||
bool gB_Prestrafe[MAXPLAYERS + 1];
|
||||
bool gB_AutoJumpOnStart[MAXPLAYERS + 1];
|
||||
bool gB_EdgeJump[MAXPLAYERS + 1];
|
||||
float g_fPower[MAXPLAYERS + 1] = {1.0, ...};
|
||||
bool gB_AutogainBasicStrafer[MAXPLAYERS + 1];
|
||||
|
||||
bool gB_ForceJump[MAXPLAYERS+1];
|
||||
int gI_LastRestart[MAXPLAYERS+1];
|
||||
|
||||
ConVar sv_airaccelerate = null;
|
||||
ConVar sv_accelerate = null;
|
||||
ConVar sv_friction = null;
|
||||
ConVar sv_stopspeed = null;
|
||||
|
||||
chatstrings_t gS_ChatStrings;
|
||||
|
||||
bool gB_GlobalTraceResult = false;
|
||||
|
||||
bool gB_ReplayRecorder = false;
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] TAS",
|
||||
author = "xutaxkamay, oblivious, KiD Fearless, rtldg",
|
||||
description = "TAS module for shavit's bhop timer featuring xutaxkamay's autostrafer and oblivious's autogain.",
|
||||
version = SHAVIT_VERSION,
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
};
|
||||
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||
{
|
||||
CreateNative("Shavit_SetAutostrafeEnabled", Native_SetAutostrafeEnabled);
|
||||
CreateNative("Shavit_GetAutostrafeEnabled", Native_GetAutostrafeEnabled);
|
||||
CreateNative("Shavit_SetAutostrafeType", Native_SetAutostrafeType);
|
||||
CreateNative("Shavit_GetAutostrafeType", Native_GetAutostrafeType);
|
||||
CreateNative("Shavit_SetAutostrafePower", Native_SetAutostrafePower);
|
||||
CreateNative("Shavit_GetAutostrafePower", Native_GetAutostrafePower);
|
||||
CreateNative("Shavit_SetAutostrafeKeyOverride", Native_SetAutostrafeKeyOverride);
|
||||
CreateNative("Shavit_GetAutostrafeKeyOverride", Native_GetAutostrafeKeyOverride);
|
||||
CreateNative("Shavit_SetAutoPrestrafe", Native_SetAutoPrestrafe);
|
||||
CreateNative("Shavit_GetAutoPrestrafe", Native_GetAutoPrestrafe);
|
||||
CreateNative("Shavit_SetAutoJumpOnStart", Native_SetAutoJumpOnStart);
|
||||
CreateNative("Shavit_GetAutoJumpOnStart", Native_GetAutoJumpOnStart);
|
||||
CreateNative("Shavit_SetEdgeJump", Native_SetEdgeJump);
|
||||
CreateNative("Shavit_GetEdgeJump", Native_GetEdgeJump);
|
||||
CreateNative("Shavit_SetAutogainBasicStrafer", Native_SetAutogainBasicStrafer);
|
||||
CreateNative("Shavit_GetAutogainBasicStrafer", Native_GetAutogainBasicStrafer);
|
||||
|
||||
gB_Late = late;
|
||||
RegPluginLibrary("shavit-tas");
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
LoadTranslations("shavit-common.phrases");
|
||||
LoadTranslations("shavit-misc.phrases");
|
||||
|
||||
gEV_Type = GetEngineVersion();
|
||||
sv_airaccelerate = FindConVar("sv_airaccelerate");
|
||||
sv_accelerate = FindConVar("sv_accelerate");
|
||||
sv_friction = FindConVar("sv_friction");
|
||||
sv_stopspeed = FindConVar("sv_stopspeed");
|
||||
|
||||
GameData gamedata = new GameData("shavit.games");
|
||||
|
||||
Address surfaceFrictionAddress;
|
||||
|
||||
if (gEV_Type == Engine_CSGO)
|
||||
surfaceFrictionAddress = gamedata.GetAddress("m_surfaceFriction");
|
||||
else
|
||||
surfaceFrictionAddress = gamedata.GetMemSig("CBasePlayer->m_surfaceFriction");
|
||||
|
||||
if (surfaceFrictionAddress == Address_Null)
|
||||
{
|
||||
g_iSurfaceFrictionOffset = -1;
|
||||
LogError("[XUTAX] The address of m_surfaceFriction is null, defaulting friction values");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gEV_Type == Engine_CSGO)
|
||||
{
|
||||
g_iSurfaceFrictionOffset = view_as<int>(surfaceFrictionAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
int instr = LoadFromAddress(surfaceFrictionAddress, NumberType_Int32);
|
||||
// The lowest two bytes are the beginning of a `mov`.
|
||||
// The offset is 100% definitely totally always 16-bit.
|
||||
// We could just put the offset into the gamedata too but SHUT UP!
|
||||
g_iSurfaceFrictionOffset = instr >> 16;
|
||||
}
|
||||
}
|
||||
|
||||
delete gamedata;
|
||||
|
||||
if (gEV_Type == Engine_CSGO)
|
||||
{
|
||||
g_fMaxMove = 450.0;
|
||||
ConVar sv_air_max_wishspeed = FindConVar("sv_air_max_wishspeed");
|
||||
sv_air_max_wishspeed.AddChangeHook(OnWishSpeedChanged);
|
||||
g_flAirSpeedCap = sv_air_max_wishspeed.FloatValue;
|
||||
}
|
||||
|
||||
AddCommandListener(CommandListener_Toggler, "+autostrafer");
|
||||
AddCommandListener(CommandListener_Toggler, "-autostrafer");
|
||||
AddCommandListener(CommandListener_Toggler, "+autostrafe");
|
||||
AddCommandListener(CommandListener_Toggler, "-autostrafe");
|
||||
AddCommandListener(CommandListener_Toggler, "+autoprestrafe");
|
||||
AddCommandListener(CommandListener_Toggler, "-autoprestrafe");
|
||||
AddCommandListener(CommandListener_Toggler, "+autojumponstart");
|
||||
AddCommandListener(CommandListener_Toggler, "-autojumponstart");
|
||||
AddCommandListener(CommandListener_Toggler, "+edgejump");
|
||||
AddCommandListener(CommandListener_Toggler, "-edgejump");
|
||||
AddCommandListener(CommandListener_Toggler, "+autogainbss");
|
||||
AddCommandListener(CommandListener_Toggler, "-autogainbss");
|
||||
|
||||
RegConsoleCmd("sm_autostrafer", Command_Toggler, "Usage: !autostrafe [1|0]");
|
||||
RegConsoleCmd("sm_autostrafe", Command_Toggler, "Usage: !autostrafe [1|0]");
|
||||
RegConsoleCmd("sm_autoprestrafe", Command_Toggler, "Usage: !autoprestrafe [1|0}");
|
||||
RegConsoleCmd("sm_autojumponstart", Command_Toggler, "Usage: !autojumponstart [1|0}");
|
||||
RegConsoleCmd("sm_edgejump", Command_Toggler, "Usage: !edgejump [1|0}");
|
||||
RegConsoleCmd("sm_autogainbss", Command_Toggler, "Usage: !autogainbss [1|0}");
|
||||
|
||||
RegConsoleCmd("sm_tasm", Command_TasSettingsMenu, "Opens the TAS settings menu.");
|
||||
RegConsoleCmd("sm_tasmenu", Command_TasSettingsMenu, "Opens the TAS settings menu.");
|
||||
|
||||
//Convar.AutoExecConfig();
|
||||
|
||||
if (gB_Late)
|
||||
{
|
||||
Shavit_OnChatConfigLoaded();
|
||||
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientConnected(i))
|
||||
{
|
||||
OnClientConnected(i);
|
||||
|
||||
if (IsClientInGame(i))
|
||||
{
|
||||
OnClientPutInServer(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gB_ReplayRecorder = LibraryExists("shavit-replay-recorder");
|
||||
}
|
||||
|
||||
public void OnLibraryAdded(const char[] name)
|
||||
{
|
||||
if (StrEqual(name, "shavit-replay-recorder"))
|
||||
{
|
||||
gB_ReplayRecorder = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLibraryRemoved(const char[] name)
|
||||
{
|
||||
if (StrEqual(name, "shavit-replay-recorder"))
|
||||
{
|
||||
gB_ReplayRecorder = false;
|
||||
}
|
||||
}
|
||||
|
||||
// doesn't exist in css so we have to cache the value
|
||||
public void OnWishSpeedChanged(ConVar convar, const char[] oldValue, const char[] newValue)
|
||||
{
|
||||
g_flAirSpeedCap = StringToFloat(newValue);
|
||||
}
|
||||
|
||||
public void OnClientConnected(int client)
|
||||
{
|
||||
gB_Autostrafer[client] = true;
|
||||
gI_Override[client] = AutostrafeOverride_Surf_W_Okay;
|
||||
gI_Type[client] = AutostrafeType_1Tick;
|
||||
gB_AutoJumpOnStart[client] = true;
|
||||
gB_EdgeJump[client] = true;
|
||||
gB_Prestrafe[client] = true;
|
||||
g_fPower[client] = 1.0;
|
||||
gB_AutogainBasicStrafer[client] = true;
|
||||
}
|
||||
|
||||
public void OnClientPutInServer(int client)
|
||||
{
|
||||
if (!IsFakeClient(client))
|
||||
{
|
||||
SDKHook(client, SDKHook_PostThinkPost, PostThinkPost);
|
||||
}
|
||||
}
|
||||
|
||||
public void Shavit_OnChatConfigLoaded()
|
||||
{
|
||||
Shavit_GetChatStringsStruct(gS_ChatStrings);
|
||||
}
|
||||
|
||||
public Action Shavit_OnStart(int client, int track)
|
||||
{
|
||||
gB_ForceJump[client] = false;
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public void Shavit_OnRestart(int client, int track)
|
||||
{
|
||||
gI_LastRestart[client] = GetGameTickCount();
|
||||
}
|
||||
|
||||
public Action Shavit_OnTeleportPre(int client, int index, int target)
|
||||
{
|
||||
// to prevent gB_ForceJump when teleporting to a checkpoint in the start zone
|
||||
gI_LastRestart[client] = GetGameTickCount();
|
||||
}
|
||||
|
||||
public void Shavit_OnEnterZone(int client, int type, int track, int id, int entity, int data)
|
||||
{
|
||||
if (!IsValidClient(client, true) || IsFakeClient(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Zone_Start)
|
||||
{
|
||||
if (Shavit_GetClientTrack(client) == track)
|
||||
{
|
||||
gB_ForceJump[client] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Shavit_OnLeaveZone(int client, int type, int track, int id, int entity, int data)
|
||||
{
|
||||
if (type != Zone_Start)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsValidClient(client, true) || IsFakeClient(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Shavit_GetStyleSettingBool(Shavit_GetBhopStyle(client), "autojumponstart"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Shavit_GetTimerStatus(client) != Timer_Running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// You can be inside multiple startzones...
|
||||
if (Shavit_InsideZone(client, type, track))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Shavit_OnLeaveZone() will be called a couple times because of the shavit-zones event-clearing thing that happens on restart.
|
||||
// 5 is a good value that works, but we'll use 6 just-in-case.
|
||||
if (GetGameTickCount() - gI_LastRestart[client] < 6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetEntityFlags(client) & FL_ONGROUND)
|
||||
{
|
||||
if (gB_AutoJumpOnStart[client])
|
||||
{
|
||||
gB_ForceJump[client] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FindMenuItem(Menu menu, const char[] info)
|
||||
{
|
||||
for (int i = 0; i < menu.ItemCount; i++)
|
||||
{
|
||||
char sInfo[64];
|
||||
menu.GetItem(i, sInfo, sizeof(sInfo));
|
||||
|
||||
if (StrEqual(info, sInfo))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool HasAnyTasStyleSettings(int style)
|
||||
{
|
||||
if (Shavit_GetStyleSettingBool(style, "tas")
|
||||
|| Shavit_GetStyleSettingBool(style, "tas_timescale")
|
||||
|| Shavit_GetStyleSettingBool(style, "autoprestrafe")
|
||||
|| Shavit_GetStyleSettingBool(style, "edgejump")
|
||||
|| Shavit_GetStyleSettingBool(style, "autojumponstart"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Action Shavit_OnCheckpointMenuMade(int client, bool segmented, Menu menu)
|
||||
{
|
||||
if (!HasAnyTasStyleSettings(Shavit_GetBhopStyle(client)))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
char sDisplay[64];
|
||||
bool tas_timescale = (Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "tas_timescale") == -1.0);
|
||||
|
||||
FormatEx(sDisplay, 64, "%T\n ", "TasSettings", client);
|
||||
|
||||
if (tas_timescale)
|
||||
{
|
||||
int pos = FindMenuItem(menu, "del");
|
||||
menu.InsertItem(pos, "tassettings", sDisplay);
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.AddItem("tassettings", sDisplay);
|
||||
}
|
||||
|
||||
menu.ExitButton = gEV_Type != Engine_CSGO;
|
||||
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
||||
public Action Shavit_OnCheckpointMenuSelect(int client, int param2, char[] info, int maxlength, int currentCheckpoint, int maxCPs)
|
||||
{
|
||||
if (StrEqual(info, "tassettings"))
|
||||
{
|
||||
OpenTasSettingsMenu(client);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public Action Shavit_OnUserCmdPre(int client, int &buttons, int &impulse, float vel[3], float angles[3], TimerStatus status, int track, int style, int mouse[2])
|
||||
{
|
||||
if (!Shavit_ShouldProcessFrame(client))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if (gB_ForceJump[client] && (Shavit_GetStyleSettingBool(style, "edgejump") || Shavit_GetStyleSettingBool(style, "autojumponstart")))
|
||||
{
|
||||
buttons |= IN_JUMP;
|
||||
}
|
||||
|
||||
gB_ForceJump[client] = false;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
||||
bool TRFilter_OnlyZones(int entity, any data)
|
||||
{
|
||||
int zoneid = Shavit_GetZoneID(entity);
|
||||
|
||||
if (zoneid == -1 || Shavit_GetZoneTrack(zoneid) != data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
gB_GlobalTraceResult = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
public void OnPlayerRunCmdPost(int client, int buttons, int impulse, const float vel[3], const float angles[3], int weapon, int subtype, int cmdnum, int tickcount, int seed, const int mouse[2])
|
||||
{
|
||||
if (IsFakeClient(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
public void PostThinkPost(int client)
|
||||
{
|
||||
#endif
|
||||
|
||||
if (gB_ForceJump[client])
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int style = Shavit_GetBhopStyle(client);
|
||||
bool edgejump = (gB_EdgeJump[client] && Shavit_GetStyleSettingBool(style, "edgejump"));
|
||||
bool autojumponstart = (gB_AutoJumpOnStart[client] && Shavit_GetStyleSettingBool(style, "autojumponstart"));
|
||||
|
||||
if (!edgejump && !autojumponstart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Shavit_ShouldProcessFrame(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsPlayerAlive(client) || GetEntityMoveType(client) != MOVETYPE_WALK || !(GetEntProp(client, Prop_Data, "m_nWaterLevel") <= 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(GetEntityFlags(client) & FL_ONGROUND))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float origin[3], absvel[3], nextpos[3];
|
||||
GetClientAbsOrigin(client, origin);
|
||||
GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", absvel);
|
||||
ScaleVector(absvel, GetTickInterval());
|
||||
float mins[3], maxs[3];
|
||||
GetEntPropVector(client, Prop_Send, "m_vecMins", mins);
|
||||
GetEntPropVector(client, Prop_Send, "m_vecMaxs", maxs);
|
||||
|
||||
if (autojumponstart)
|
||||
{
|
||||
int track = Shavit_GetClientTrack(client);
|
||||
if (Shavit_InsideZone(client, Zone_Start, track))
|
||||
{
|
||||
float blah[3]; blah = absvel;
|
||||
ScaleVector(blah, 3.0); // 2 isn't always enough... so 3 it is :)
|
||||
AddVectors(origin, blah, nextpos);
|
||||
|
||||
gB_GlobalTraceResult = false;
|
||||
TR_EnumerateEntitiesHull(nextpos, nextpos, mins, maxs, PARTITION_TRIGGER_EDICTS, TRFilter_OnlyZones, track);
|
||||
|
||||
if (!gB_GlobalTraceResult)
|
||||
{
|
||||
gB_ForceJump[client] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (edgejump && !gB_ForceJump[client])
|
||||
{
|
||||
float lower[3];
|
||||
AddVectors(origin, absvel, nextpos);
|
||||
AddVectors(nextpos, view_as<float>({0.0, 0.0, -10.0}), lower);
|
||||
|
||||
TR_TraceHullFilter(nextpos, lower, mins, maxs, MASK_PLAYERSOLID, TRFilter_NoPlayers, client);
|
||||
gB_ForceJump[client] = !TR_DidHit();
|
||||
}
|
||||
}
|
||||
|
||||
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2])
|
||||
{
|
||||
if (IsFakeClient(client))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if (!Shavit_ShouldProcessFrame(client))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if (!IsPlayerAlive(client) || GetEntityMoveType(client) == MOVETYPE_NOCLIP || GetEntityMoveType(client) == MOVETYPE_LADDER || !(GetEntProp(client, Prop_Data, "m_nWaterLevel") <= 1))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
static int s_iOnGroundCount[MAXPLAYERS+1] = {1, ...};
|
||||
|
||||
if (GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") != -1)
|
||||
{
|
||||
s_iOnGroundCount[client]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_iOnGroundCount[client] = 0;
|
||||
|
||||
#if 0
|
||||
if (buttons & IN_FORWARD)
|
||||
{
|
||||
buttons &= ~IN_FORWARD;
|
||||
vel[0] = 0.0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
float flSurfaceFriction = 1.0;
|
||||
|
||||
if (g_iSurfaceFrictionOffset > 0)
|
||||
{
|
||||
flSurfaceFriction = GetEntDataFloat(client, g_iSurfaceFrictionOffset);
|
||||
}
|
||||
|
||||
int style = Shavit_GetBhopStyle(client);
|
||||
AutostrafeType type = view_as<AutostrafeType>(Shavit_GetStyleSettingInt(style, "autostrafe"));
|
||||
|
||||
if (type == AutostrafeType_Any)
|
||||
{
|
||||
type = gI_Type[client];
|
||||
}
|
||||
|
||||
float oldyaw = g_flOldYawAngle[client];
|
||||
g_flOldYawAngle[client] = angles[1];
|
||||
|
||||
if (s_iOnGroundCount[client] <= 1)
|
||||
{
|
||||
if (!type || !gB_Autostrafer[client] || IsSurfing(client))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if (type != AutostrafeType_Autogain && type != AutostrafeType_AutogainNoSpeedLoss)
|
||||
{
|
||||
if (!!(buttons & IN_BACK))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if (!!(buttons & IN_FORWARD))
|
||||
{
|
||||
if (gI_Override[client] != AutostrafeOverride_Surf_W_Okay)
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!!(buttons & (IN_MOVERIGHT | IN_MOVELEFT)))
|
||||
{
|
||||
if (gI_Override[client] == AutostrafeOverride_All)
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
/*
|
||||
else if (gI_Override[client] == AutostrafeOverride_Surf && IsSurfing(client))
|
||||
{
|
||||
return Plugin_Continue;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if (type == AutostrafeType_1Tick)
|
||||
{
|
||||
XutaxOnPlayerRunCmd(client, buttons, impulse, vel, angles, weapon, subtype, cmdnum, tickcount, seed, mouse,
|
||||
sv_airaccelerate.FloatValue, flSurfaceFriction, g_flAirSpeedCap, g_fMaxMove, oldyaw, g_fPower[client]);
|
||||
}
|
||||
else if (type == AutostrafeType_Autogain || type == AutostrafeType_AutogainNoSpeedLoss)
|
||||
{
|
||||
if (gB_AutogainBasicStrafer[client])
|
||||
{
|
||||
float delta = AngleNormalize(angles[1] - oldyaw);
|
||||
|
||||
if (delta < 0.0)
|
||||
{
|
||||
vel[1] = g_fMaxMove;
|
||||
}
|
||||
else if (delta > 0.0)
|
||||
{
|
||||
vel[1] = -g_fMaxMove;
|
||||
}
|
||||
}
|
||||
|
||||
ObliviousOnPlayerRunCmd(client, buttons, impulse, vel, angles, weapon, subtype, cmdnum, tickcount, seed, mouse,
|
||||
sv_airaccelerate.FloatValue, flSurfaceFriction, g_flAirSpeedCap, g_fMaxMove,
|
||||
(type == AutostrafeType_AutogainNoSpeedLoss));
|
||||
}
|
||||
else if (type == AutostrafeType_Basic)
|
||||
{
|
||||
float delta = AngleNormalize(angles[1] - oldyaw);
|
||||
|
||||
if (delta < 0.0)
|
||||
{
|
||||
vel[1] = g_fMaxMove;
|
||||
}
|
||||
else if (delta > 0.0)
|
||||
{
|
||||
vel[1] = -g_fMaxMove;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gB_Prestrafe[client]
|
||||
&& (vel[0] != 0.0 || vel[1] != 0.0)
|
||||
&& Shavit_GetStyleSettingBool(style, "autoprestrafe"))
|
||||
{
|
||||
float _delta_opt = ground_delta_opt(client, angles, vel, flSurfaceFriction,
|
||||
sv_accelerate.FloatValue, sv_friction.FloatValue, sv_stopspeed.FloatValue);
|
||||
|
||||
float _tmp[3]; _tmp[0] = angles[0]; _tmp[2] = angles[2];
|
||||
_tmp[1] = normalize_yaw(angles[1] - _delta_opt);
|
||||
|
||||
if (gB_ReplayRecorder)
|
||||
{
|
||||
Shavit_HijackAngles(client, angles[0], angles[1], 2, true);
|
||||
}
|
||||
|
||||
angles[1] = _tmp[1];
|
||||
}
|
||||
}
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
void OpenTasSettingsMenu(int client, int pos=0)
|
||||
{
|
||||
char display[64];
|
||||
Menu menu = new Menu(MenuHandler_TasSettings, MENU_ACTIONS_DEFAULT);
|
||||
menu.SetTitle("%T\n ", "TasSettings", client);
|
||||
|
||||
int style = Shavit_GetBhopStyle(client);
|
||||
|
||||
bool autostrafe_allowed = Shavit_GetStyleSettingBool(style, "autostrafe");
|
||||
bool autostrafe = (gB_Autostrafer[client] && autostrafe_allowed);
|
||||
FormatEx(display, sizeof(display), "[%s] %T", autostrafe ? "+":"-", "Autostrafer", client);
|
||||
menu.AddItem("autostrafe", display, autostrafe_allowed ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
bool autojumponstart_allowed = Shavit_GetStyleSettingBool(style, "autojumponstart");
|
||||
bool autojumponstart = (gB_AutoJumpOnStart[client] && autojumponstart_allowed);
|
||||
FormatEx(display, sizeof(display), "[%s] %T", autojumponstart ? "+":"-", "AutoJumpOnStart", client);
|
||||
menu.AddItem("autojump", display, autojumponstart_allowed ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
bool autoprestrafe_allowed = Shavit_GetStyleSettingBool(style, "autoprestrafe");
|
||||
bool autoprestrafe = (gB_Prestrafe[client] && autoprestrafe_allowed);
|
||||
FormatEx(display, sizeof(display), "[%s] %T\n ", autoprestrafe ? "+":"-", "AutoPrestrafe", client);
|
||||
menu.AddItem("prestrafe", display, autoprestrafe_allowed ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
AutostrafeType tastype = view_as<AutostrafeType>(Shavit_GetStyleSettingInt(style, "autostrafe"));
|
||||
bool tastype_editable = (tastype == AutostrafeType_Any);
|
||||
tastype = tastype_editable ? gI_Type[client] : tastype;
|
||||
|
||||
FormatEx(display, sizeof(display), "%T: %T\n ", "Autostrafer_type", client,
|
||||
(tastype == AutostrafeType_Disabled ? "TASDisabled" : (tastype == AutostrafeType_1Tick ? "Autostrafer_1tick" : (tastype == AutostrafeType_Autogain ? "Autostrafer_autogain" : tastype == AutostrafeType_Basic ? "Autostrafer_basic" : "Autostrafer_autogain_nsl"))), client);
|
||||
menu.AddItem("type", display, (tastype_editable ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED));
|
||||
|
||||
bool tas_timescale = (Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(client), "tas_timescale") == -1.0);
|
||||
|
||||
float ts = Shavit_GetClientTimescale(client);
|
||||
char buf[10];
|
||||
PrettyishTimescale(buf, sizeof(buf), ts, 0.1, 1.0, 0.0);
|
||||
FormatEx(display, sizeof(display), "--%T\n%T: %s", "Timescale", client, "CurrentTimescale", client, buf);
|
||||
menu.AddItem("tsminus", display, (tas_timescale && ts > 0.1) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
FormatEx(display, sizeof(display), "++%T\n ", "Timescale", client);
|
||||
menu.AddItem("tsplus", display, (tas_timescale && ts != 1.0) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
bool edgejump_allowed = Shavit_GetStyleSettingBool(style, "edgejump");
|
||||
bool edgejump = (gB_EdgeJump[client] && edgejump_allowed);
|
||||
FormatEx(display, sizeof(display), "[%s] %T", edgejump ? "+":"-", "EdgeJump", client);
|
||||
menu.AddItem("edgejump", display, edgejump_allowed ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
AutostrafeOverride ov = gI_Override[client];
|
||||
FormatEx(display, sizeof(display), "%T: %T", "AutostrafeOverride", client,
|
||||
(ov == AutostrafeOverride_Normal ? "AutostrafeOverride_Normal" : (ov == AutostrafeOverride_Surf ? "AutostrafeOverride_Surf" : (ov == AutostrafeOverride_Surf_W_Okay ? "AutostrafeOverride_Surf_W_Okay" : "AutostrafeOverride_All"))), client);
|
||||
menu.AddItem("override", display);
|
||||
|
||||
FormatEx(display, sizeof(display), "[%s] %T", gB_AutogainBasicStrafer[client] ? "+":"-", "AutogainBasicStrafer", client);
|
||||
menu.AddItem("autogainbss", display,
|
||||
(tastype == AutostrafeType_Autogain || tastype == AutostrafeType_AutogainNoSpeedLoss) ?
|
||||
ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
if (Shavit_GetStyleSettingBool(Shavit_GetBhopStyle(client), "segments"))
|
||||
{
|
||||
menu.ExitBackButton = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.ExitButton = true;
|
||||
}
|
||||
|
||||
menu.DisplayAt(client, pos, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
public int MenuHandler_TasSettings(Menu menu, MenuAction action, int param1, int param2)
|
||||
{
|
||||
if (action == MenuAction_Select)
|
||||
{
|
||||
char info[16];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
|
||||
if (StrEqual(info, "autostrafe"))
|
||||
{
|
||||
gB_Autostrafer[param1] = !gB_Autostrafer[param1];
|
||||
}
|
||||
else if (StrEqual(info, "autojump"))
|
||||
{
|
||||
gB_AutoJumpOnStart[param1] = !gB_AutoJumpOnStart[param1];
|
||||
}
|
||||
else if (StrEqual(info, "edgejump"))
|
||||
{
|
||||
gB_EdgeJump[param1] = !gB_EdgeJump[param1];
|
||||
}
|
||||
else if (StrEqual(info, "prestrafe"))
|
||||
{
|
||||
gB_Prestrafe[param1] = !gB_Prestrafe[param1];
|
||||
}
|
||||
else if (StrEqual(info, "autogainbss"))
|
||||
{
|
||||
gB_AutogainBasicStrafer[param1] = !gB_AutogainBasicStrafer[param1];
|
||||
}
|
||||
else if (StrEqual(info, "type"))
|
||||
{
|
||||
AutostrafeType tastype = view_as<AutostrafeType>(Shavit_GetStyleSettingInt(Shavit_GetBhopStyle(param1), "autostrafe"));
|
||||
|
||||
if (tastype == AutostrafeType_Any)
|
||||
{
|
||||
gI_Type[param1] = (gI_Type[param1] == AutostrafeType_1Tick ? AutostrafeType_Autogain : gI_Type[param1] == AutostrafeType_Basic ? AutostrafeType_1Tick : AutostrafeType_Basic);
|
||||
}
|
||||
}
|
||||
else if (StrEqual(info, "override"))
|
||||
{
|
||||
if (++gI_Override[param1] >= AutostrafeOverride_Size)
|
||||
{
|
||||
gI_Override[param1] = AutostrafeOverride_Normal;
|
||||
}
|
||||
}
|
||||
else if (StrEqual(info, "tsplus"))
|
||||
{
|
||||
if (Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(param1), "tas_timescale") == -1.0)
|
||||
{
|
||||
FakeClientCommand(param1, "sm_tsplus");
|
||||
}
|
||||
}
|
||||
else if (StrEqual(info, "tsminus"))
|
||||
{
|
||||
if (Shavit_GetStyleSettingFloat(Shavit_GetBhopStyle(param1), "tas_timescale") == -1.0)
|
||||
{
|
||||
FakeClientCommand(param1, "sm_tsminus");
|
||||
}
|
||||
}
|
||||
|
||||
OpenTasSettingsMenu(param1, GetMenuSelectionPosition());
|
||||
}
|
||||
else if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
|
||||
{
|
||||
FakeClientCommandEx(param1, "sm_cp");
|
||||
}
|
||||
else if (action == MenuAction_End)
|
||||
{
|
||||
delete menu;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Command_Toggler_Internal(int client, const char[] asdfcommand, int x)
|
||||
{
|
||||
if (!IsValidClient(client))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char command[32];
|
||||
strcopy(command, sizeof(command), asdfcommand);
|
||||
|
||||
if (StrEqual(command, "autostrafer"))
|
||||
{
|
||||
command = "autostrafe";
|
||||
}
|
||||
|
||||
if (!StrEqual(command, "autogainbss"))
|
||||
{
|
||||
if (!Shavit_GetStyleSettingBool(Shavit_GetBhopStyle(client), command))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool set;
|
||||
char translation[32];
|
||||
|
||||
if (StrEqual(command, "autostrafe"))
|
||||
{
|
||||
set = gB_Autostrafer[client] = (x == -1) ? !gB_Autostrafer[client] : (x != 0);
|
||||
translation = "Autostrafer";
|
||||
}
|
||||
else if (StrEqual(command, "autoprestrafe"))
|
||||
{
|
||||
set = gB_Prestrafe[client] = (x == -1) ? !gB_Prestrafe[client] : (x != 0);
|
||||
translation = "AutoPrestrafe";
|
||||
}
|
||||
else if (StrEqual(command, "autojumponstart"))
|
||||
{
|
||||
set = gB_AutoJumpOnStart[client] = (x == -1) ? !gB_AutoJumpOnStart[client] : (x != 0);
|
||||
translation = "AutoJumpOnStart";
|
||||
}
|
||||
else if (StrEqual(command, "edgejump"))
|
||||
{
|
||||
set = gB_EdgeJump[client] = (x == -1) ? !gB_EdgeJump[client] : (x != 0);
|
||||
translation = "EdgeJump";
|
||||
}
|
||||
else if (StrEqual(command, "autogainbss"))
|
||||
{
|
||||
set = gB_AutogainBasicStrafer[client] = (x == -1) ? !gB_AutogainBasicStrafer[client] : (x != 0);
|
||||
translation = "AutogainBasicStrafer";
|
||||
}
|
||||
|
||||
Shavit_StopChatSound();
|
||||
Shavit_PrintToChat(client, "%T: %s%T", translation, client, (set ? gS_ChatStrings.sVariable : gS_ChatStrings.sWarning), (set ? "TASEnabled" : "TASDisabled"), client);
|
||||
}
|
||||
|
||||
public Action CommandListener_Toggler(int client, const char[] command, int args)
|
||||
{
|
||||
Command_Toggler_Internal(client, command[1], (command[0] == '+') ? 1 : 0);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
|
||||
public Action Command_Toggler(int client, int args)
|
||||
{
|
||||
char command[32];
|
||||
GetCmdArg(0, command, sizeof(command));
|
||||
|
||||
int x = -1;
|
||||
|
||||
if (args > 0)
|
||||
{
|
||||
char arg[5];
|
||||
GetCmdArg(1, arg, sizeof(arg));
|
||||
x = StringToInt(arg);
|
||||
}
|
||||
|
||||
Command_Toggler_Internal(client, command[3], x);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action Command_TasSettingsMenu(int client, int args)
|
||||
{
|
||||
if (IsValidClient(client))
|
||||
{
|
||||
OpenTasSettingsMenu(client);
|
||||
}
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// natives
|
||||
public any Native_SetAutostrafeEnabled(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
bool value = GetNativeCell(2);
|
||||
gB_Autostrafer[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutostrafeEnabled(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gB_Autostrafer[client];
|
||||
}
|
||||
|
||||
public any Native_SetAutostrafeType(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
AutostrafeType value = view_as<AutostrafeType>(GetNativeCell(2));
|
||||
gI_Type[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutostrafeType(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gI_Type[client];
|
||||
}
|
||||
|
||||
public any Native_SetAutostrafePower(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
float value = GetNativeCell(2);
|
||||
g_fPower[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutostrafePower(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return g_fPower[client];
|
||||
}
|
||||
|
||||
public any Native_SetAutostrafeKeyOverride(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
AutostrafeOverride value = view_as<AutostrafeOverride>(GetNativeCell(2));
|
||||
gI_Override[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutostrafeKeyOverride(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gI_Override[client];
|
||||
}
|
||||
|
||||
public any Native_SetAutoPrestrafe(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
bool value = GetNativeCell(2);
|
||||
gB_Prestrafe[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutoPrestrafe(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gB_Prestrafe[client];
|
||||
}
|
||||
|
||||
public any Native_SetAutoJumpOnStart(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
bool value = GetNativeCell(2);
|
||||
gB_AutoJumpOnStart[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutoJumpOnStart(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gB_AutoJumpOnStart[client];
|
||||
}
|
||||
|
||||
public any Native_SetEdgeJump(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
bool value = GetNativeCell(2);
|
||||
gB_EdgeJump[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetEdgeJump(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gB_EdgeJump[client];
|
||||
}
|
||||
|
||||
public any Native_SetAutogainBasicStrafer(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
bool value = GetNativeCell(2);
|
||||
gB_AutogainBasicStrafer[client] = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public any Native_GetAutogainBasicStrafer(Handle plugin, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
return gB_AutogainBasicStrafer[client];
|
||||
}
|
||||
@ -1,8 +1,9 @@
|
||||
/*
|
||||
* shavit's Timer - Dynamic Timelimits
|
||||
* by: shavit
|
||||
* by: shavit, Nickelony, Sirhephaestus, rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
* This file is part of shavit's Timer.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
@ -16,7 +17,7 @@
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
// original idea from ckSurf.
|
||||
|
||||
@ -24,8 +25,10 @@
|
||||
#include <convar_class>
|
||||
#include <dhooks>
|
||||
|
||||
#include <shavit/core>
|
||||
#include <shavit/wr>
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#include <shavit>
|
||||
|
||||
#undef REQUIRE_EXTENSIONS
|
||||
#include <cstrike>
|
||||
@ -36,7 +39,7 @@
|
||||
// #define DEBUG
|
||||
|
||||
// database handle
|
||||
Database2 gH_SQL = null;
|
||||
Database gH_SQL = null;
|
||||
|
||||
// base cvars
|
||||
ConVar mp_do_warmup_period = null;
|
||||
@ -66,27 +69,28 @@ bool gB_BlockRoundEndEvent = false;
|
||||
bool gB_AlternateZeroPrint = false;
|
||||
Handle gH_Timer = null;
|
||||
EngineVersion gEV_Type = Engine_Unknown;
|
||||
chatstrings_t gS_ChatStrings;
|
||||
|
||||
Handle gH_Forwards_OnCountdownStart = null;
|
||||
|
||||
// table prefix
|
||||
char gS_MySQLPrefix[32];
|
||||
|
||||
bool gB_Late = false;
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] Dynamic Timelimits",
|
||||
author = "shavit",
|
||||
author = "shavit, Nickelony, Sirhephaestus, rtldg",
|
||||
description = "Sets a dynamic value of mp_timelimit and mp_roundtime, based on average map times on the server.",
|
||||
version = SHAVIT_VERSION,
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
}
|
||||
|
||||
public void OnAllPluginsLoaded()
|
||||
public APLRes AskPluginLoad2(Handle plugin, bool late, char[] error, int maxlength)
|
||||
{
|
||||
if(!LibraryExists("shavit-wr"))
|
||||
{
|
||||
SetFailState("shavit-wr is required for the plugin to work.");
|
||||
}
|
||||
gB_Late = late;
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
@ -102,7 +106,7 @@ public void OnPluginStart()
|
||||
mp_ignore_round_win_conditions = FindConVar("mp_ignore_round_win_conditions");
|
||||
mp_timelimit = FindConVar("mp_timelimit");
|
||||
mp_roundtime = FindConVar("mp_roundtime");
|
||||
|
||||
|
||||
if(mp_roundtime != null)
|
||||
{
|
||||
mp_roundtime.SetBounds(ConVarBound_Upper, false);
|
||||
@ -130,10 +134,16 @@ public void OnPluginStart()
|
||||
|
||||
Convar.AutoExecConfig();
|
||||
|
||||
RegAdminCmd("sm_extend", Command_Extend, ADMFLAG_CHANGEMAP, "Admin command for extending map");
|
||||
RegAdminCmd("sm_extendmap", Command_Extend, ADMFLAG_CHANGEMAP, "Admin command for extending map");
|
||||
|
||||
HookEvent("round_end", round_end, EventHookMode_Pre);
|
||||
|
||||
GetTimerSQLPrefix(gS_MySQLPrefix, 32);
|
||||
gH_SQL = GetTimerDatabaseHandle2();
|
||||
gH_SQL = GetTimerDatabaseHandle();
|
||||
|
||||
if(gB_Late)
|
||||
Shavit_OnChatConfigLoaded();
|
||||
}
|
||||
|
||||
public void OnMapStart()
|
||||
@ -148,7 +158,6 @@ public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] n
|
||||
delete gH_Timer;
|
||||
gH_Timer = CreateTimer(1.0, Timer_PrintToChat, 0, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
delete gH_Timer;
|
||||
@ -201,7 +210,6 @@ public void OnConfigsExecuted()
|
||||
{
|
||||
StartCalculating();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
SetLimit(RoundToNearest(gCV_DefaultLimit.FloatValue));
|
||||
@ -213,6 +221,11 @@ public void OnConfigsExecuted()
|
||||
}
|
||||
}
|
||||
|
||||
public void Shavit_OnChatConfigLoaded()
|
||||
{
|
||||
Shavit_GetChatStringsStruct(gS_ChatStrings);
|
||||
}
|
||||
|
||||
void StartCalculating()
|
||||
{
|
||||
char sMap[PLATFORM_MAX_PATH];
|
||||
@ -225,7 +238,7 @@ void StartCalculating()
|
||||
PrintToServer("%s", sQuery);
|
||||
#endif
|
||||
|
||||
gH_SQL.Query(SQL_GetMapTimes, sQuery, 0, DBPrio_Low);
|
||||
QueryLog(gH_SQL, SQL_GetMapTimes, sQuery, 0, DBPrio_Low);
|
||||
}
|
||||
|
||||
public void SQL_GetMapTimes(Database db, DBResultSet results, const char[] error, any data)
|
||||
@ -276,7 +289,6 @@ public void SQL_GetMapTimes(Database db, DBResultSet results, const char[] error
|
||||
{
|
||||
fAverage = gCV_MinimumLimit.FloatValue;
|
||||
}
|
||||
|
||||
else if(fAverage > gCV_MaximumLimit.FloatValue)
|
||||
{
|
||||
fAverage = gCV_MaximumLimit.FloatValue;
|
||||
@ -284,7 +296,6 @@ public void SQL_GetMapTimes(Database db, DBResultSet results, const char[] error
|
||||
|
||||
SetLimit(RoundToCeil(fAverage / 10) * 10);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
SetLimit(RoundToNearest(gCV_DefaultLimit.FloatValue));
|
||||
@ -298,6 +309,7 @@ void SetLimit(int time)
|
||||
if(mp_roundtime != null)
|
||||
{
|
||||
mp_roundtime.IntValue = time;
|
||||
GameRules_SetProp("m_iRoundTime", time * 60);
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,11 +330,6 @@ public Action Timer_PrintToChat(Handle timer)
|
||||
int timeleft = 0;
|
||||
GetMapTimeLeft(timeleft);
|
||||
|
||||
if(timeleft <= -1 && timeleft >= -3)
|
||||
{
|
||||
Shavit_StopChatSound();
|
||||
}
|
||||
|
||||
if (gCV_InstantMapChange.BoolValue && timeleft <= 5)
|
||||
{
|
||||
if (timeleft)
|
||||
@ -348,17 +355,26 @@ public Action Timer_PrintToChat(Handle timer)
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
if(timeleft <= 0 && timeleft >= -3)
|
||||
{
|
||||
Shavit_StopChatSound();
|
||||
}
|
||||
|
||||
char timebuf[12];
|
||||
|
||||
switch(timeleft)
|
||||
{
|
||||
case 3600: Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, "60");
|
||||
case 1800: Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, "30");
|
||||
case 1200: Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, "20");
|
||||
case 600: Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, "10");
|
||||
case 300: Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, "5");
|
||||
case 120: Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, "2");
|
||||
case 60: Shavit_PrintToChatAll("%T", "Seconds", LANG_SERVER, "60");
|
||||
case 30: Shavit_PrintToChatAll("%T", "Seconds", LANG_SERVER, "30");
|
||||
case 15: Shavit_PrintToChatAll("%T", "Seconds", LANG_SERVER, "15");
|
||||
case 3600, 1800, 1200, 600, 300, 120:
|
||||
{
|
||||
IntToString(timeleft/60, timebuf, sizeof(timebuf));
|
||||
Shavit_StopChatSound();
|
||||
Shavit_PrintToChatAll("%T", "Minutes", LANG_SERVER, timebuf);
|
||||
}
|
||||
case 60, 30, 15:
|
||||
{
|
||||
IntToString(timeleft, timebuf, sizeof(timebuf));
|
||||
Shavit_PrintToChatAll("%T", "Seconds", LANG_SERVER, timebuf);
|
||||
}
|
||||
|
||||
case 0: // case 0 is hit twice....
|
||||
{
|
||||
@ -368,7 +384,6 @@ public Action Timer_PrintToChat(Handle timer)
|
||||
Call_Finish();
|
||||
}
|
||||
|
||||
Shavit_StopChatSound();
|
||||
Shavit_PrintToChatAll("%d..", gB_AlternateZeroPrint ? 4 : 5);
|
||||
gB_AlternateZeroPrint = !gB_AlternateZeroPrint;
|
||||
}
|
||||
@ -421,7 +436,7 @@ public Action CS_OnTerminateRound(float &fDelay, CSRoundEndReason &iReason)
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
@ -435,3 +450,28 @@ public Action round_end(Event event, const char[] name, bool dontBroadcast)
|
||||
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public Action Command_Extend(int client, int args)
|
||||
{
|
||||
int extendtime = 10 * 60;
|
||||
|
||||
if (args > 0)
|
||||
{
|
||||
char sArg[8];
|
||||
GetCmdArg(1, sArg, sizeof(sArg));
|
||||
extendtime = RoundFloat(StringToFloat(sArg) * 60);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConVar smc_mapvote_extend_time = FindConVar("smc_mapvote_extend_time");
|
||||
|
||||
if (smc_mapvote_extend_time)
|
||||
{
|
||||
extendtime = RoundFloat(smc_mapvote_extend_time.FloatValue * 60.0);
|
||||
}
|
||||
}
|
||||
|
||||
ExtendMapTimeLimit(extendtime);
|
||||
Shavit_PrintToChatAll("%T", "Extended", LANG_SERVER, gS_ChatStrings.sVariable2, client, gS_ChatStrings.sText, gS_ChatStrings.sVariable, extendtime / 60, gS_ChatStrings.sText);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
706
addons/sourcemod/scripting/shavit-zones-json.sp
Normal file
706
addons/sourcemod/scripting/shavit-zones-json.sp
Normal file
@ -0,0 +1,706 @@
|
||||
/*
|
||||
* shavit's Timer - JSON zones for shavit-zones
|
||||
* by: rtldg
|
||||
*
|
||||
* This file is part of shavit's Timer (https://github.com/shavitush/bhoptimer)
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program 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
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sourcemod>
|
||||
#include <convar_class>
|
||||
|
||||
#include <shavit/core>
|
||||
#include <shavit/zones>
|
||||
|
||||
#undef REQUIRE_PLUGIN
|
||||
#undef REQUIRE_EXTENSIONS
|
||||
#include <ripext> // https://github.com/ErikMinekus/sm-ripext
|
||||
#include <json> // https://github.com/clugg/sm-json
|
||||
#include <SteamWorks> // HTTP stuff
|
||||
|
||||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
|
||||
static char gS_ZoneTypes[ZONETYPES_SIZE][18] = {
|
||||
"start",
|
||||
"end",
|
||||
"respawn",
|
||||
"stop",
|
||||
"slay",
|
||||
"freestyle",
|
||||
"customspeedlimit",
|
||||
"teleport",
|
||||
"customspawn",
|
||||
"easybhop",
|
||||
"slide",
|
||||
"airaccel",
|
||||
"stage",
|
||||
"notimergravity",
|
||||
"gravity",
|
||||
"speedmod",
|
||||
"nojump",
|
||||
"autobhop"
|
||||
};
|
||||
|
||||
static char gS_ZoneForms[5][26] = {
|
||||
"box",
|
||||
"hook trigger_multiple",
|
||||
"hook trigger_teleport",
|
||||
"hook func_button",
|
||||
"areas and clusters"
|
||||
};
|
||||
|
||||
bool gB_Late = false;
|
||||
bool gB_YouCanLoadZonesNow = false;
|
||||
char gS_Map[PLATFORM_MAX_PATH];
|
||||
char gS_ZonesForMap[PLATFORM_MAX_PATH];
|
||||
char gS_EngineName[16];
|
||||
ArrayList gA_Zones = null;
|
||||
|
||||
enum struct MapInfoTrack
|
||||
{
|
||||
int tier; // 0 = unknown
|
||||
// -1 = unknown | 0 = false | 1 = true | 2 = really hard
|
||||
int possible_on_scroll;
|
||||
int possible_on_400vel;
|
||||
int possible_on_stamina;
|
||||
}
|
||||
|
||||
static char gS_InfoDescripters[][] = {
|
||||
"Unknown",
|
||||
"False",
|
||||
"True",
|
||||
"Really hard",
|
||||
};
|
||||
|
||||
int gI_MapInfoTrack[MAXPLAYERS+1];
|
||||
MapInfoTrack gA_TrackInfo[TRACKS_SIZE];
|
||||
|
||||
Convar gCV_Enable = null;
|
||||
Convar gCV_UseRipext = null;
|
||||
Convar gCV_ApiUrl = null;
|
||||
Convar gCV_ApiKey = null;
|
||||
Convar gCV_Source = null;
|
||||
Convar gCV_Folder = null;
|
||||
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] Map Zones (JSON)",
|
||||
author = "rtldg",
|
||||
description = "Retrieves map zones for bhoptimer from an HTTP API.",
|
||||
version = SHAVIT_VERSION,
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
}
|
||||
|
||||
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||
{
|
||||
gB_Late = late;
|
||||
|
||||
MarkNativeAsOptional("HTTPRequest.HTTPRequest");
|
||||
MarkNativeAsOptional("HTTPRequest.SetHeader");
|
||||
MarkNativeAsOptional("HTTPRequest.Get");
|
||||
MarkNativeAsOptional("HTTPResponse.Status.get");
|
||||
MarkNativeAsOptional("HTTPResponse.Data.get");
|
||||
MarkNativeAsOptional("JSONObject.HasKey");
|
||||
MarkNativeAsOptional("JSONObject.Get");
|
||||
MarkNativeAsOptional("JSONObject.GetInt");
|
||||
MarkNativeAsOptional("JSONObject.GetFloat");
|
||||
MarkNativeAsOptional("JSONObject.GetString");
|
||||
MarkNativeAsOptional("JSONArray.Get");
|
||||
MarkNativeAsOptional("JSONArray.Length.get");
|
||||
MarkNativeAsOptional("JSONArray.GetFloat");
|
||||
MarkNativeAsOptional("SteamWorks_SetHTTPRequestAbsoluteTimeoutMS");
|
||||
|
||||
switch (GetEngineVersion())
|
||||
{
|
||||
case Engine_CSGO: gS_EngineName = "csgo";
|
||||
case Engine_CSS: gS_EngineName = "cstrike";
|
||||
case Engine_TF2: gS_EngineName = "tf2";
|
||||
}
|
||||
|
||||
char dir[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, dir, sizeof(dir), "data/zones-%s", gS_EngineName);
|
||||
CreateDirectory(dir, 1 | 4 | 8 | 32 | 64 | 128 | 256);
|
||||
StrCat(dir, sizeof(dir), "/z");
|
||||
CreateDirectory(dir, 1 | 4 | 8 | 32 | 64 | 128 | 256);
|
||||
dir[strlen(dir)-1] = 'i';
|
||||
CreateDirectory(dir, 1 | 4 | 8 | 32 | 64 | 128 | 256);
|
||||
|
||||
RegPluginLibrary("shavit-zones-json");
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
LoadTranslations("shavit-common.phrases");
|
||||
|
||||
gCV_Enable = new Convar("shavit_zones_json_enable", "1", "Whether to enable this or not...", 0, true, 0.0, true, 1.0);
|
||||
gCV_UseRipext = new Convar("shavit_zones_json_ripext", "1", "Whether to use ripext or steamworks", 0, true, 0.0, true, 1.0);
|
||||
gCV_ApiUrl = new Convar("shavit_zones_json_url", "http://zones-{engine}.srcwr.com/z/{map}.json", "API URL. Will replace `{map}`, `{key}`, and `{engine}` with the mapname, api key, and engine name....\nOther example urls:\n https://srcwr.github.io/zones-{engine}/z/{map}.json\n https://sourcejump.net/api/v2/maps/{map}/zones", FCVAR_PROTECTED);
|
||||
gCV_ApiKey = new Convar("shavit_zones_json_key", "", "API key that some APIs might require.", FCVAR_PROTECTED);
|
||||
gCV_Source = new Convar("shavit_zones_json_src", "http", "A string used by plugins to identify where a zone came from (http, sourcejump, sql, etc)");
|
||||
gCV_Folder = new Convar("shavit_zones_json_folder", "0", "Whether to use a local folder for json zones instead of the http URL.\n0 - use HTTP stuff...\n1 - use folder of JSON zones at `addons/sourcemod/data/zones-{engine}/z/{map}.json`");
|
||||
|
||||
Convar.AutoExecConfig();
|
||||
|
||||
RegAdminCmd("sm_dumpzones", Command_DumpZones, ADMFLAG_RCON, "Dumps current map's zones to a json file");
|
||||
RegAdminCmd("sm_editmi", Command_EditMapInfo, ADMFLAG_RCON, "Edits current map's info and dumps to a json file");
|
||||
|
||||
if (gB_Late)
|
||||
{
|
||||
gB_YouCanLoadZonesNow = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMapEnd()
|
||||
{
|
||||
gB_YouCanLoadZonesNow = false;
|
||||
}
|
||||
|
||||
public void OnConfigsExecuted()
|
||||
{
|
||||
GetLowercaseMapName(gS_Map);
|
||||
|
||||
if (!StrEqual(gS_Map, gS_ZonesForMap))
|
||||
{
|
||||
RetrieveZones(gS_Map);
|
||||
}
|
||||
}
|
||||
|
||||
public void Shavit_LoadZonesHere()
|
||||
{
|
||||
gB_YouCanLoadZonesNow = true;
|
||||
|
||||
if (StrEqual(gS_Map, gS_ZonesForMap))
|
||||
{
|
||||
LoadCachedZones();
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCachedZones()
|
||||
{
|
||||
if (!gCV_Enable.BoolValue || !gA_Zones)
|
||||
return;
|
||||
|
||||
Shavit_UnloadZones(); // TODO: fuck it......
|
||||
|
||||
for (int i = 0; i < gA_Zones.Length; i++)
|
||||
{
|
||||
zone_cache_t cache;
|
||||
gA_Zones.GetArray(i, cache);
|
||||
Shavit_AddZone(cache);
|
||||
}
|
||||
}
|
||||
|
||||
void RetrieveZones(const char[] mapname)
|
||||
{
|
||||
if (!gCV_Enable.BoolValue)
|
||||
return;
|
||||
|
||||
if (gCV_Folder.BoolValue)
|
||||
{
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/zones-%s/z/%s.json", gS_EngineName, gS_Map);
|
||||
|
||||
JSONArray records = JSONArray.FromFile(path);
|
||||
|
||||
if (records)
|
||||
{
|
||||
gS_ZonesForMap = gS_Map;
|
||||
delete gA_Zones;
|
||||
gA_Zones = EatUpZones(records, true, "folder");
|
||||
delete records;
|
||||
if (gB_YouCanLoadZonesNow)
|
||||
LoadCachedZones();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
char apikey[64], apiurl[512];
|
||||
gCV_ApiKey.GetString(apikey, sizeof(apikey));
|
||||
gCV_ApiUrl.GetString(apiurl, sizeof(apiurl));
|
||||
|
||||
if (!apiurl[0])
|
||||
{
|
||||
LogError("Missing API URL");
|
||||
return;
|
||||
}
|
||||
|
||||
ReplaceString(apiurl, sizeof(apiurl), "{map}", mapname);
|
||||
ReplaceString(apiurl, sizeof(apiurl), "{key}", apikey);
|
||||
ReplaceString(apiurl, sizeof(apiurl), "{engine}", gS_EngineName);
|
||||
|
||||
DataPack pack = new DataPack();
|
||||
pack.WriteString(mapname);
|
||||
|
||||
if (gCV_UseRipext.BoolValue)
|
||||
{
|
||||
HTTPRequest http = new HTTPRequest(apiurl);
|
||||
if (apikey[0])
|
||||
http.SetHeader("api-key", "%s", apikey);
|
||||
http.SetHeader("map", "%s", mapname);
|
||||
http.Get(RequestCallback_Ripext, pack);
|
||||
return;
|
||||
}
|
||||
|
||||
Handle request;
|
||||
if (!(request = SteamWorks_CreateHTTPRequest(k_EHTTPMethodGET, apiurl))
|
||||
|| (apikey[0] && !SteamWorks_SetHTTPRequestHeaderValue(request, "api-key", apikey))
|
||||
|| !SteamWorks_SetHTTPRequestHeaderValue(request, "accept", "application/json")
|
||||
|| !(!apikey[0] || SteamWorks_SetHTTPRequestHeaderValue(request, "api-key", apikey))
|
||||
|| !SteamWorks_SetHTTPRequestHeaderValue(request, "map", mapname)
|
||||
|| !SteamWorks_SetHTTPRequestContextValue(request, pack)
|
||||
|| !SteamWorks_SetHTTPRequestAbsoluteTimeoutMS(request, 4000)
|
||||
//|| !SteamWorks_SetHTTPRequestRequiresVerifiedCertificate(request, true)
|
||||
|| !SteamWorks_SetHTTPCallbacks(request, RequestCompletedCallback_Steamworks)
|
||||
|| !SteamWorks_SendHTTPRequest(request)
|
||||
)
|
||||
{
|
||||
CloseHandle(request);
|
||||
LogError("failed to setup & send HTTP request");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestCallback_Ripext(HTTPResponse response, DataPack pack, const char[] error)
|
||||
{
|
||||
if (response.Status != HTTPStatus_OK || response.Data == null)
|
||||
{
|
||||
LogError("HTTP API request failed");
|
||||
delete pack;
|
||||
return;
|
||||
}
|
||||
|
||||
handlestuff(pack, response.Data, true);
|
||||
}
|
||||
|
||||
public void RequestCompletedCallback_Steamworks(Handle request, bool bFailure, bool bRequestSuccessful, EHTTPStatusCode eStatusCode, DataPack pack)
|
||||
{
|
||||
if (bFailure || !bRequestSuccessful || eStatusCode != k_EHTTPStatusCode200OK)
|
||||
{
|
||||
pack.Reset();
|
||||
char mapname[PLATFORM_MAX_PATH];
|
||||
pack.ReadString(mapname, sizeof(mapname));
|
||||
delete pack;
|
||||
LogError("HTTP API failed for '%s'. statuscode=%d", mapname, eStatusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
SteamWorks_GetHTTPResponseBodyCallback(request, RequestCallback_Steamworks, pack);
|
||||
}
|
||||
|
||||
void RequestCallback_Steamworks(const char[] data, DataPack pack)
|
||||
{
|
||||
JSON_Array records = view_as<JSON_Array>(json_decode(data));
|
||||
|
||||
if (records)
|
||||
{
|
||||
handlestuff(pack, records, false);
|
||||
json_cleanup(records);
|
||||
}
|
||||
}
|
||||
|
||||
enum struct JsonThing
|
||||
{
|
||||
JSONObject objrip;
|
||||
JSON_Object objsw;
|
||||
bool isrip;
|
||||
|
||||
bool HasKey(const char[] key)
|
||||
{
|
||||
return this.isrip ? this.objrip.HasKey(key) : this.objsw.HasKey(key);
|
||||
}
|
||||
|
||||
int GetInt(const char[] key)
|
||||
{
|
||||
return this.isrip ? this.objrip.GetInt(key) : this.objsw.GetInt(key);
|
||||
}
|
||||
|
||||
float GetFloat(const char[] key)
|
||||
{
|
||||
return this.isrip ? this.objrip.GetFloat(key) : this.objsw.GetFloat(key);
|
||||
}
|
||||
|
||||
bool GetString(const char[] key, char[] buf, int size)
|
||||
{
|
||||
return this.isrip ? this.objrip.GetString(key, buf, size) : this.objsw.GetString(key, buf, size);
|
||||
}
|
||||
|
||||
void GetVec(const char[] key, float vec[3])
|
||||
{
|
||||
if (this.isrip)
|
||||
{
|
||||
JSONArray arr = view_as<JSONArray>(this.objrip.Get(key));
|
||||
vec[0] = arr.GetFloat(0);
|
||||
vec[1] = arr.GetFloat(1);
|
||||
vec[2] = arr.GetFloat(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_Array arr = view_as<JSON_Array>(this.objsw.GetObject(key));
|
||||
vec[0] = arr.GetFloat(0);
|
||||
vec[1] = arr.GetFloat(1);
|
||||
vec[2] = arr.GetFloat(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handlestuff(DataPack pack, any records, bool ripext)
|
||||
{
|
||||
pack.Reset();
|
||||
char mapname[PLATFORM_MAX_PATH];
|
||||
pack.ReadString(mapname, sizeof(mapname));
|
||||
delete pack;
|
||||
|
||||
if (!StrEqual(mapname, gS_Map))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char source[16];
|
||||
gCV_Source.GetString(source, sizeof(source));
|
||||
if (!source[0]) source = "http";
|
||||
|
||||
gS_ZonesForMap = mapname;
|
||||
delete gA_Zones;
|
||||
gA_Zones = EatUpZones(records, ripext, source);
|
||||
|
||||
if (gB_YouCanLoadZonesNow)
|
||||
LoadCachedZones();
|
||||
}
|
||||
|
||||
ArrayList EatUpZones(any records, bool ripext, const char source[16])
|
||||
{
|
||||
ArrayList zones = new ArrayList(sizeof(zone_cache_t));
|
||||
|
||||
int asdf = ripext ? view_as<JSONArray>(records).Length : view_as<JSON_Array>(records).Length;
|
||||
|
||||
for (int RN = 0; RN < asdf; RN++)
|
||||
{
|
||||
any data = ripext ?
|
||||
view_as<int>(view_as<JSONArray>(records).Get(RN)) :
|
||||
view_as<int>(view_as<JSON_Array>(records).GetObject(RN));
|
||||
|
||||
JsonThing json;
|
||||
json.objrip = data;
|
||||
json.objsw = data;
|
||||
json.isrip = ripext;
|
||||
|
||||
char buf[32];
|
||||
zone_cache_t cache;
|
||||
|
||||
json.GetString("type", buf, sizeof(buf));
|
||||
cache.iType = -1;
|
||||
|
||||
for (int i = 0; i < ZONETYPES_SIZE; i++)
|
||||
{
|
||||
if (StrEqual(buf, gS_ZoneTypes[i]))
|
||||
{
|
||||
cache.iType = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cache.iType == -1)
|
||||
{
|
||||
//PrintToServer("");
|
||||
continue;
|
||||
}
|
||||
|
||||
cache.iTrack = json.GetInt("track");
|
||||
//cache.iEntity
|
||||
cache.iDatabaseID = json.GetInt("id");
|
||||
if (json.HasKey("flags")) cache.iFlags = json.GetInt("flags");
|
||||
if (json.HasKey("data")) cache.iData = json.GetInt("data");
|
||||
|
||||
if (cache.iType == Zone_Stage)
|
||||
if (json.HasKey("index")) cache.iData = json.GetInt("index");
|
||||
|
||||
if (json.HasKey("point_a")) json.GetVec("point_a", cache.fCorner1);
|
||||
if (json.HasKey("point_b")) json.GetVec("point_b", cache.fCorner2);
|
||||
if (json.HasKey("dest")) json.GetVec("dest", cache.fDestination);
|
||||
|
||||
if (json.HasKey("form")) cache.iForm = json.GetInt("form");
|
||||
if (json.HasKey("target")) json.GetString("target", cache.sTarget, sizeof(cache.sTarget));
|
||||
//json.GetString("source", cache.sSource, sizeof(cache.sSource));
|
||||
cache.sSource = source;
|
||||
zones.PushArray(cache);
|
||||
}
|
||||
|
||||
if (!zones.Length)
|
||||
delete zones;
|
||||
return zones;
|
||||
}
|
||||
|
||||
void FillBoxMinMax(float point1[3], float point2[3], float boxmin[3], float boxmax[3])
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
float a = point1[i];
|
||||
float b = point2[i];
|
||||
|
||||
if (a < b)
|
||||
{
|
||||
boxmin[i] = a;
|
||||
boxmax[i] = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
boxmin[i] = b;
|
||||
boxmax[i] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EmptyVector(float vec[3])
|
||||
{
|
||||
return vec[0] == 0.0 && vec[1] == 0.0 && vec[2] == 0.0;
|
||||
}
|
||||
|
||||
JSONObject FillYourMom(zone_cache_t cache)
|
||||
{
|
||||
// normalize mins & maxs......................................................
|
||||
FillBoxMinMax(cache.fCorner1, cache.fCorner2, cache.fCorner1, cache.fCorner2);
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.SetString("type", gS_ZoneTypes[cache.iType]);
|
||||
obj.SetInt("track", cache.iTrack);
|
||||
obj.SetInt("id", cache.iDatabaseID);
|
||||
if (cache.iFlags) obj.SetInt("flags", cache.iFlags);
|
||||
if (cache.iData) obj.SetInt("data", cache.iData);
|
||||
JSONArray a = new JSONArray(), b = new JSONArray(), c = new JSONArray();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
a.PushFloat(cache.fCorner1[i]);
|
||||
b.PushFloat(cache.fCorner2[i]);
|
||||
c.PushFloat(cache.fDestination[i]);
|
||||
}
|
||||
if (!EmptyVector(cache.fCorner1)) obj.Set("point_a", a);
|
||||
if (!EmptyVector(cache.fCorner2)) obj.Set("point_b", b);
|
||||
if (!EmptyVector(cache.fDestination)) obj.Set("dest", c);
|
||||
if (cache.iForm) obj.SetInt("form", cache.iForm);
|
||||
if (cache.sTarget[0]) obj.SetString("target", cache.sTarget);
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Action Command_DumpZones(int client, int args)
|
||||
{
|
||||
int count = Shavit_GetZoneCount();
|
||||
|
||||
if (!count)
|
||||
{
|
||||
ReplyToCommand(client, "Map doesn't have any zones...");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
JSONArray wow = new JSONArray();
|
||||
|
||||
for (int XXXXXX = 0; XXXXXX < count; XXXXXX++)
|
||||
{
|
||||
zone_cache_t cache;
|
||||
Shavit_GetZone(XXXXXX, cache);
|
||||
JSONObject obj = FillYourMom(cache);
|
||||
wow.Push(obj);
|
||||
delete obj;
|
||||
}
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/zones-%s/z/%s.json", gS_EngineName, gS_Map);
|
||||
wow.ToFile(path, JSON_SORT_KEYS);
|
||||
delete wow;
|
||||
Shavit_PrintToChat(client, "Dumped zones to %s", path);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
int MaybeInt(JSONObject json, const char[] key, int defaultttt=0) // TODO: remove
|
||||
{
|
||||
if (json && json.HasKey(key)) return json.GetInt(key);
|
||||
return defaultttt;
|
||||
}
|
||||
|
||||
void JsonToMapInfo(JSONArray arr)
|
||||
{
|
||||
for (int i = 0; i < TRACKS_SIZE; i++)
|
||||
{
|
||||
JSONObject obj = (arr.Length > i && !arr.IsNull(i)) ? view_as<JSONObject>(arr.Get(i)) : null;
|
||||
gA_TrackInfo[i].tier = MaybeInt(obj, "tier", 0);
|
||||
gA_TrackInfo[i].possible_on_scroll = MaybeInt(obj, "possible_on_scroll", -1);
|
||||
gA_TrackInfo[i].possible_on_400vel = MaybeInt(obj, "possible_on_400vel", -1);
|
||||
gA_TrackInfo[i].possible_on_stamina = MaybeInt(obj, "possible_on_stamina", -1);
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject MapInfoToJson(MapInfoTrack info)
|
||||
{
|
||||
JSONObject json = new JSONObject();
|
||||
if (info.tier > 0) json.SetInt("tier", info.tier);
|
||||
if (info.possible_on_scroll > -1) json.SetInt("possible_on_scroll", info.possible_on_scroll);
|
||||
if (info.possible_on_400vel > -1) json.SetInt("possible_on_400vel", info.possible_on_400vel);
|
||||
if (info.possible_on_stamina > -1) json.SetInt("possible_on_stamina", info.possible_on_stamina);
|
||||
if (json.Size < 1) delete json;
|
||||
return json;
|
||||
}
|
||||
|
||||
int MenuHandler_MapInfo(Menu menu, MenuAction action, int param1, int param2)
|
||||
{
|
||||
if (action == MenuAction_Select)
|
||||
{
|
||||
char info[32];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
int track = gI_MapInfoTrack[param1];
|
||||
|
||||
if (StrEqual(info, "save"))
|
||||
{
|
||||
JSONArray arr = new JSONArray();
|
||||
JSONObject empty = new JSONObject();
|
||||
|
||||
for (int i, empties; i < TRACKS_SIZE; i++)
|
||||
{
|
||||
JSONObject obj = MapInfoToJson(gA_TrackInfo[i]);
|
||||
|
||||
if (!obj)
|
||||
{
|
||||
++empties;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (; empties; --empties)
|
||||
arr.Push(empty);
|
||||
arr.Push(obj);
|
||||
delete obj;
|
||||
}
|
||||
|
||||
delete empty;
|
||||
|
||||
if (!arr.Length)
|
||||
{
|
||||
delete arr;
|
||||
Shavit_PrintToChat(param1, "Empty map info array... doing nothing");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/zones-%s/i/%s.json", gS_EngineName, gS_Map);
|
||||
arr.ToFile(path);
|
||||
char buff[512];
|
||||
arr.ToString(buff, sizeof(buff));
|
||||
PrintToServer("%s", buff);
|
||||
delete arr;
|
||||
Shavit_PrintToChat(param1, "Wrote mapinfo to %s", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (StrEqual(info, "back2main"))
|
||||
{
|
||||
gI_MapInfoTrack[param1] = 0;
|
||||
}
|
||||
else if (StrEqual(info, "trackiter"))
|
||||
{
|
||||
gI_MapInfoTrack[param1] = (track + 1) % TRACKS_SIZE;
|
||||
}
|
||||
else if (StrEqual(info, "tier"))
|
||||
{
|
||||
gA_TrackInfo[track].tier = (gA_TrackInfo[track].tier + 1) % 11; // hardcode 10 lol
|
||||
}
|
||||
else if (StrEqual(info, "scroll"))
|
||||
{
|
||||
gA_TrackInfo[track].possible_on_scroll += 1;
|
||||
if (gA_TrackInfo[track].possible_on_scroll > 2)
|
||||
gA_TrackInfo[track].possible_on_scroll = -1;
|
||||
}
|
||||
else if (StrEqual(info, "400vel"))
|
||||
{
|
||||
gA_TrackInfo[track].possible_on_400vel += 1;
|
||||
if (gA_TrackInfo[track].possible_on_400vel > 2)
|
||||
gA_TrackInfo[track].possible_on_400vel = -1;
|
||||
}
|
||||
else if (StrEqual(info, "stamina"))
|
||||
{
|
||||
gA_TrackInfo[track].possible_on_stamina += 1;
|
||||
if (gA_TrackInfo[track].possible_on_stamina > 2)
|
||||
gA_TrackInfo[track].possible_on_stamina = -1;
|
||||
}
|
||||
|
||||
CreateMapInfoMenu(param1);
|
||||
}
|
||||
else if (action == MenuAction_End)
|
||||
{
|
||||
delete menu;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CreateMapInfoMenu(int client)
|
||||
{
|
||||
Menu menu = new Menu(MenuHandler_MapInfo);
|
||||
menu.SetTitle("Map info\n ");
|
||||
|
||||
char display[128];
|
||||
int track = gI_MapInfoTrack[client];
|
||||
int tier = gA_TrackInfo[track].tier;
|
||||
|
||||
menu.AddItem("save", "Save\n ");
|
||||
menu.AddItem("back2main", "Back to Main track",
|
||||
track > 0 ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED);
|
||||
|
||||
GetTrackName(client, track, display, sizeof(display), true);
|
||||
Format(display, sizeof(display), "Track: %s\n ", display);
|
||||
menu.AddItem("trackiter", display);
|
||||
|
||||
FormatEx(display, sizeof(display), "Track Tier: %d%s", tier, tier < 1 ? " (unknown)" : "");
|
||||
menu.AddItem("tier", display);
|
||||
|
||||
FormatEx(display, sizeof(display), "Possible on Scroll: %s", gS_InfoDescripters[1 + gA_TrackInfo[track].possible_on_scroll]);
|
||||
menu.AddItem("scroll", display);
|
||||
FormatEx(display, sizeof(display), "Possible on 400vel: %s", gS_InfoDescripters[1 + gA_TrackInfo[track].possible_on_400vel]);
|
||||
menu.AddItem("400vel", display);
|
||||
FormatEx(display, sizeof(display), "Possible on Stamina: %s\n ", gS_InfoDescripters[1 + gA_TrackInfo[track].possible_on_stamina]);
|
||||
menu.AddItem("stamina", display);
|
||||
|
||||
menu.ExitButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
public Action Command_EditMapInfo(int client, int args)
|
||||
{
|
||||
if (!client)
|
||||
{
|
||||
ReplyToCommand(client, "You're not real");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/zones-%s/i/%s.json", gS_EngineName, gS_Map);
|
||||
|
||||
JSONArray arr = JSONArray.FromFile(path);
|
||||
if (!arr) arr = new JSONArray();
|
||||
JsonToMapInfo(arr);
|
||||
delete arr;
|
||||
|
||||
int empty[MAXPLAYERS+1];
|
||||
gI_MapInfoTrack = empty;
|
||||
|
||||
CreateMapInfoMenu(client);
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,11 @@
|
||||
{
|
||||
"en" "Check your console."
|
||||
}
|
||||
"CCAccessGrantedToPlayer"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You've been given access to custom chat! Use {1}!cchelp{2} for more info."
|
||||
}
|
||||
"CCHelp_Intro"
|
||||
{
|
||||
"en" "- You have access to custom chat.\nUsage information:"
|
||||
@ -51,6 +56,18 @@
|
||||
{
|
||||
"en" "Select chat rank:\n"
|
||||
}
|
||||
"SelectChatRankType"
|
||||
{
|
||||
"en" "Which chat ranks do you want to see?\n"
|
||||
}
|
||||
"SelectChatRankUnlocked"
|
||||
{
|
||||
"en" "Unlocked chat ranks\n"
|
||||
}
|
||||
"SelectChatRankAll"
|
||||
{
|
||||
"en" "All chat ranks\n"
|
||||
}
|
||||
"AutoAssign"
|
||||
{
|
||||
"en" "Auto-assign\nAutomatically assign using your rank."
|
||||
@ -63,90 +80,6 @@
|
||||
{
|
||||
"en" "Obtainable chat ranks:\nSelect an entry to preview.\n"
|
||||
}
|
||||
"ChatRanksMenu_Unranked"
|
||||
{
|
||||
"en" "Unranked"
|
||||
}
|
||||
"ChatRanksMenu_Points"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Have {1} points"
|
||||
}
|
||||
"ChatRanksMenu_Points_1"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Have {1} point"
|
||||
}
|
||||
"ChatRanksMenu_Points_Ranged"
|
||||
{
|
||||
"#format" "{1:.0f},{2:.0f}"
|
||||
"en" "Have between {1} and {2} points"
|
||||
}
|
||||
"ChatRanksMenu_Flat"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Ranked #{1} or better"
|
||||
}
|
||||
"ChatRanksMenu_Flat_1"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Ranked #{1}"
|
||||
}
|
||||
"ChatRanksMenu_Flat_Ranged"
|
||||
{
|
||||
"#format" "{1:.0f},{2:.0f}"
|
||||
"en" "Ranked between #{1} and #{2}"
|
||||
}
|
||||
"ChatRanksMenu_Percentage"
|
||||
{
|
||||
"#format" "{1:.1f},{2:.0f},{3:c}"
|
||||
"en" "Top {1}{3}"
|
||||
}
|
||||
"ChatRanksMenu_Percentage_Ranged"
|
||||
{
|
||||
"#format" "{1:.1f},{2:.1f},{3:c},{4:c}"
|
||||
"en" "Between top {1}{3} and {2}{4}"
|
||||
}
|
||||
"ChatRanksMenu_WR_Count"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Have {1} WRs"
|
||||
}
|
||||
"ChatRanksMenu_WR_Count_1"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Have {1} WR"
|
||||
}
|
||||
"ChatRanksMenu_WR_Count_Ranged"
|
||||
{
|
||||
"#format" "{1:.0f},{2:.0f}"
|
||||
"en" "Have between {1} and {2} WRs"
|
||||
}
|
||||
"ChatRanksMenu_WR_Rank"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Ranked #{1} or better from WR holders"
|
||||
}
|
||||
"ChatRanksMenu_WR_Rank_1"
|
||||
{
|
||||
"#format" "{1:.0f}"
|
||||
"en" "Ranked #{1} out of WRs held"
|
||||
}
|
||||
"ChatRanksMenu_WR_Rank_Ranged"
|
||||
{
|
||||
"#format" "{1:.0f},{2:.0f}"
|
||||
"en" "Ranked between #{1} and #{2} out of WRs held"
|
||||
}
|
||||
"ChatRanksMenu_WR_Rank_Percentage"
|
||||
{
|
||||
"#format" "{1:.0f},{2:.0f},{3:c}"
|
||||
"en" "Top {1}{3} out of WRs held"
|
||||
}
|
||||
"ChatRanksMenu_WR_Rank_Percentage_Ranged"
|
||||
{
|
||||
"#format" "{1:.0f},{2:.0f},{3:c},{4:c}"
|
||||
"en" "Between Top {1}{3} and {2}{4} out of WRs held"
|
||||
}
|
||||
"ChatRanksMenu_SampleText"
|
||||
{
|
||||
"en" "The quick brown fox jumps over the lazy dog"
|
||||
|
||||
@ -18,6 +18,10 @@
|
||||
"#format" "{1:d}"
|
||||
"en" "Bonus {1}"
|
||||
}
|
||||
"Track_Bonus_NoNum"
|
||||
{
|
||||
"en" "Bonus"
|
||||
}
|
||||
// ---------- Commands ---------- //
|
||||
"NoCommandAccess"
|
||||
{
|
||||
@ -41,10 +45,37 @@
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "{1} minutes remaining."
|
||||
}
|
||||
}
|
||||
"Seconds"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "{1} seconds remaining."
|
||||
}
|
||||
"Extended"
|
||||
{
|
||||
"#format" "{1:s},{2:N},{3:s},{4:s},{5:d},{6:s}"
|
||||
"en" "{1}{2}{3} extended the map by {4}{5}{6} minutes."
|
||||
}
|
||||
// ----------- Random ----------- //
|
||||
"TimerLoading"
|
||||
{
|
||||
"en" "Loading.."
|
||||
}
|
||||
"Timescale"
|
||||
{
|
||||
"en" "Timescale"
|
||||
}
|
||||
"CurrentTimescale"
|
||||
{
|
||||
"en" "Current Timescale"
|
||||
}
|
||||
"OpenSteamProfile"
|
||||
{
|
||||
"en" "Open Steam profile"
|
||||
}
|
||||
"ReRolling Maps"
|
||||
{
|
||||
"#format" "{1:i},{2:i}"
|
||||
"en" "Voting for next map has restarted. Reroll complete. (Received {1}%% of {2} votes)"
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,11 +26,25 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You lack the {1}permissions{2} for this style."
|
||||
}
|
||||
"NoEditingTimescale"
|
||||
{
|
||||
"en" "This style doesn't allow you to change timescale."
|
||||
}
|
||||
// ---------- Errors ---------- //
|
||||
"VerificationFailed"
|
||||
{
|
||||
"en" "Couldn't verify your, or the server's connection to Steam."
|
||||
}
|
||||
"TimeUnderMinimumTime"
|
||||
{
|
||||
"#format" "{1:f},{2:f},{3:s}"
|
||||
"en" "Your time ({2}) was faster than the style's {3} setting ({1}) and did not count."
|
||||
}
|
||||
"TimeUnderMinimumTime2"
|
||||
{
|
||||
"#format" "{1:f},{2:f}"
|
||||
"en" "Your time ({2}) was faster or equal to the timer's minimum ({1}) and did not count."
|
||||
}
|
||||
// ---------- Menus ---------- //
|
||||
"StyleMenuTitle"
|
||||
{
|
||||
|
||||
@ -16,10 +16,15 @@
|
||||
"#format" "{1:d}"
|
||||
"en" "In Start Zone\n\n{1}"
|
||||
}
|
||||
"HudInStartZoneNoSpeed"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "In Start Zone"
|
||||
}
|
||||
"HudInStartZoneCSGO"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "In Start Zone\n\n\t\t\t{1}"
|
||||
"en" "In Start Zone"
|
||||
}
|
||||
"HudEndZone"
|
||||
{
|
||||
@ -30,10 +35,15 @@
|
||||
"#format" "{1:d}"
|
||||
"en" "In End Zone\n\n{1}"
|
||||
}
|
||||
"HudInEndZoneNoSpeed"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "In End Zone"
|
||||
}
|
||||
"HudInEndZoneCSGO"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "In End Zone\n\n\t\t\t{1}"
|
||||
"en" "In End Zone"
|
||||
}
|
||||
"HudPaused"
|
||||
{
|
||||
@ -75,6 +85,22 @@
|
||||
{
|
||||
"en" "Perfect jumps"
|
||||
}
|
||||
"HudPerfsCenter"
|
||||
{
|
||||
"en" "Perfect jumps (center hud)"
|
||||
}
|
||||
"HudDefaultPistol"
|
||||
{
|
||||
"en" "Default Pistol: 1=USP 2=Glock"
|
||||
}
|
||||
"HudUSPSilencer"
|
||||
{
|
||||
"en" "Spawn USPs with a silencer attached"
|
||||
}
|
||||
"HudGlockBurst"
|
||||
{
|
||||
"en" "Spawn Glocks with Burst"
|
||||
}
|
||||
"HudPracticeMode"
|
||||
{
|
||||
"en" "[PRACTICE]"
|
||||
@ -88,6 +114,10 @@
|
||||
"#format" "{1:d}"
|
||||
"en" "(Speed Limit: {1})"
|
||||
}
|
||||
"HudCenterKeys"
|
||||
{
|
||||
"en" "!keys in the center"
|
||||
}
|
||||
// ---------- Menus ---------- //
|
||||
"HUDMenuTitle"
|
||||
{
|
||||
@ -113,6 +143,10 @@
|
||||
{
|
||||
"en" "Spectator list"
|
||||
}
|
||||
"HudSpectatorsDead"
|
||||
{
|
||||
"en" "Spectator list (only when dead)"
|
||||
}
|
||||
"HudKeyOverlay"
|
||||
{
|
||||
"en" "Key display"
|
||||
@ -165,6 +199,10 @@
|
||||
{
|
||||
"en" "Velocity Difference"
|
||||
}
|
||||
"HudDebugTargetname"
|
||||
{
|
||||
"en" "Debug targetname"
|
||||
}
|
||||
// ---------- Record Bots ---------- //
|
||||
"ReplayText"
|
||||
{
|
||||
|
||||
@ -48,6 +48,26 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You are now {1}not hiding{2} players."
|
||||
}
|
||||
"AutoRestartEnabled"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You will now {1}automatically restart{2} if you are slower than your PB."
|
||||
}
|
||||
"AutoRestartDisabled"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You will no longer {1}automatically restart{2}."
|
||||
}
|
||||
"AutoRestartTriggered1"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You were {1}automatically restarted{2} due to being slower than your PB."
|
||||
}
|
||||
"AutoRestartTriggered2"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Use {1}!autorestart{2} to disable this."
|
||||
}
|
||||
"LackingAccess"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
@ -99,10 +119,14 @@
|
||||
{
|
||||
"en" "Unable to save due to checkpoint overflow."
|
||||
}
|
||||
"MiscCheckpointOwnerInvalid"
|
||||
{
|
||||
"en" "The checkpoint's owner is invalid or has disconnected."
|
||||
}
|
||||
"MiscSegmentedCommand"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Use {1}!cp{2} to re-open the segmented checkpoints menu."
|
||||
"en" "Use {1}!cp{2} to re-open the checkpoints menu."
|
||||
}
|
||||
// ---------- Menus ---------- //
|
||||
"StopTimerWarning"
|
||||
@ -129,6 +153,10 @@
|
||||
{
|
||||
"en" "No."
|
||||
}
|
||||
"MiscCheckpointNoOtherPlayers"
|
||||
{
|
||||
"en" "You are alone (also, the server is empty)"
|
||||
}
|
||||
"TeleportMenuTitle"
|
||||
{
|
||||
"en" "Teleport to:"
|
||||
@ -152,8 +180,13 @@
|
||||
}
|
||||
"MiscCheckpointSave"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "Save checkpoint ({1})"
|
||||
"#format" "{1:d},{2:d}"
|
||||
"en" "Save checkpoint ({1}/{2})"
|
||||
}
|
||||
"MiscCheckpointDuplicate"
|
||||
{
|
||||
"#format" "{1:d},{2:d}"
|
||||
"en" "Duplicate checkpoint ({1}/{2})"
|
||||
}
|
||||
"MiscCheckpointTeleport"
|
||||
{
|
||||
@ -168,6 +201,14 @@
|
||||
{
|
||||
"en" "Next"
|
||||
}
|
||||
"MiscCheckpointUseOthers"
|
||||
{
|
||||
"en" "Use another player's checkpoints"
|
||||
}
|
||||
"MiscCheckpointBack"
|
||||
{
|
||||
"en" "Back to your checkpoints"
|
||||
}
|
||||
"MiscCheckpointReset"
|
||||
{
|
||||
"en" "Reset checkpoints"
|
||||
@ -188,6 +229,78 @@
|
||||
{
|
||||
"en" "Use velocity"
|
||||
}
|
||||
"TasSettings"
|
||||
{
|
||||
"en" "TAS Settings"
|
||||
}
|
||||
"Autostrafer"
|
||||
{
|
||||
"en" "Autostrafer"
|
||||
}
|
||||
"AutoJumpOnStart"
|
||||
{
|
||||
"en" "Jump on start-zone exit"
|
||||
}
|
||||
"EdgeJump"
|
||||
{
|
||||
"en" "Edge jump"
|
||||
}
|
||||
"AutogainBasicStrafer"
|
||||
{
|
||||
"en" "Autogain basic strafer"
|
||||
}
|
||||
"AutoPrestrafe"
|
||||
{
|
||||
"en" "Auto Prestrafe"
|
||||
}
|
||||
"Autostrafer_type"
|
||||
{
|
||||
"en" "Type"
|
||||
}
|
||||
"Autostrafer_1tick"
|
||||
{
|
||||
"en" "1Tick (xutaxkamay)"
|
||||
}
|
||||
"Autostrafer_autogain"
|
||||
{
|
||||
"en" "Velocity/autogain (oblivious)"
|
||||
}
|
||||
"Autostrafer_autogain_nsl"
|
||||
{
|
||||
"en" "Velocity/autogain (No speed loss) (oblivious)"
|
||||
}
|
||||
"Autostrafer_basic"
|
||||
{
|
||||
"en" "Basic"
|
||||
}
|
||||
"TASEnabled"
|
||||
{
|
||||
"en" "Enabled"
|
||||
}
|
||||
"TASDisabled"
|
||||
{
|
||||
"en" "Disabled"
|
||||
}
|
||||
"AutostrafeOverride"
|
||||
{
|
||||
"en" "Key Override"
|
||||
}
|
||||
"AutostrafeOverride_Normal"
|
||||
{
|
||||
"en" "W/S"
|
||||
}
|
||||
"AutostrafeOverride_Surf"
|
||||
{
|
||||
"en" "W/S (and A/D on surf ramps)"
|
||||
}
|
||||
"AutostrafeOverride_Surf_W_Okay"
|
||||
{
|
||||
"en" "S (and A/D on surf ramps)"
|
||||
}
|
||||
"AutostrafeOverride_All"
|
||||
{
|
||||
"en" "W/S A/D"
|
||||
}
|
||||
// ---------- Misc ---------- //
|
||||
"BHStartZoneDisallowed"
|
||||
{
|
||||
|
||||
@ -107,6 +107,11 @@
|
||||
"#format" "{1:s}"
|
||||
"en" "[{1}] Toggle 2x speed"
|
||||
}
|
||||
"Menu_PlaybackSpeed"
|
||||
{
|
||||
"#format" "{1:.1f}"
|
||||
"en" "Playback speed: {1}x"
|
||||
}
|
||||
"Menu_RefreshReplay"
|
||||
{
|
||||
"en" "Refresh"
|
||||
|
||||
@ -6,11 +6,20 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "{1}ERROR: {2}Could not open the stats menu."
|
||||
}
|
||||
"StatsMenuUnknownPlayer"
|
||||
{
|
||||
"#format" "{1:s},{2:s},{3:s},{4:d}"
|
||||
"en" "{1}ERROR: {2}Unknown player {3}[U:1:{4}]"
|
||||
}
|
||||
// ---------- Map Completions ---------- //
|
||||
"SelectTrack"
|
||||
{
|
||||
"en" "Select timer track:"
|
||||
}
|
||||
"SelectTier"
|
||||
{
|
||||
"en" "Select map tier:"
|
||||
}
|
||||
"MapsDone"
|
||||
{
|
||||
"en" "Maps done"
|
||||
@ -69,6 +78,10 @@
|
||||
{
|
||||
"en" "Last Login"
|
||||
}
|
||||
"FirstLogin"
|
||||
{
|
||||
"en" "First Login"
|
||||
}
|
||||
"MapCompletions"
|
||||
{
|
||||
"en" "Map completions"
|
||||
|
||||
@ -25,6 +25,11 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Records for {1}:\n({2})"
|
||||
}
|
||||
"ListPersonalBest"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Personal best for {1} on {2}"
|
||||
}
|
||||
// ---------- Completion Messages ---------- //
|
||||
"FirstCompletion"
|
||||
{
|
||||
@ -132,12 +137,38 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "{1}FATAL ERROR: {2}No styles are available. Contact the server owner immediately!"
|
||||
}
|
||||
// ---------- WR Menu ---------- //
|
||||
"NoPB"
|
||||
{
|
||||
"#format" "{1:s},{2:s},{3:s},{4:s},{5:s},{6:s}"
|
||||
"en" "No PB records were found for {1}{2}{3} on map {4}{5}{6}."
|
||||
}
|
||||
// ---------- RR Menu ---------- //
|
||||
"RecentRecords"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "Recent {1} record(s)"
|
||||
}
|
||||
"RecentRecordsFirstMenuTitle"
|
||||
{
|
||||
"en" "Recent records"
|
||||
}
|
||||
"RecentRecordsStyleSelectionMenuTitle"
|
||||
{
|
||||
"en" "Recent records (by style)"
|
||||
}
|
||||
"RecentRecordsAll"
|
||||
{
|
||||
"en" "All recent records"
|
||||
}
|
||||
"RecentRecordsByStyle"
|
||||
{
|
||||
"en" "Sorted by style"
|
||||
}
|
||||
"RecentRecordsMainOnly"
|
||||
{
|
||||
"en" "Main only"
|
||||
}
|
||||
// ---------- WR Menu ---------- //
|
||||
"WRDate"
|
||||
{
|
||||
"en" "Date"
|
||||
|
||||
@ -24,16 +24,42 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You have to be {1}alive{2} to set your start position."
|
||||
}
|
||||
"SetStartNotInStartZone"
|
||||
{
|
||||
"#format" "{1:s},{2:s},{3:s},{4:s}"
|
||||
"en" "You {1}must{2} be in the {3}start zone{4} to use set start."
|
||||
}
|
||||
"DeleteSetStart"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Start position has been {1}deleted{2}."
|
||||
}
|
||||
"DeleteSetStartMenuTitle"
|
||||
{
|
||||
"en" "Start position to delete"
|
||||
}
|
||||
// ---------- ZoneHook ---------- //
|
||||
"ZoneHook_Crosshair"
|
||||
{
|
||||
"en" "Entity under crosshair"
|
||||
}
|
||||
"ZoneHook_Tpto"
|
||||
{
|
||||
"en" "Teleport to (stops timer)"
|
||||
}
|
||||
"ZoneHook_Draw"
|
||||
{
|
||||
"en" "Draw beams around entity"
|
||||
}
|
||||
"ZoneHook_Zonetype"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "Zone type: {1}"
|
||||
}
|
||||
"ZoneHook_Hooktype"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Hook type: {1} ({2})"
|
||||
}
|
||||
"ZoneHook_Confirm"
|
||||
{
|
||||
"en" "Go to confirm"
|
||||
}
|
||||
// ---------- Commands ---------- //
|
||||
"StageCommandAlive"
|
||||
{
|
||||
@ -57,6 +83,11 @@
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You {1}cannot{2} setup mapzones when you're dead."
|
||||
}
|
||||
"ZonesNotSQL"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "You {1}cannot{2} add/edit/delete non-sql zones."
|
||||
}
|
||||
"ZoneCustomSpawnMenuTitle"
|
||||
{
|
||||
"en" "Add custom spawn for track:"
|
||||
@ -122,7 +153,7 @@
|
||||
}
|
||||
"ZoneAxis"
|
||||
{
|
||||
"en" "axis"
|
||||
"en" "Change Axis"
|
||||
}
|
||||
"ZoneCustomSpawnSuccess"
|
||||
{
|
||||
@ -229,11 +260,26 @@
|
||||
"#format" "{1:d}"
|
||||
"en" "Custom speed limit: {1} (No Limit)"
|
||||
}
|
||||
"ZoneSetSpeedLimitDefault"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "Custom speed limit: {1} (Default Speedcap)"
|
||||
}
|
||||
"ZoneSetStage"
|
||||
{
|
||||
"#format" "{1:d}"
|
||||
"en" "Stage: {1}"
|
||||
}
|
||||
"ZoneSetGravity"
|
||||
{
|
||||
"#format" "{1:f}"
|
||||
"en" "Gravity scale: {1}"
|
||||
}
|
||||
"ZoneSetSpeedmod"
|
||||
{
|
||||
"#format" "{1:f}"
|
||||
"en" "Speedmod: {1}"
|
||||
}
|
||||
"ZoneEnterDataChat"
|
||||
{
|
||||
"en" "Input your desired data in chat."
|
||||
@ -281,6 +327,15 @@
|
||||
{
|
||||
"en" "Edit a map zone"
|
||||
}
|
||||
"HookZone"
|
||||
{
|
||||
"en" "Hook a trigger, teleporter, or button."
|
||||
}
|
||||
"HookZone2"
|
||||
{
|
||||
"#format" "{1:s}"
|
||||
"en" "Hook {1}"
|
||||
}
|
||||
"ZoneEditTitle"
|
||||
{
|
||||
"en" "Choose a zone to edit:"
|
||||
@ -293,6 +348,103 @@
|
||||
{
|
||||
"en" "Refresh menu"
|
||||
}
|
||||
"TpToZone"
|
||||
{
|
||||
"en" "Teleport to a zone"
|
||||
}
|
||||
// ---------- Custom Zone ---------- //
|
||||
"CustomZone_MainMenuTitle"
|
||||
{
|
||||
"en" "Select the zone you want to customize"
|
||||
}
|
||||
"CustomZone_SubMenuTitle"
|
||||
{
|
||||
"#format" "{1:s},{2:s}"
|
||||
"en" "Customizing {1} - {2}"
|
||||
}
|
||||
"CustomZone_DisplayType"
|
||||
{
|
||||
"en" "Zone display type"
|
||||
}
|
||||
"CustomZone_Color"
|
||||
{
|
||||
"en" "Zone color"
|
||||
}
|
||||
"CustomZone_Width"
|
||||
{
|
||||
"en" "Zone width"
|
||||
}
|
||||
"CustomZone_Default"
|
||||
{
|
||||
"en" "Default"
|
||||
}
|
||||
|
||||
"CustomZone_DisplayType_None"
|
||||
{
|
||||
"en" "None"
|
||||
}
|
||||
"CustomZone_DisplayType_Box"
|
||||
{
|
||||
"en" "Box"
|
||||
}
|
||||
"CustomZone_DisplayType_Flat"
|
||||
{
|
||||
"en" "Flat"
|
||||
}
|
||||
|
||||
"CustomZone_Color_White"
|
||||
{
|
||||
"en" "White"
|
||||
}
|
||||
"CustomZone_Color_Red"
|
||||
{
|
||||
"en" "Red"
|
||||
}
|
||||
"CustomZone_Color_Orange"
|
||||
{
|
||||
"en" "Orange"
|
||||
}
|
||||
"CustomZone_Color_Yellow"
|
||||
{
|
||||
"en" "Yellow"
|
||||
}
|
||||
"CustomZone_Color_Green"
|
||||
{
|
||||
"en" "Green"
|
||||
}
|
||||
"CustomZone_Color_Cyan"
|
||||
{
|
||||
"en" "Cyan"
|
||||
}
|
||||
"CustomZone_Color_Blue"
|
||||
{
|
||||
"en" "Blue"
|
||||
}
|
||||
"CustomZone_Color_Purple"
|
||||
{
|
||||
"en" "Purple"
|
||||
}
|
||||
"CustomZone_Color_Pink"
|
||||
{
|
||||
"en" "Pink"
|
||||
}
|
||||
|
||||
"CustomZone_Width_UltraThin"
|
||||
{
|
||||
"en" "Ultra thin"
|
||||
}
|
||||
"CustomZone_Width_Thin"
|
||||
{
|
||||
"en" "Thin"
|
||||
}
|
||||
"CustomZone_Width_Normal"
|
||||
{
|
||||
"en" "Normal"
|
||||
}
|
||||
"CustomZone_Width_Thick"
|
||||
{
|
||||
"en" "Thick"
|
||||
}
|
||||
// ---------- Messages ---------- //
|
||||
"ZoneSlayEnter"
|
||||
{
|
||||
@ -307,6 +459,82 @@
|
||||
"ZoneStageEnter"
|
||||
{
|
||||
"#format" "{1:s},{2:s},{3:d},{4:s},{5:s},{6:s}{7:s}"
|
||||
"en" "{1}You have reached stage {2}{3}{4} with a time of {5}{6}{7}."
|
||||
"en" "{1}Stage {2}{3}{4} @ {5}{6}{7} "
|
||||
}
|
||||
}
|
||||
"Zone_Start"
|
||||
{
|
||||
"en" "Start zone"
|
||||
}
|
||||
"Zone_End"
|
||||
{
|
||||
"en" "End zone"
|
||||
}
|
||||
"Zone_Respawn"
|
||||
{
|
||||
"en" "Glitch Zone (Respawn Player)"
|
||||
}
|
||||
"Zone_Stop"
|
||||
{
|
||||
"en" "Glitch Zone (Stop Timer)"
|
||||
}
|
||||
"Zone_Slay"
|
||||
{
|
||||
"en" "Slay Player"
|
||||
}
|
||||
"Zone_Freestyle"
|
||||
{
|
||||
"en" "Freestyle Zone"
|
||||
}
|
||||
"Zone_CustomSpeedLimit"
|
||||
{
|
||||
"en" "Custom Speed Limit"
|
||||
}
|
||||
"Zone_Teleport"
|
||||
{
|
||||
"en" "Teleport Zone"
|
||||
}
|
||||
"Zone_CustomSpawn"
|
||||
{
|
||||
"en" "SPAWN POINT"
|
||||
}
|
||||
"Zone_Easybhop"
|
||||
{
|
||||
"en" "Easybhop Zone"
|
||||
}
|
||||
"Zone_Slide"
|
||||
{
|
||||
"en" "Slide Zone"
|
||||
}
|
||||
"Zone_Airaccelerate"
|
||||
{
|
||||
"en" "Custom Airaccelerate"
|
||||
}
|
||||
"Zone_Stage"
|
||||
{
|
||||
"en" "Stage Zone"
|
||||
}
|
||||
"Zone_NoTimerGravity"
|
||||
{
|
||||
"en" "No Timer Gravity Zone"
|
||||
}
|
||||
"Zone_Gravity"
|
||||
{
|
||||
"en" "Gravity Zone"
|
||||
}
|
||||
"Zone_Speedmod"
|
||||
{
|
||||
"en" "Speedmod Zone"
|
||||
}
|
||||
"Zone_NoJump"
|
||||
{
|
||||
"en" "No Jump Zone"
|
||||
}
|
||||
"Zone_Autobhop"
|
||||
{
|
||||
"en" "Autobhop Zone"
|
||||
}
|
||||
"Zone_Unknown"
|
||||
{
|
||||
"en" "UNKNOWN ZONE"
|
||||
}
|
||||
}
|
||||
|
||||
5
addons/stripper/maps/bhop_blueblocks.cfg
Normal file
5
addons/stripper/maps/bhop_blueblocks.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
;; removes empty classname entity that crashes servers
|
||||
filter:
|
||||
{
|
||||
"hammerid" "396"
|
||||
}
|
||||
8
addons/stripper/maps/bhop_classicpillars.cfg
Normal file
8
addons/stripper/maps/bhop_classicpillars.cfg
Normal file
@ -0,0 +1,8 @@
|
||||
remove:
|
||||
{
|
||||
"targetname" "mod_zone_start"
|
||||
}
|
||||
remove:
|
||||
{
|
||||
"targetname" "mod_zone_end"
|
||||
}
|
||||
21
addons/stripper/maps/bhop_connectivity_fix.cfg
Normal file
21
addons/stripper/maps/bhop_connectivity_fix.cfg
Normal file
@ -0,0 +1,21 @@
|
||||
;; empty classname entities
|
||||
filter:
|
||||
{
|
||||
"model" "*57"
|
||||
"hammerid" "197699"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"model" "*58"
|
||||
"hammerid" "197718"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"model" "*59"
|
||||
"hammerid" "197727"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"model" "*60"
|
||||
"hammerid" "197743"
|
||||
}
|
||||
21
addons/stripper/maps/bhop_continuity.cfg
Normal file
21
addons/stripper/maps/bhop_continuity.cfg
Normal file
@ -0,0 +1,21 @@
|
||||
; empty classnames crash server
|
||||
filter:
|
||||
{
|
||||
"model" "*57"
|
||||
"hammerid" "197699"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"model" "*58"
|
||||
"hammerid" "197718"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"model" "*59"
|
||||
"hammerid" "197727"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"model" "*60"
|
||||
"hammerid" "197743"
|
||||
}
|
||||
6
addons/stripper/maps/bhop_cys_nonstop.cfg
Normal file
6
addons/stripper/maps/bhop_cys_nonstop.cfg
Normal file
@ -0,0 +1,6 @@
|
||||
;; empty entity classname
|
||||
filter:
|
||||
{
|
||||
"origin" "1708.02 696.406 64"
|
||||
"hammerid" "716"
|
||||
}
|
||||
9
addons/stripper/maps/bhop_desert_smoke.cfg
Normal file
9
addons/stripper/maps/bhop_desert_smoke.cfg
Normal file
@ -0,0 +1,9 @@
|
||||
;; shitty small zones that are shit
|
||||
filter:
|
||||
{
|
||||
"targetname" "mod_zone_start"
|
||||
}
|
||||
filter:
|
||||
{
|
||||
"targetname" "mod_zone_end"
|
||||
}
|
||||
25
addons/stripper/maps/bhop_dron.cfg
Normal file
25
addons/stripper/maps/bhop_dron.cfg
Normal file
@ -0,0 +1,25 @@
|
||||
;; fix missing empty classnames
|
||||
modify:
|
||||
{
|
||||
match:
|
||||
{
|
||||
"origin" "3019.49 1646.03 1.73"
|
||||
"hammerid" "9981"
|
||||
}
|
||||
replace:
|
||||
{
|
||||
"classname" "trigger_teleport"
|
||||
}
|
||||
}
|
||||
modify:
|
||||
{
|
||||
match:
|
||||
{
|
||||
"origin" "3019.49 1646.03 3.24"
|
||||
"hammerid" "9984"
|
||||
}
|
||||
replace:
|
||||
{
|
||||
"classname" "trigger_multiple"
|
||||
}
|
||||
}
|
||||
5
addons/stripper/maps/bhop_n0bs1_css.cfg
Normal file
5
addons/stripper/maps/bhop_n0bs1_css.cfg
Normal file
@ -0,0 +1,5 @@
|
||||
;; shit zone
|
||||
filter:
|
||||
{
|
||||
"targetname" "mod_zone_start"
|
||||
}
|
||||
6
addons/stripper/maps/bhop_narkozzz.cfg
Normal file
6
addons/stripper/maps/bhop_narkozzz.cfg
Normal file
@ -0,0 +1,6 @@
|
||||
;; empty entity classname
|
||||
filter:
|
||||
{
|
||||
"model" "*18"
|
||||
"hammerid" "5005"
|
||||
}
|
||||
6
addons/stripper/maps/bhop_splrez.cfg
Normal file
6
addons/stripper/maps/bhop_splrez.cfg
Normal file
@ -0,0 +1,6 @@
|
||||
;; empty entity classname
|
||||
filter:
|
||||
{
|
||||
"model" "*215"
|
||||
"hammerid" "79725"
|
||||
}
|
||||
12
addons/stripper/maps/workshop/1195609162/bhop_bless.cfg
Normal file
12
addons/stripper/maps/workshop/1195609162/bhop_bless.cfg
Normal file
@ -0,0 +1,12 @@
|
||||
modify:
|
||||
{
|
||||
match:
|
||||
{
|
||||
"targetname" "filter_activator"
|
||||
"classname" "filter_activator_name"
|
||||
}
|
||||
insert:
|
||||
{
|
||||
"filtername" "activator"
|
||||
}
|
||||
}
|
||||
12
addons/stripper/maps/workshop/2117675766/bhop_craton.cfg
Normal file
12
addons/stripper/maps/workshop/2117675766/bhop_craton.cfg
Normal file
@ -0,0 +1,12 @@
|
||||
modify:
|
||||
{
|
||||
match:
|
||||
{
|
||||
"targetname" "filter_activator"
|
||||
"classname" "filter_activator_name"
|
||||
}
|
||||
insert:
|
||||
{
|
||||
"filtername" "bhop"
|
||||
}
|
||||
}
|
||||
12
addons/stripper/maps/workshop/859067603/bhop_bless.cfg
Normal file
12
addons/stripper/maps/workshop/859067603/bhop_bless.cfg
Normal file
@ -0,0 +1,12 @@
|
||||
modify:
|
||||
{
|
||||
match:
|
||||
{
|
||||
"targetname" "filter_activator"
|
||||
"classname" "filter_activator_name"
|
||||
}
|
||||
insert:
|
||||
{
|
||||
"filtername" "activator"
|
||||
}
|
||||
}
|
||||
7
smbuild
7
smbuild
@ -1,17 +1,20 @@
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-chat.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-core.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-hud.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-mapchooser.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-misc.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-rankings.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-replay.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-replay-playback.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-replay-recorder.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-sounds.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-stats.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-tas.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-timelimit.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-wr.sp')
|
||||
Plugin(source='addons/sourcemod/scripting/shavit-zones.sp')
|
||||
|
||||
Package(name='bhoptimer',
|
||||
plugins=['shavit-chat', 'shavit-core', 'shavit-hud', 'shavit-misc', 'shavit-rankings', 'shavit-replay', 'shavit-sounds', 'shavit-stats', 'shavit-timelimit', 'shavit-wr', 'shavit-zones'],
|
||||
plugins=['shavit-chat', 'shavit-core', 'shavit-hud', 'shavit-misc', 'shavit-mapchooser', 'shavit-rankings', 'shavit-replay-playback', 'shavit-replay-recorder', 'shavit-sounds', 'shavit-stats', 'shavit-tas', 'shavit-timelimit', 'shavit-wr', 'shavit-zones'],
|
||||
filegroups={
|
||||
'.': ['README.md', 'LICENSE'],
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user