More fixes to optiomal node search.

Support for replying to UTF-8 chat messages.
Minor refactoring.
This commit is contained in:
jeefo 2019-08-04 18:22:01 +03:00
commit a186f33ffb
18 changed files with 488 additions and 189 deletions

View file

@ -205,7 +205,7 @@ public:
if (index + count > m_capacity) {
return false;
}
for (size_t i = index; i < index + count; i++) {
for (size_t i = index; i < index + count; ++i) {
alloc.destruct (&m_data[i]);
}
m_length -= count;
@ -233,7 +233,7 @@ public:
return false;
}
alloc.construct (&m_data[m_length], cr::forward <U> (object));
m_length++;
++m_length;
return true;
}
@ -243,7 +243,7 @@ public:
return false;
}
alloc.construct (&m_data[m_length], cr::forward <Args> (args)...);
m_length++;
++m_length;
return true;
}

View file

@ -234,7 +234,7 @@ public:
return kEOF;
}
auto ch = m_data[m_pos];
m_pos++;
++m_pos;
return static_cast <char> (ch);
}

View file

@ -236,10 +236,10 @@ private:
break;
default:
symbols++;
++symbols;
break;
}
pos++;
++pos;
}
String response (reinterpret_cast <const char *> (buffer));
size_t responseCodeStart = response.find ("HTTP/1.1");

View file

@ -69,6 +69,7 @@ CR_NAMESPACE_END
#endif
#include <assert.h>
#include <locale.h>
#if defined (CR_ANDROID)
# include <android/log.h>
@ -78,6 +79,12 @@ CR_NAMESPACE_BEGIN
// helper struct for platform detection
struct Platform : public Singleton <Platform> {
#if defined (CR_WINDOWS)
using LocaleHandle = _locale_t;
#else
using LocaleHandle = locale_t;
#endif
bool isWindows = false;
bool isLinux = false;
bool isOSX = false;
@ -193,7 +200,6 @@ struct Platform : public Singleton <Platform> {
#endif
::abort ();
}
};
// expose platform singleton

View file

@ -558,7 +558,7 @@ public:
insert (pos, to);
pos += to.length ();
replaced++;
++replaced;
}
return replaced;
}
@ -867,4 +867,235 @@ public:
// expose global string pool
static auto &strings = StringBuffer::get ();
// some limited utf8 stuff
class Utf8Tools : public Singleton <Utf8Tools> {
private:
enum : int32 {
Utf8MaxChars = 706
};
private:
// sample implementation from unicode home page: https://web.archive.org/web/19970105220809/http://www.stonehand.com/unicode/standard/fss-utf.html
struct Utf8Table {
int32 cmask, cval, shift;
long lmask, lval;
Utf8Table (int32 cmask, int32 cval, int32 shift, long lmask, long lval) :
cmask (cmask), cval (cval), shift (shift), lmask (lmask), lval (lval) {
}
};
struct Utf8CaseTable {
int32 from, to;
};
private:
Utf8CaseTable m_toUpperTable[Utf8MaxChars] = {
{ 0x0061, 0x0041 }, { 0x0062, 0x0042 }, { 0x0063, 0x0043 }, { 0x0064, 0x0044 }, { 0x0065, 0x0045 }, { 0x0066, 0x0046 }, { 0x0067, 0x0047 }, { 0x0068, 0x0048 },
{ 0x0069, 0x0049 }, { 0x006a, 0x004a }, { 0x006b, 0x004b }, { 0x006c, 0x004c }, { 0x006d, 0x004d }, { 0x006e, 0x004e }, { 0x006f, 0x004f }, { 0x0070, 0x0050 },
{ 0x0071, 0x0051 }, { 0x0072, 0x0052 }, { 0x0073, 0x0053 }, { 0x0074, 0x0054 }, { 0x0075, 0x0055 }, { 0x0076, 0x0056 }, { 0x0077, 0x0057 }, { 0x0078, 0x0058 },
{ 0x0079, 0x0059 }, { 0x007a, 0x005a }, { 0x00e0, 0x00c0 }, { 0x00e1, 0x00c1 }, { 0x00e2, 0x00c2 }, { 0x00e3, 0x00c3 }, { 0x00e4, 0x00c4 }, { 0x00e5, 0x00c5 },
{ 0x00e6, 0x00c6 }, { 0x00e7, 0x00c7 }, { 0x00e8, 0x00c8 }, { 0x00e9, 0x00c9 }, { 0x00ea, 0x00ca }, { 0x00eb, 0x00cb }, { 0x00ec, 0x00cc }, { 0x00ed, 0x00cd },
{ 0x00ee, 0x00ce }, { 0x00ef, 0x00cf }, { 0x00f0, 0x00d0 }, { 0x00f1, 0x00d1 }, { 0x00f2, 0x00d2 }, { 0x00f3, 0x00d3 }, { 0x00f4, 0x00d4 }, { 0x00f5, 0x00d5 },
{ 0x00f6, 0x00d6 }, { 0x00f8, 0x00d8 }, { 0x00f9, 0x00d9 }, { 0x00fa, 0x00da }, { 0x00fb, 0x00db }, { 0x00fc, 0x00dc }, { 0x00fd, 0x00dd }, { 0x00fe, 0x00de },
{ 0x00ff, 0x0178 }, { 0x0101, 0x0100 }, { 0x0103, 0x0102 }, { 0x0105, 0x0104 }, { 0x0107, 0x0106 }, { 0x0109, 0x0108 }, { 0x010b, 0x010a }, { 0x010d, 0x010c },
{ 0x010f, 0x010e }, { 0x0111, 0x0110 }, { 0x0113, 0x0112 }, { 0x0115, 0x0114 }, { 0x0117, 0x0116 }, { 0x0119, 0x0118 }, { 0x011b, 0x011a }, { 0x011d, 0x011c },
{ 0x011f, 0x011e }, { 0x0121, 0x0120 }, { 0x0123, 0x0122 }, { 0x0125, 0x0124 }, { 0x0127, 0x0126 }, { 0x0129, 0x0128 }, { 0x012b, 0x012a }, { 0x012d, 0x012c },
{ 0x012f, 0x012e }, { 0x0131, 0x0049 }, { 0x0133, 0x0132 }, { 0x0135, 0x0134 }, { 0x0137, 0x0136 }, { 0x013a, 0x0139 }, { 0x013c, 0x013b }, { 0x013e, 0x013d },
{ 0x0140, 0x013f }, { 0x0142, 0x0141 }, { 0x0144, 0x0143 }, { 0x0146, 0x0145 }, { 0x0148, 0x0147 }, { 0x014b, 0x014a }, { 0x014d, 0x014c }, { 0x014f, 0x014e },
{ 0x0151, 0x0150 }, { 0x0153, 0x0152 }, { 0x0155, 0x0154 }, { 0x0157, 0x0156 }, { 0x0159, 0x0158 }, { 0x015b, 0x015a }, { 0x015d, 0x015c }, { 0x015f, 0x015e },
{ 0x0161, 0x0160 }, { 0x0163, 0x0162 }, { 0x0165, 0x0164 }, { 0x0167, 0x0166 }, { 0x0169, 0x0168 }, { 0x016b, 0x016a }, { 0x016d, 0x016c }, { 0x016f, 0x016e },
{ 0x0171, 0x0170 }, { 0x0173, 0x0172 }, { 0x0175, 0x0174 }, { 0x0177, 0x0176 }, { 0x017a, 0x0179 }, { 0x017c, 0x017b }, { 0x017e, 0x017d }, { 0x0183, 0x0182 },
{ 0x0185, 0x0184 }, { 0x0188, 0x0187 }, { 0x018c, 0x018b }, { 0x0192, 0x0191 }, { 0x0195, 0x01f6 }, { 0x0199, 0x0198 }, { 0x019e, 0x0220 }, { 0x01a1, 0x01a0 },
{ 0x01a3, 0x01a2 }, { 0x01a5, 0x01a4 }, { 0x01a8, 0x01a7 }, { 0x01ad, 0x01ac }, { 0x01b0, 0x01af }, { 0x01b4, 0x01b3 }, { 0x01b6, 0x01b5 }, { 0x01b9, 0x01b8 },
{ 0x01bd, 0x01bc }, { 0x01bf, 0x01f7 }, { 0x01c6, 0x01c4 }, { 0x01c9, 0x01c7 }, { 0x01cc, 0x01ca }, { 0x01ce, 0x01cd }, { 0x01d0, 0x01cf }, { 0x01d2, 0x01d1 },
{ 0x01d4, 0x01d3 }, { 0x01d6, 0x01d5 }, { 0x01d8, 0x01d7 }, { 0x01da, 0x01d9 }, { 0x01dc, 0x01db }, { 0x01dd, 0x018e }, { 0x01df, 0x01de }, { 0x01e1, 0x01e0 },
{ 0x01e3, 0x01e2 }, { 0x01e5, 0x01e4 }, { 0x01e7, 0x01e6 }, { 0x01e9, 0x01e8 }, { 0x01eb, 0x01ea }, { 0x01ed, 0x01ec }, { 0x01ef, 0x01ee }, { 0x01f3, 0x01f1 },
{ 0x01f5, 0x01f4 }, { 0x01f9, 0x01f8 }, { 0x01fb, 0x01fa }, { 0x01fd, 0x01fc }, { 0x01ff, 0x01fe }, { 0x0201, 0x0200 }, { 0x0203, 0x0202 }, { 0x0205, 0x0204 },
{ 0x0207, 0x0206 }, { 0x0209, 0x0208 }, { 0x020b, 0x020a }, { 0x020d, 0x020c }, { 0x020f, 0x020e }, { 0x0211, 0x0210 }, { 0x0213, 0x0212 }, { 0x0215, 0x0214 },
{ 0x0217, 0x0216 }, { 0x0219, 0x0218 }, { 0x021b, 0x021a }, { 0x021d, 0x021c }, { 0x021f, 0x021e }, { 0x0223, 0x0222 }, { 0x0225, 0x0224 }, { 0x0227, 0x0226 },
{ 0x0229, 0x0228 }, { 0x022b, 0x022a }, { 0x022d, 0x022c }, { 0x022f, 0x022e }, { 0x0231, 0x0230 }, { 0x0233, 0x0232 }, { 0x0253, 0x0181 }, { 0x0254, 0x0186 },
{ 0x0256, 0x0189 }, { 0x0257, 0x018a }, { 0x0259, 0x018f }, { 0x025b, 0x0190 }, { 0x0260, 0x0193 }, { 0x0263, 0x0194 }, { 0x0268, 0x0197 }, { 0x0269, 0x0196 },
{ 0x026f, 0x019c }, { 0x0272, 0x019d }, { 0x0275, 0x019f }, { 0x0280, 0x01a6 }, { 0x0283, 0x01a9 }, { 0x0288, 0x01ae }, { 0x028a, 0x01b1 }, { 0x028b, 0x01b2 },
{ 0x0292, 0x01b7 }, { 0x03ac, 0x0386 }, { 0x03ad, 0x0388 }, { 0x03ae, 0x0389 }, { 0x03af, 0x038a }, { 0x03b1, 0x0391 }, { 0x03b2, 0x0392 }, { 0x03b3, 0x0393 },
{ 0x03b4, 0x0394 }, { 0x03b5, 0x0395 }, { 0x03b6, 0x0396 }, { 0x03b7, 0x0397 }, { 0x03b8, 0x0398 }, { 0x03b9, 0x0345 }, { 0x03ba, 0x039a }, { 0x03bb, 0x039b },
{ 0x03bc, 0x00b5 }, { 0x03bd, 0x039d }, { 0x03be, 0x039e }, { 0x03bf, 0x039f }, { 0x03c0, 0x03a0 }, { 0x03c1, 0x03a1 }, { 0x03c3, 0x03a3 }, { 0x03c4, 0x03a4 },
{ 0x03c5, 0x03a5 }, { 0x03c6, 0x03a6 }, { 0x03c7, 0x03a7 }, { 0x03c8, 0x03a8 }, { 0x03c9, 0x03a9 }, { 0x03ca, 0x03aa }, { 0x03cb, 0x03ab }, { 0x03cc, 0x038c },
{ 0x03cd, 0x038e }, { 0x03ce, 0x038f }, { 0x03d9, 0x03d8 }, { 0x03db, 0x03da }, { 0x03dd, 0x03dc }, { 0x03df, 0x03de }, { 0x03e1, 0x03e0 }, { 0x03e3, 0x03e2 },
{ 0x03e5, 0x03e4 }, { 0x03e7, 0x03e6 }, { 0x03e9, 0x03e8 }, { 0x03eb, 0x03ea }, { 0x03ed, 0x03ec }, { 0x03ef, 0x03ee }, { 0x03f2, 0x03f9 }, { 0x03f8, 0x03f7 },
{ 0x03fb, 0x03fa }, { 0x0430, 0x0410 }, { 0x0431, 0x0411 }, { 0x0432, 0x0412 }, { 0x0433, 0x0413 }, { 0x0434, 0x0414 }, { 0x0435, 0x0415 }, { 0x0436, 0x0416 },
{ 0x0437, 0x0417 }, { 0x0438, 0x0418 }, { 0x0439, 0x0419 }, { 0x043a, 0x041a }, { 0x043b, 0x041b }, { 0x043c, 0x041c }, { 0x043d, 0x041d }, { 0x043e, 0x041e },
{ 0x043f, 0x041f }, { 0x0440, 0x0420 }, { 0x0441, 0x0421 }, { 0x0442, 0x0422 }, { 0x0443, 0x0423 }, { 0x0444, 0x0424 }, { 0x0445, 0x0425 }, { 0x0446, 0x0426 },
{ 0x0447, 0x0427 }, { 0x0448, 0x0428 }, { 0x0449, 0x0429 }, { 0x044a, 0x042a }, { 0x044b, 0x042b }, { 0x044c, 0x042c }, { 0x044d, 0x042d }, { 0x044e, 0x042e },
{ 0x044f, 0x042f }, { 0x0450, 0x0400 }, { 0x0451, 0x0401 }, { 0x0452, 0x0402 }, { 0x0453, 0x0403 }, { 0x0454, 0x0404 }, { 0x0455, 0x0405 }, { 0x0456, 0x0406 },
{ 0x0457, 0x0407 }, { 0x0458, 0x0408 }, { 0x0459, 0x0409 }, { 0x045a, 0x040a }, { 0x045b, 0x040b }, { 0x045c, 0x040c }, { 0x045d, 0x040d }, { 0x045e, 0x040e },
{ 0x045f, 0x040f }, { 0x0461, 0x0460 }, { 0x0463, 0x0462 }, { 0x0465, 0x0464 }, { 0x0467, 0x0466 }, { 0x0469, 0x0468 }, { 0x046b, 0x046a }, { 0x046d, 0x046c },
{ 0x046f, 0x046e }, { 0x0471, 0x0470 }, { 0x0473, 0x0472 }, { 0x0475, 0x0474 }, { 0x0477, 0x0476 }, { 0x0479, 0x0478 }, { 0x047b, 0x047a }, { 0x047d, 0x047c },
{ 0x047f, 0x047e }, { 0x0481, 0x0480 }, { 0x048b, 0x048a }, { 0x048d, 0x048c }, { 0x048f, 0x048e }, { 0x0491, 0x0490 }, { 0x0493, 0x0492 }, { 0x0495, 0x0494 },
{ 0x0497, 0x0496 }, { 0x0499, 0x0498 }, { 0x049b, 0x049a }, { 0x049d, 0x049c }, { 0x049f, 0x049e }, { 0x04a1, 0x04a0 }, { 0x04a3, 0x04a2 }, { 0x04a5, 0x04a4 },
{ 0x04a7, 0x04a6 }, { 0x04a9, 0x04a8 }, { 0x04ab, 0x04aa }, { 0x04ad, 0x04ac }, { 0x04af, 0x04ae }, { 0x04b1, 0x04b0 }, { 0x04b3, 0x04b2 }, { 0x04b5, 0x04b4 },
{ 0x04b7, 0x04b6 }, { 0x04b9, 0x04b8 }, { 0x04bb, 0x04ba }, { 0x04bd, 0x04bc }, { 0x04bf, 0x04be }, { 0x04c2, 0x04c1 }, { 0x04c4, 0x04c3 }, { 0x04c6, 0x04c5 },
{ 0x04c8, 0x04c7 }, { 0x04ca, 0x04c9 }, { 0x04cc, 0x04cb }, { 0x04ce, 0x04cd }, { 0x04d1, 0x04d0 }, { 0x04d3, 0x04d2 }, { 0x04d5, 0x04d4 }, { 0x04d7, 0x04d6 },
{ 0x04d9, 0x04d8 }, { 0x04db, 0x04da }, { 0x04dd, 0x04dc }, { 0x04df, 0x04de }, { 0x04e1, 0x04e0 }, { 0x04e3, 0x04e2 }, { 0x04e5, 0x04e4 }, { 0x04e7, 0x04e6 },
{ 0x04e9, 0x04e8 }, { 0x04eb, 0x04ea }, { 0x04ed, 0x04ec }, { 0x04ef, 0x04ee }, { 0x04f1, 0x04f0 }, { 0x04f3, 0x04f2 }, { 0x04f5, 0x04f4 }, { 0x04f9, 0x04f8 },
{ 0x0501, 0x0500 }, { 0x0503, 0x0502 }, { 0x0505, 0x0504 }, { 0x0507, 0x0506 }, { 0x0509, 0x0508 }, { 0x050b, 0x050a }, { 0x050d, 0x050c }, { 0x050f, 0x050e },
{ 0x0561, 0x0531 }, { 0x0562, 0x0532 }, { 0x0563, 0x0533 }, { 0x0564, 0x0534 }, { 0x0565, 0x0535 }, { 0x0566, 0x0536 }, { 0x0567, 0x0537 }, { 0x0568, 0x0538 },
{ 0x0569, 0x0539 }, { 0x056a, 0x053a }, { 0x056b, 0x053b }, { 0x056c, 0x053c }, { 0x056d, 0x053d }, { 0x056e, 0x053e }, { 0x056f, 0x053f }, { 0x0570, 0x0540 },
{ 0x0571, 0x0541 }, { 0x0572, 0x0542 }, { 0x0573, 0x0543 }, { 0x0574, 0x0544 }, { 0x0575, 0x0545 }, { 0x0576, 0x0546 }, { 0x0577, 0x0547 }, { 0x0578, 0x0548 },
{ 0x0579, 0x0549 }, { 0x057a, 0x054a }, { 0x057b, 0x054b }, { 0x057c, 0x054c }, { 0x057d, 0x054d }, { 0x057e, 0x054e }, { 0x057f, 0x054f }, { 0x0580, 0x0550 },
{ 0x0581, 0x0551 }, { 0x0582, 0x0552 }, { 0x0583, 0x0553 }, { 0x0584, 0x0554 }, { 0x0585, 0x0555 }, { 0x0586, 0x0556 }, { 0x1e01, 0x1e00 }, { 0x1e03, 0x1e02 },
{ 0x1e05, 0x1e04 }, { 0x1e07, 0x1e06 }, { 0x1e09, 0x1e08 }, { 0x1e0b, 0x1e0a }, { 0x1e0d, 0x1e0c }, { 0x1e0f, 0x1e0e }, { 0x1e11, 0x1e10 }, { 0x1e13, 0x1e12 },
{ 0x1e15, 0x1e14 }, { 0x1e17, 0x1e16 }, { 0x1e19, 0x1e18 }, { 0x1e1b, 0x1e1a }, { 0x1e1d, 0x1e1c }, { 0x1e1f, 0x1e1e }, { 0x1e21, 0x1e20 }, { 0x1e23, 0x1e22 },
{ 0x1e25, 0x1e24 }, { 0x1e27, 0x1e26 }, { 0x1e29, 0x1e28 }, { 0x1e2b, 0x1e2a }, { 0x1e2d, 0x1e2c }, { 0x1e2f, 0x1e2e }, { 0x1e31, 0x1e30 }, { 0x1e33, 0x1e32 },
{ 0x1e35, 0x1e34 }, { 0x1e37, 0x1e36 }, { 0x1e39, 0x1e38 }, { 0x1e3b, 0x1e3a }, { 0x1e3d, 0x1e3c }, { 0x1e3f, 0x1e3e }, { 0x1e41, 0x1e40 }, { 0x1e43, 0x1e42 },
{ 0x1e45, 0x1e44 }, { 0x1e47, 0x1e46 }, { 0x1e49, 0x1e48 }, { 0x1e4b, 0x1e4a }, { 0x1e4d, 0x1e4c }, { 0x1e4f, 0x1e4e }, { 0x1e51, 0x1e50 }, { 0x1e53, 0x1e52 },
{ 0x1e55, 0x1e54 }, { 0x1e57, 0x1e56 }, { 0x1e59, 0x1e58 }, { 0x1e5b, 0x1e5a }, { 0x1e5d, 0x1e5c }, { 0x1e5f, 0x1e5e }, { 0x1e61, 0x1e60 }, { 0x1e63, 0x1e62 },
{ 0x1e65, 0x1e64 }, { 0x1e67, 0x1e66 }, { 0x1e69, 0x1e68 }, { 0x1e6b, 0x1e6a }, { 0x1e6d, 0x1e6c }, { 0x1e6f, 0x1e6e }, { 0x1e71, 0x1e70 }, { 0x1e73, 0x1e72 },
{ 0x1e75, 0x1e74 }, { 0x1e77, 0x1e76 }, { 0x1e79, 0x1e78 }, { 0x1e7b, 0x1e7a }, { 0x1e7d, 0x1e7c }, { 0x1e7f, 0x1e7e }, { 0x1e81, 0x1e80 }, { 0x1e83, 0x1e82 },
{ 0x1e85, 0x1e84 }, { 0x1e87, 0x1e86 }, { 0x1e89, 0x1e88 }, { 0x1e8b, 0x1e8a }, { 0x1e8d, 0x1e8c }, { 0x1e8f, 0x1e8e }, { 0x1e91, 0x1e90 }, { 0x1e93, 0x1e92 },
{ 0x1e95, 0x1e94 }, { 0x1ea1, 0x1ea0 }, { 0x1ea3, 0x1ea2 }, { 0x1ea5, 0x1ea4 }, { 0x1ea7, 0x1ea6 }, { 0x1ea9, 0x1ea8 }, { 0x1eab, 0x1eaa }, { 0x1ead, 0x1eac },
{ 0x1eaf, 0x1eae }, { 0x1eb1, 0x1eb0 }, { 0x1eb3, 0x1eb2 }, { 0x1eb5, 0x1eb4 }, { 0x1eb7, 0x1eb6 }, { 0x1eb9, 0x1eb8 }, { 0x1ebb, 0x1eba }, { 0x1ebd, 0x1ebc },
{ 0x1ebf, 0x1ebe }, { 0x1ec1, 0x1ec0 }, { 0x1ec3, 0x1ec2 }, { 0x1ec5, 0x1ec4 }, { 0x1ec7, 0x1ec6 }, { 0x1ec9, 0x1ec8 }, { 0x1ecb, 0x1eca }, { 0x1ecd, 0x1ecc },
{ 0x1ecf, 0x1ece }, { 0x1ed1, 0x1ed0 }, { 0x1ed3, 0x1ed2 }, { 0x1ed5, 0x1ed4 }, { 0x1ed7, 0x1ed6 }, { 0x1ed9, 0x1ed8 }, { 0x1edb, 0x1eda }, { 0x1edd, 0x1edc },
{ 0x1edf, 0x1ede }, { 0x1ee1, 0x1ee0 }, { 0x1ee3, 0x1ee2 }, { 0x1ee5, 0x1ee4 }, { 0x1ee7, 0x1ee6 }, { 0x1ee9, 0x1ee8 }, { 0x1eeb, 0x1eea }, { 0x1eed, 0x1eec },
{ 0x1eef, 0x1eee }, { 0x1ef1, 0x1ef0 }, { 0x1ef3, 0x1ef2 }, { 0x1ef5, 0x1ef4 }, { 0x1ef7, 0x1ef6 }, { 0x1ef9, 0x1ef8 }, { 0x1f00, 0x1f08 }, { 0x1f01, 0x1f09 },
{ 0x1f02, 0x1f0a }, { 0x1f03, 0x1f0b }, { 0x1f04, 0x1f0c }, { 0x1f05, 0x1f0d }, { 0x1f06, 0x1f0e }, { 0x1f07, 0x1f0f }, { 0x1f10, 0x1f18 }, { 0x1f11, 0x1f19 },
{ 0x1f12, 0x1f1a }, { 0x1f13, 0x1f1b }, { 0x1f14, 0x1f1c }, { 0x1f15, 0x1f1d }, { 0x1f20, 0x1f28 }, { 0x1f21, 0x1f29 }, { 0x1f22, 0x1f2a }, { 0x1f23, 0x1f2b },
{ 0x1f24, 0x1f2c }, { 0x1f25, 0x1f2d }, { 0x1f26, 0x1f2e }, { 0x1f27, 0x1f2f }, { 0x1f30, 0x1f38 }, { 0x1f31, 0x1f39 }, { 0x1f32, 0x1f3a }, { 0x1f33, 0x1f3b },
{ 0x1f34, 0x1f3c }, { 0x1f35, 0x1f3d }, { 0x1f36, 0x1f3e }, { 0x1f37, 0x1f3f }, { 0x1f40, 0x1f48 }, { 0x1f41, 0x1f49 }, { 0x1f42, 0x1f4a }, { 0x1f43, 0x1f4b },
{ 0x1f44, 0x1f4c }, { 0x1f45, 0x1f4d }, { 0x1f51, 0x1f59 }, { 0x1f53, 0x1f5b }, { 0x1f55, 0x1f5d }, { 0x1f57, 0x1f5f }, { 0x1f60, 0x1f68 }, { 0x1f61, 0x1f69 },
{ 0x1f62, 0x1f6a }, { 0x1f63, 0x1f6b }, { 0x1f64, 0x1f6c }, { 0x1f65, 0x1f6d }, { 0x1f66, 0x1f6e }, { 0x1f67, 0x1f6f }, { 0x1f70, 0x1fba }, { 0x1f71, 0x1fbb },
{ 0x1f72, 0x1fc8 }, { 0x1f73, 0x1fc9 }, { 0x1f74, 0x1fca }, { 0x1f75, 0x1fcb }, { 0x1f76, 0x1fda }, { 0x1f77, 0x1fdb }, { 0x1f78, 0x1ff8 }, { 0x1f79, 0x1ff9 },
{ 0x1f7a, 0x1fea }, { 0x1f7b, 0x1feb }, { 0x1f7c, 0x1ffa }, { 0x1f7d, 0x1ffb }, { 0x1f80, 0x1f88 }, { 0x1f81, 0x1f89 }, { 0x1f82, 0x1f8a }, { 0x1f83, 0x1f8b },
{ 0x1f84, 0x1f8c }, { 0x1f85, 0x1f8d }, { 0x1f86, 0x1f8e }, { 0x1f87, 0x1f8f }, { 0x1f90, 0x1f98 }, { 0x1f91, 0x1f99 }, { 0x1f92, 0x1f9a }, { 0x1f93, 0x1f9b },
{ 0x1f94, 0x1f9c }, { 0x1f95, 0x1f9d }, { 0x1f96, 0x1f9e }, { 0x1f97, 0x1f9f }, { 0x1fa0, 0x1fa8 }, { 0x1fa1, 0x1fa9 }, { 0x1fa2, 0x1faa }, { 0x1fa3, 0x1fab },
{ 0x1fa4, 0x1fac }, { 0x1fa5, 0x1fad }, { 0x1fa6, 0x1fae }, { 0x1fa7, 0x1faf }, { 0x1fb0, 0x1fb8 }, { 0x1fb1, 0x1fb9 }, { 0x1fb3, 0x1fbc }, { 0x1fc3, 0x1fcc },
{ 0x1fd0, 0x1fd8 }, { 0x1fd1, 0x1fd9 }, { 0x1fe0, 0x1fe8 }, { 0x1fe1, 0x1fe9 }, { 0x1fe5, 0x1fec }, { 0x1ff3, 0x1ffc }, { 0x2170, 0x2160 }, { 0x2171, 0x2161 },
{ 0x2172, 0x2162 }, { 0x2173, 0x2163 }, { 0x2174, 0x2164 }, { 0x2175, 0x2165 }, { 0x2176, 0x2166 }, { 0x2177, 0x2167 }, { 0x2178, 0x2168 }, { 0x2179, 0x2169 },
{ 0x217a, 0x216a }, { 0x217b, 0x216b }, { 0x217c, 0x216c }, { 0x217d, 0x216d }, { 0x217e, 0x216e }, { 0x217f, 0x216f }, { 0x24d0, 0x24b6 }, { 0x24d1, 0x24b7 },
{ 0x24d2, 0x24b8 }, { 0x24d3, 0x24b9 }, { 0x24d4, 0x24ba }, { 0x24d5, 0x24bb }, { 0x24d6, 0x24bc }, { 0x24d7, 0x24bd }, { 0x24d8, 0x24be }, { 0x24d9, 0x24bf },
{ 0x24da, 0x24c0 }, { 0x24db, 0x24c1 }, { 0x24dc, 0x24c2 }, { 0x24dd, 0x24c3 }, { 0x24de, 0x24c4 }, { 0x24df, 0x24c5 }, { 0x24e0, 0x24c6 }, { 0x24e1, 0x24c7 },
{ 0x24e2, 0x24c8 }, { 0x24e3, 0x24c9 }, { 0x24e4, 0x24ca }, { 0x24e5, 0x24cb }, { 0x24e6, 0x24cc }, { 0x24e7, 0x24cd }, { 0x24e8, 0x24ce }, { 0x24e9, 0x24cf },
{ 0xff41, 0xff21 }, { 0xff42, 0xff22 }, { 0xff43, 0xff23 }, { 0xff44, 0xff24 }, { 0xff45, 0xff25 }, { 0xff46, 0xff26 }, { 0xff47, 0xff27 }, { 0xff48, 0xff28 },
{ 0xff49, 0xff29 }, { 0xff4a, 0xff2a }, { 0xff4b, 0xff2b }, { 0xff4c, 0xff2c }, { 0xff4d, 0xff2d }, { 0xff4e, 0xff2e }, { 0xff4f, 0xff2f }, { 0xff50, 0xff30 },
{ 0xff51, 0xff31 }, { 0xff52, 0xff32 }, { 0xff53, 0xff33 }, { 0xff54, 0xff34 }, { 0xff55, 0xff35 }, { 0xff56, 0xff36 }, { 0xff57, 0xff37 }, { 0xff58, 0xff38 },
{ 0xff59, 0xff39 }, { 0xff5a, 0xff3a }
};
private:
SmallArray <Utf8Table> m_utfTable;
private:
void buildTable () {
m_utfTable.emplace (0x80, 0x00, 0 * 6, 0x7f, 0); // 1 byte sequence
m_utfTable.emplace (0xe0, 0xc0, 1 * 6, 0x7ff, 0x80); // 2 byte sequence
m_utfTable.emplace (0xf0, 0xe0, 2 * 6, 0xffff, 0x800); // 3 byte sequence
m_utfTable.emplace (0xf8, 0xf0, 3 * 6, 0x1fffff, 0x10000); // 4 byte sequence
m_utfTable.emplace (0xfc, 0xf8, 4 * 6, 0x3ffffff, 0x200000); // 5 byte sequence
m_utfTable.emplace (0xfe, 0xfc, 5 * 6, 0x7fffffff, 0x4000000); // 6 byte sequence
}
int32 multiByteToWideChar (wchar_t *wide, const char *mbs) {
int32 len = 0;
auto ch = *mbs;
auto lval = static_cast <int> (ch);
for (const auto &table : m_utfTable) {
len++;
if ((ch & table.cmask) == table.cval) {
lval &= table.lmask;
if (lval < table.lval) {
return -1;
}
*wide = static_cast <wchar_t> (lval);
return len;
}
mbs++;
auto test = (*mbs ^ 0x80) & 0xff;
if (test & 0xc0) {
return -1;
}
lval = (lval << 6) | test;
}
return -1;
}
int32 wideCharToMultiByte (char *mbs, wchar_t wide) {
if (!mbs) {
return 0;
}
long lmask = wide;
int32 len = 0;
for (const auto &table : m_utfTable) {
len++;
if (lmask <= table.lmask) {
auto ch = table.shift;
*mbs = static_cast <char> (table.cval | (lmask >> ch));
while (ch > 0) {
ch -= 6;
mbs++;
*mbs = 0x80 | ((lmask >> ch) & 0x3F);
}
return len;
}
}
return -1;
}
public:
Utf8Tools () {
buildTable ();
}
~Utf8Tools () = default;
public:
wchar_t toUpper (wchar_t ch) {
int32 bottom = 0;
int32 top = Utf8MaxChars - 1;
while (bottom <= top) {
const auto mid = (bottom + top) / 2;
wchar_t cur = static_cast <wchar_t> (m_toUpperTable[mid].from);
if (ch == cur) {
return static_cast <wchar_t> (m_toUpperTable[mid].to);
}
if (ch > cur) {
bottom = mid + 1;
}
else {
top = mid - 1;
}
}
return ch;
}
String strToUpper (const String &in) {
String result (in);
auto ptr = const_cast <char *> (result.chars ());
int32 len = 0;
wchar_t wide;
while (*ptr && len < static_cast <int32> (result.length ())) {
multiByteToWideChar (&wide, ptr);
ptr += wideCharToMultiByte (ptr, toUpper (wide));
}
return result;
}
};
// expose global utf8 tools
static auto &utf8tools = Utf8Tools::get ();
CR_NAMESPACE_END

View file

@ -74,7 +74,7 @@ public:
int32 length = MinMatch;
while (length < maxMatch && in[lookup + length] == in[cur + length]) {
length++;
++length;
}
if (length > bestLength) {
@ -111,7 +111,7 @@ public:
int32 length = MinMatch;
while (length < target && in[lookup + length] == in[next + length]) {
length++;
++length;
}
if (length == target) {

View file

@ -113,22 +113,6 @@ struct RefVector {
// entity prototype
using EntityFunction = void (*) (entvars_t *);
// language hasher
struct HashLangString {
uint32 operator () (const String &key) const {
auto str = reinterpret_cast <uint8 *> (const_cast <char *> (key.chars ()));
uint32 hash = 0;
while (*str++) {
if (!isalnum (*str)) {
continue;
}
hash = ((*str << 5) + hash) + *str;
}
return hash;
}
};
// provides utility functions to not call original engine (less call-cost)
class Game final : public Singleton <Game> {
private:
@ -143,16 +127,15 @@ private:
edict_t *m_localEntity;
Array <VarPair> m_cvars;
Dictionary <String, String, HashLangString> m_language;
SharedLibrary m_gameLib;
MessageBlock m_msgBlock;
bool m_precached;
bool m_precached;
int m_gameFlags;
int m_mapFlags;
float m_slowFrame; // per second updated frame
public:
RefVector vec;
@ -206,9 +189,6 @@ public:
// sends local registration stack for engine registration
void registerCvars (bool gameVars = false);
// translates bot message into needed language
const char *translate (const char *input);
// do actual network message processing
void processMessages (void *ptr);
@ -303,16 +283,6 @@ public:
// gets the player team
int getTeam (edict_t *ent);
// adds translation pair from config
void addTranslation (const String &original, const String &translated) {
m_language.push (original, translated);
}
// clear the translation table
void clearTranslation () {
m_language.clear ();
}
// resets the message capture mechanism
void resetMessages () {
m_msgBlock.msg = NetMsg::None;
@ -367,6 +337,12 @@ public:
in.buildVectors (&vec.forward, &vec.right, &vec.up);
}
// check the engine visibility wrapper
bool checkVisibility (edict_t *ent, uint8 *set);
// get pvs/pas visibility set
uint8 *getVisibilitySet (Bot *bot, bool pvs);
// what kind of game engine / game dll / mod / tool we're running ?
bool is (const int type) const {
return !!(m_gameFlags & type);
@ -402,7 +378,7 @@ public:
// prints data to servers console
template <typename ...Args> void print (const char *fmt, Args ...args) {
engfuncs.pfnServerPrint (strncat (strings.format (translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
engfuncs.pfnServerPrint (strncat (strings.format (conf.translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
}
// prints center message to specified player
@ -411,7 +387,7 @@ public:
print (fmt, cr::forward <Args> (args)...);
return;
}
sendClientMessage (true, ent, strncat (strings.format (translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
sendClientMessage (true, ent, strncat (strings.format (conf.translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
}
// prints message to client console
@ -420,7 +396,7 @@ public:
print (fmt, cr::forward <Args> (args)...);
return;
}
sendClientMessage (false, ent, strncat (strings.format (translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
sendClientMessage (false, ent, strncat (strings.format (conf.translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
}
};
@ -523,11 +499,11 @@ public:
public:
static inline uint16 fu16 (float value, float scale) {
return cr::clamp <uint16> (static_cast <uint16> (value * cr::bit (static_cast <short> (scale))), 0, 0xffff);
return cr::clamp <uint16> (static_cast <uint16> (value * cr::bit (static_cast <short> (scale))), 0, USHRT_MAX);
}
static inline short fs16 (float value, float scale) {
return cr::clamp <short> (static_cast <short> (value * cr::bit (static_cast <short> (scale))), -32767, 32767);
return cr::clamp <short> (static_cast <short> (value * cr::bit (static_cast <short> (scale))), -SHRT_MAX, SHRT_MAX);
}
};
@ -700,4 +676,9 @@ public:
static Handle CR_STDCALL replacement (Handle module, Name function) {
return DynamicEntityLink::get ().search (module, function);
}
};
};
// expose globals
static auto &game = Game::get ();
static auto &illum = LightMeasure::get ();
static auto &ents = DynamicEntityLink::get ();

View file

@ -501,11 +501,13 @@ namespace TaskPri {
constexpr char kPodbotMagic[8] = "PODWAY!";
constexpr int32 kStorageMagic = 0x59415042;
constexpr float kInfiniteDistance = 9999999.0f;
constexpr float kGrenadeCheckTime = 2.15f;
constexpr float kSprayDistance = 260.0f;
constexpr float kDoubleSprayDistance = kSprayDistance * 2;
constexpr float kMaxChatterRepeatInteval = 99.0f;
constexpr int kInfiniteDistanceLong = static_cast <int> (kInfiniteDistance);
constexpr int kMaxNodeLinks = 8;
constexpr int kMaxPracticeDamageValue = 2040;
constexpr int kMaxPracticeGoalValue = 2040;
@ -1298,6 +1300,7 @@ private:
Array <edict_t *> m_activeGrenades; // holds currently active grenades on the map
Array <edict_t *> m_intrestingEntities; // holds currently intresting entities on the map
SmallArray <CreateQueue> m_creationTab; // bot creation tab
SmallArray <BotTask> m_filters; // task filters
@ -1360,7 +1363,7 @@ public:
void execGameEntity (entvars_t *vars);
void forEach (ForEachBot handler);
void erase (Bot *bot);
bool isTeamStacked (int team);
public:
@ -1573,8 +1576,8 @@ public:
int getFacingIndex ();
int getFarest (const Vector &origin, float maxDistance = 32.0);
int getNearest (const Vector &origin, float minDistance = 9999.0f, int flags = -1);
int getNearestNoBuckets (const Vector &origin, float minDistance = 9999.0f, int flags = -1);
int getNearest (const Vector &origin, float minDistance = kInfiniteDistance, int flags = -1);
int getNearestNoBuckets (const Vector &origin, float minDistance = kInfiniteDistance, int flags = -1);
int getEditorNeareset ();
int getDangerIndex (int team, int start, int goal);
int getDangerValue (int team, int start, int goal);
@ -1715,6 +1718,22 @@ public:
}
};
// language hasher
struct HashLangString {
uint32 operator () (const String &key) const {
auto str = reinterpret_cast <uint8 *> (const_cast <char *> (key.chars ()));
uint32 hash = 0;
while (*str++) {
if (!isalnum (*str)) {
continue;
}
hash = ((*str << 5) + hash) + *str;
}
return hash;
}
};
// mostly config stuff, and some stuff dealing with menus
class BotConfig final : public Singleton <BotConfig> {
private:
@ -1729,6 +1748,8 @@ private:
StringArray m_logos;
StringArray m_avatars;
Dictionary <String, String, HashLangString> m_language;
// default tables for personality weapon preferences, overridden by general.cfg
SmallArray <int32> m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 };
SmallArray <int32> m_rusherWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 24, 19, 22, 23, 20, 21, 10, 12, 13, 7, 8, 11, 9, 18, 17, 19, 25, 15, 16 };
@ -1784,8 +1805,12 @@ public:
// fix weapon prices (ie for elite)
void adjustWeaponPrices ();
// find weapon info by weaponi d
WeaponInfo &findWeaponById (int id);
// translates bot message into needed language
const char *translate (const char *input);
private:
bool isCommentLine (const String &line) {
const char ch = line.at (0);
@ -2176,7 +2201,7 @@ public:
void collectArgs () {
m_args.clear ();
for (int i = 0; i < engfuncs.pfnCmd_Argc (); i++) {
for (int i = 0; i < engfuncs.pfnCmd_Argc (); ++i) {
m_args.emplace (engfuncs.pfnCmd_Argv (i));
}
}
@ -2196,17 +2221,15 @@ public:
bool handleMenuCommands (edict_t *ent);
};
#include <engine.h>
// expose bot super-globals
static auto &graph = BotGraph::get ();
static auto &bots = BotManager::get ();
static auto &conf = BotConfig::get ();
static auto &util = BotUtils::get ();
static auto &ctrl = BotControl::get ();
static auto &game = Game::get ();
static auto &illum = LightMeasure::get ();
static auto &ents = DynamicEntityLink::get ();
// include game-related stuff
#include <engine.h>
// very global convars
extern ConVar yb_jasonmode;
@ -2215,6 +2238,7 @@ extern ConVar yb_ignore_enemies;
extern ConVar yb_chat;
extern ConVar yb_language;
extern ConVar yb_show_latency;
extern ConVar yb_enable_query_hook;
inline int Game::getTeam (edict_t *ent) {
if (game.isNullEntity (ent)) {

View file

@ -165,12 +165,12 @@ void Bot::checkGrenadesThrow () {
// don't throw grenades at anything that isn't on the ground!
if (!(m_lastEnemy->v.flags & FL_ONGROUND) && !m_lastEnemy->v.waterlevel && m_lastEnemyOrigin.z > pev->absmax.z) {
distance = 9999.0f;
distance = kInfiniteDistance;
}
// too high to throw?
if (m_lastEnemy->v.origin.z > pev->origin.z + 500.0f) {
distance = 9999.0f;
distance = kInfiniteDistance;
}
// enemy within a good throw distance?
@ -823,7 +823,7 @@ void Bot::getCampDirection (Vector *dest) {
if (tempIndex == kInvalidNodeIndex || enemyIndex == kInvalidNodeIndex) {
return;
}
float minDistance = 99999.0f;
float minDistance = kInfiniteDistance;
int lookAtWaypoint = kInvalidNodeIndex;
Path &path = graph[tempIndex];
@ -1288,7 +1288,7 @@ void Bot::buyStuff () {
assert (*pref < kNumWeapons);
selectedWeapon = &tab[*pref];
count++;
++count;
if (selectedWeapon->buyGroup == 1) {
continue;
@ -1474,7 +1474,7 @@ void Bot::buyStuff () {
assert (*pref < kNumWeapons);
selectedWeapon = &tab[*pref];
count++;
++count;
if (selectedWeapon->buyGroup != 1) {
continue;
@ -1609,7 +1609,7 @@ void Bot::buyStuff () {
break;
}
m_buyState++;
++m_buyState;
pushMsgQueue (BotMsg::Buy);
}
@ -1731,7 +1731,7 @@ void Bot::setConditions () {
pushChatterMessage (Chatter::SniperKilled);
}
else {
switch (numEnemiesNear (pev->origin, 99999.0f)) {
switch (numEnemiesNear (pev->origin, kInfiniteDistance)) {
case 0:
if (rg.chance (50)) {
pushChatterMessage (Chatter::NoEnemiesLeft);
@ -2198,7 +2198,7 @@ void Bot::checkRadioQueue () {
for (const auto &bot : bots) {
if (bot->m_notKilled) {
if (bot->m_targetEntity == m_radioEntity) {
numFollowers++;
++numFollowers;
}
}
}
@ -2450,7 +2450,7 @@ void Bot::checkRadioQueue () {
// if bot has no enemy
if (m_lastEnemyOrigin.empty ()) {
float nearestDistance = 99999.0f;
float nearestDistance = kInfiniteDistance;
// take nearest enemy to ordering player
for (const auto &client : util.getClients ()) {
@ -2556,7 +2556,7 @@ void Bot::checkRadioQueue () {
// check if it's a ct command
if (game.getTeam (m_radioEntity) == Team::CT && m_team == Team::CT && util.isFakeClient (m_radioEntity) && bots.getPlantedBombSearchTimestamp () < game.timebase ()) {
float minDistance = 99999.0f;
float minDistance = kInfiniteDistance;
int bombPoint = kInvalidNodeIndex;
// find nearest bomb waypoint to player
@ -2605,7 +2605,7 @@ void Bot::checkRadioQueue () {
// if bot has no enemy
if (m_lastEnemyOrigin.empty ()) {
float nearestDistance = 99999.0f;
float nearestDistance = kInfiniteDistance;
// take nearest enemy to ordering player
for (const auto &client : util.getClients ()) {
@ -2767,15 +2767,15 @@ void Bot::updateAimDir () {
void Bot::checkDarkness () {
// do not check for darkness at the start of the round
if (m_spawnTime + 5.0f > game.timebase () || !graph.exists (m_currentNodeIndex)) {
if (m_spawnTime + 5.0f > game.timebase () || !graph.exists (m_currentNodeIndex) || cr::fzero (m_path->light)) {
return;
}
// do not check every frame
if (m_checkDarkTime + 2.5f > game.timebase ()) {
if (m_checkDarkTime + 5.0f > game.timebase ()) {
return;
}
float skyColor = illum.getSkyColor ();
auto skyColor = illum.getSkyColor ();
if (mp_flashlight.bool_ () && !m_hasNVG) {
auto task = Task ();
@ -2873,7 +2873,7 @@ void Bot::fastFrame () {
}
edict_t *killer = game.entityOfIndex (m_lastVoteKick);
killer->v.frags++;
++killer->v.frags;
MDLL_ClientKill (killer);
}
@ -2898,8 +2898,8 @@ void Bot::frame () {
if (m_slowFrameTimestamp > game.timebase ()) {
return;
}
m_numFriendsLeft = numFriendsNear (pev->origin, 99999.0f);
m_numEnemiesLeft = numEnemiesNear (pev->origin, 99999.0f);
m_numFriendsLeft = numFriendsNear (pev->origin, kInfiniteDistance);
m_numEnemiesLeft = numEnemiesNear (pev->origin, kInfiniteDistance);
if (bots.isBombPlanted () && m_team == Team::CT && m_notKilled) {
const Vector &bombPosition = graph.getBombPos ();
@ -3521,7 +3521,7 @@ void Bot::camp_ () {
campPoints[numFoundPoints] = i;
distances[numFoundPoints] = distance;
numFoundPoints++;
++numFoundPoints;
}
}
}
@ -4261,7 +4261,7 @@ void Bot::escapeFromBomb_ () {
else if (!hasActiveGoal ()) {
clearSearchNodes ();
int lastSelectedGoal = kInvalidNodeIndex, minPathDistance = 99999;
int lastSelectedGoal = kInvalidNodeIndex, minPathDistance = kInfiniteDistanceLong;
float safeRadius = rg.float_ (1248.0f, 2048.0f);
for (int i = 0; i < graph.length (); ++i) {
@ -5627,7 +5627,10 @@ bool Bot::isOutOfBombTimer () {
void Bot::updateHearing () {
int hearEnemyIndex = kInvalidNodeIndex;
float minDistance = 99999.0f;
float minDistance = kInfiniteDistance;
// setup potential visibility set from engine
auto set = game.getVisibilitySet (this, false);
// loop through all enemy clients to check for hearable stuff
for (int i = 0; i < game.maxClients (); ++i) {
@ -5636,6 +5639,10 @@ void Bot::updateHearing () {
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent () || client.team == m_team || client.timeSoundLasting < game.timebase ()) {
continue;
}
if (!game.checkVisibility (client.ent, set)) {
continue;
}
float distance = (client.sound - pev->origin).length ();
if (distance > client.hearingDistance) {

View file

@ -256,12 +256,7 @@ void Bot::prepareChatMessage (const String &message) {
// chat reply
case 's':
if (m_sayTextBuffer.entityIndex != -1) {
m_chatBuffer.replace ("%s", humanizedName (m_sayTextBuffer.entityIndex));
}
else {
m_chatBuffer.replace ("%s", getHighfragPlayer ());
}
m_chatBuffer.replace ("%s", m_sayTextBuffer.entityIndex != -1 ? humanizedName (m_sayTextBuffer.entityIndex) : getHighfragPlayer ());
break;
// last bot victim
@ -284,7 +279,7 @@ void Bot::prepareChatMessage (const String &message) {
m_chatBuffer.replace ("%e", getPlayerAlive (true));
break;
};
replaceCounter++;
++replaceCounter;
}
finishPreparation ();
}
@ -292,8 +287,7 @@ void Bot::prepareChatMessage (const String &message) {
bool Bot::checkChatKeywords (String &reply) {
// this function parse chat buffer, and prepare buffer to keyword searching
String message = m_sayTextBuffer.sayText;
return util.checkKeywords (message.uppercase (), reply);
return util.checkKeywords (utf8tools.strToUpper (m_sayTextBuffer.sayText), reply);
}
bool Bot::isReplyingToChat () {

View file

@ -24,7 +24,7 @@ int Bot::numFriendsNear (const Vector &origin, float radius) {
}
if ((client.origin - origin).lengthSq () < cr::square (radius)) {
count++;
++count;
}
}
return count;
@ -39,7 +39,7 @@ int Bot::numEnemiesNear (const Vector &origin, float radius) {
}
if ((client.origin - origin).lengthSq () < cr::square (radius)) {
count++;
++count;
}
}
return count;
@ -210,6 +210,9 @@ bool Bot::lookupEnemies () {
m_visibility = 0;
m_enemyOrigin= nullvec;
// setup potential visibility set from engine
auto set = game.getVisibilitySet (this, true);
if (!game.isNullEntity (m_enemy)) {
player = m_enemy;
@ -232,7 +235,13 @@ bool Bot::lookupEnemies () {
}
player = client.ent;
if ((player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance) {
// check the engine PVS
if (!game.checkVisibility (player, set)) {
continue;
}
// extra skill player can see thru smoke... if beeing attacked
if ((player->v.button & (IN_ATTACK | IN_ATTACK2)) && m_viewDistance < m_maxViewDistance && yb_whose_your_daddy.bool_ ()) {
nearestDistance = cr::square (m_maxViewDistance);
}
@ -625,14 +634,14 @@ bool Bot::isPenetrableObstacle2 (const Vector &dest) {
game.testLine (source, dest, TraceIgnore::Everything, ent (), &tr);
while (tr.flFraction != 1.0f && numHits < 3) {
numHits++;
thikness++;
++numHits;
++thikness;
point = tr.vecEndPos + direction;
while (engfuncs.pfnPointContents (point) == CONTENTS_SOLID && thikness < 98) {
point = point + direction;
thikness++;
++thikness;
}
game.testLine (point, dest, TraceIgnore::Everything, ent (), &tr);
}
@ -720,7 +729,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
if (tab[choosen].id == id) {
break;
}
choosen++;
++choosen;
}
}
@ -884,7 +893,7 @@ void Bot::fireWeapons () {
choosenWeapon = selectIndex;
}
}
selectIndex++;
++selectIndex;
}
selectId = tab[choosenWeapon].id;
@ -914,7 +923,7 @@ void Bot::fireWeapons () {
return;
}
}
selectIndex++;
++selectIndex;
}
selectId = Weapon::Knife; // no available ammo, use knife!
}
@ -1236,8 +1245,8 @@ bool Bot::usesRifle () {
if (m_currentWeapon == tab->id) {
break;
}
tab++;
count++;
++tab;
++count;
}
if (tab->id && count > 13) {
@ -1255,8 +1264,8 @@ bool Bot::usesPistol () {
if (m_currentWeapon == tab->id) {
break;
}
tab++;
count++;
++tab;
++count;
}
if (tab->id && count < 7) {
@ -1300,7 +1309,7 @@ int Bot::bestPrimaryCarried () {
if (weapons & cr::bit (weaponTab[*pref].id)) {
weaponIndex = i;
}
pref++;
++pref;
}
return weaponIndex;
}
@ -1326,7 +1335,7 @@ int Bot::bestSecondaryCarried () {
weaponIndex = i;
break;
}
pref++;
++pref;
}
return weaponIndex;
}
@ -1357,7 +1366,7 @@ bool Bot::rateGroundWeapon (edict_t *ent) {
groundIndex = i;
break;
}
pref++;
++pref;
}
int hasWeapon = 0;
@ -1396,7 +1405,7 @@ void Bot::selectBestWeapon () {
while (tab[selectIndex].id) {
// is the bot NOT carrying this weapon?
if (!(pev->weapons & cr::bit (tab[selectIndex].id))) {
selectIndex++; // skip to next weapon
++selectIndex; // skip to next weapon
continue;
}
@ -1417,7 +1426,7 @@ void Bot::selectBestWeapon () {
if (ammoLeft) {
chosenWeaponIndex = selectIndex;
}
selectIndex++;
++selectIndex;
}
chosenWeaponIndex %= kNumWeapons + 1;
@ -1456,7 +1465,7 @@ int Bot::bestWeaponCarried () {
num = i;
}
++i;
tab++;
++tab;
}
return num;
}
@ -1580,7 +1589,7 @@ void Bot::checkReload () {
}
if (weapons == 0) {
m_reloadState++;
++m_reloadState;
if (m_reloadState > Reload::Secondary) {
m_reloadState = Reload::None;
@ -1613,7 +1622,7 @@ void Bot::checkReload () {
m_reloadState = Reload::None;
return;
}
m_reloadState++;
++m_reloadState;
if (m_reloadState > Reload::Secondary) {
m_reloadState = Reload::None;

View file

@ -1172,31 +1172,31 @@ int BotControl::menuGraphPage2 (int item) {
Path &path = graph[i];
if (path.flags & NodeFlag::TerroristOnly) {
terrPoints++;
++terrPoints;
}
if (path.flags & NodeFlag::CTOnly) {
ctPoints++;
++ctPoints;
}
if (path.flags & NodeFlag::Goal) {
goalPoints++;
++goalPoints;
}
if (path.flags & NodeFlag::Rescue) {
rescuePoints++;
++rescuePoints;
}
if (path.flags & NodeFlag::Camp) {
campPoints++;
++campPoints;
}
if (path.flags & NodeFlag::Sniper) {
sniperPoints++;
++sniperPoints;
}
if (path.flags & NodeFlag::NoHostage) {
noHostagePoints++;
++noHostagePoints;
}
}
msg ("Nodes: %d - T Points: %d\n"
@ -1620,7 +1620,7 @@ void BotControl::showMenu (int id) {
// make menus looks like we need only once
if (!s_menusParsed) {
for (auto &parsed : m_menus) {
const String &translated = game.translate (parsed.text.chars ());
const String &translated = conf.translate (parsed.text.chars ());
// translate all the things
parsed.text = translated;

View file

@ -104,7 +104,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
ent->v.renderamt = 127; // set its transparency amount
ent->v.effects |= EF_NODRAW;
m_spawnCount[Team::CT]++;
++m_spawnCount[Team::CT];
}
else if (strcmp (classname, "info_player_deathmatch") == 0) {
engfuncs.pfnSetModel (ent, ENGINE_STR ("models/player/terror/terror.mdl"));
@ -113,7 +113,7 @@ void Game::levelInitialize (edict_t *entities, int max) {
ent->v.renderamt = 127; // set its transparency amount
ent->v.effects |= EF_NODRAW;
m_spawnCount[Team::Terrorist]++;
++m_spawnCount[Team::Terrorist];
}
else if (strcmp (classname, "info_vip_start") == 0) {
@ -341,6 +341,49 @@ void Game::playSound (edict_t *ent, const char *sound) {
engfuncs.pfnEmitSound (ent, CHAN_WEAPON, sound, 1.0f, ATTN_NORM, 0, 100);
}
bool Game::checkVisibility (edict_t *ent, uint8 *set) {
if (!set) {
return true;
}
if (ent->headnode < 0) {
for (int i = 0; i < ent->num_leafs; ++i) {
auto leaf = ent->leafnums[i];
if (set[leaf >> 3] & cr::bit (leaf & 7)) {
return true;
}
}
return false;
}
for (int i = 0; i < 48; ++i) {
auto leaf = ent->leafnums[i];
if (leaf == -1) {
break;
}
if (set[leaf >> 3] & cr::bit (leaf & 7)) {
return true;
}
}
return engfuncs.pfnCheckVisibility (ent, set) > 0;
}
uint8 *Game::getVisibilitySet (Bot *bot, bool pvs) {
if (is (GameFlags::Xash3D)) {
return nullptr;
}
auto eyes = bot->getEyesPos ();
if (bot->pev->flags & FL_DUCKING) {
eyes += VEC_HULL_MIN - VEC_DUCK_HULL_MIN;
}
float org[3] { eyes.x, eyes.y, eyes.z };
return pvs ? engfuncs.pfnSetFatPVS (org) : engfuncs.pfnSetFatPAS (org);
}
void Game::sendClientMessage (bool console, edict_t *ent, const char *message) {
// helper to sending the client message
@ -498,20 +541,6 @@ void Game::registerCvars (bool gameVars) {
}
}
const char *Game::translate (const char *input) {
// this function translate input string into needed language
if (isDedicated ()) {
return input;
}
static String result;
if (m_language.find (input, result)) {
return result.chars ();
}
return input; // nothing found
}
void Game::processMessages (void *ptr) {
if (m_msgBlock.msg == NetMsg::None) {
return;
@ -993,7 +1022,7 @@ void Game::processMessages (void *ptr) {
default:
logger.error ("Network message handler error. Call to unrecognized message id (%d).\n", m_msgBlock.msg);
}
m_msgBlock.state++; // and finally update network message state
++m_msgBlock.state; // and finally update network message state
}
bool Game::loadCSBinary () {
@ -1029,16 +1058,16 @@ bool Game::loadCSBinary () {
}
return true;
};
// search the libraries inside game dlls directory
for (const auto &lib : libs) {
auto *path = strings.format ("%s/dlls/%s", modname, lib.chars ());
auto path = strings.format ("%s/dlls/%s", modname, lib.chars ());
// if we can't read file, skip it
if (!File::exists (path)) {
continue;
}
// special case, czero is always detected first, as it's has custom directory
if (strcmp (modname, "czero") == 0) {
m_gameFlags |= (GameFlags::ConditionZero | GameFlags::HasBotVoice | GameFlags::HasFakePings);
@ -1075,7 +1104,7 @@ bool Game::loadCSBinary () {
}
return true;
}
if (entity != nullptr) {
m_gameFlags |= (GameFlags::Modern | GameFlags::HasBotVoice | GameFlags::HasFakePings);
}
@ -1211,15 +1240,15 @@ void Game::slowFrame () {
}
ctrl.maintainAdminRights ();
// calculate light levels for all waypoints if needed
graph.initLightLevels ();
// update bot difficulties to newly selected from cvar
bots.updateBotDifficulties ();
// update client pings
util.calculatePings ();
// initialize light levels
graph.initLightLevels ();
// detect csdm
detectDeathmatch ();

View file

@ -51,7 +51,6 @@ int BotGraph::clearConnections (int index) {
if (bots.hasBotsOnline ()) {
bots.kickEveryone (true);
}
const int kInfiniteDistance = 99999;
struct Connection {
int index;
@ -68,7 +67,7 @@ int BotGraph::clearConnections (int index) {
void reset () {
index = kInvalidNodeIndex;
number = kInvalidNodeIndex;
distance = kInfiniteDistance;
distance = kInfiniteDistanceLong;
angles = 0.0f;
}
};
@ -86,7 +85,7 @@ int BotGraph::clearConnections (int index) {
cur.distance = link.distance;
if (cur.index == kInvalidNodeIndex) {
cur.distance = kInfiniteDistance;
cur.distance = kInfiniteDistanceLong;
}
if (cur.distance < top.distance) {
@ -117,7 +116,7 @@ int BotGraph::clearConnections (int index) {
// calculate angles related to the angle of the closeset connected node
for (auto &cur : sorted) {
if (cur.index == kInvalidNodeIndex) {
cur.distance = kInfiniteDistance;
cur.distance = kInfiniteDistanceLong;
cur.angles = 360.0f;
}
else if (exists (cur.index)) {
@ -415,7 +414,7 @@ void BotGraph::addPath (int addIndex, int pathIndex, float distance) {
}
// there wasn't any free space. try exchanging it with a long-distance path
int maxDistance = -9999;
int maxDistance = -kInfiniteDistanceLong;
int slot = kInvalidNodeIndex;
for (int i = 0; i < kMaxNodeLinks; ++i) {
@ -710,7 +709,7 @@ void BotGraph::add (int type, const Vector &pos) {
// Ladder nodes need careful connections
if (path->flags & NodeFlag::Ladder) {
float minDistance = 9999.0f;
float minDistance = kInfiniteDistance;
int destIndex = kInvalidNodeIndex;
TraceResult tr;
@ -1960,7 +1959,7 @@ void BotGraph::frame () {
m_editor->v.movetype = MOVETYPE_NOCLIP;
}
float nearestDistance = 99999.0f;
float nearestDistance = kInfiniteDistance;
int nearestIndex = kInvalidNodeIndex;
// check if it's time to add jump node
@ -2011,7 +2010,7 @@ void BotGraph::frame () {
m_facingAtIndex = getFacingIndex ();
// reset the minimal distance changed before
nearestDistance = 999999.0f;
nearestDistance = kInfiniteDistance;
// now iterate through all nodes in a map, and draw required ones
for (auto &path : m_paths) {
@ -2234,8 +2233,8 @@ void BotGraph::frame () {
// show the information about that point
graphMessage.assignf ("\n\n\n\n Graph Information:\n\n"
" Node %d of %d, Radius: %.1f\n"
" Flags: %s\n\n", nearestIndex, m_paths.length () - 1, path.radius, getFlagsAsStr (nearestIndex));
" Node %d of %d, Radius: %.1f, Light: %.1f\n"
" Flags: %s\n\n", nearestIndex, m_paths.length () - 1, path.radius, path.light, getFlagsAsStr (nearestIndex));
// if node is not changed display experience also
if (!m_hasChanged) {

View file

@ -423,7 +423,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
// keep bot number up to date
bots.maintainQuota ();
if (game.is (GameFlags::Metamod)) {
RETURN_META (MRES_IGNORED);
}
@ -435,7 +435,7 @@ CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
functionTable->pfnCmdStart = [] (const edict_t *player, usercmd_t *cmd, unsigned int random_seed) {
auto ent = const_cast <edict_t *> (player);
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false
// and SV_EmitPings will not overwrite our results
if (game.is (GameFlags::HasFakePings) && yb_show_latency.int_ () == 2) {
@ -534,10 +534,6 @@ CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, int *interfaceV
auto api_GetNewDLLFunctions = game.lib ().resolve <int (*) (newgamefuncs_t *, int *)> (__FUNCTION__);
if (api_GetNewDLLFunctions == nullptr) {
return FALSE;
}
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
return FALSE;

View file

@ -66,12 +66,12 @@ void BotManager::createKillerEntity () {
m_killerEntity = engfuncs.pfnCreateNamedEntity (MAKE_STRING ("trigger_hurt"));
m_killerEntity->v.dmg = 9999.0f;
m_killerEntity->v.dmg = kInfiniteDistance;
m_killerEntity->v.dmg_take = 1.0f;
m_killerEntity->v.dmgtime = 2.0f;
m_killerEntity->v.effects |= EF_NODRAW;
engfuncs.pfnSetOrigin (m_killerEntity, Vector (-99999.0f, -99999.0f, -99999.0f));
engfuncs.pfnSetOrigin (m_killerEntity, Vector (-kInfiniteDistance, -kInfiniteDistance, -kInfiniteDistance));
MDLL_Spawn (m_killerEntity);
}
@ -224,12 +224,13 @@ Bot *BotManager::findBotByIndex (int index) {
if (index < 0 || index >= kGameMaxPlayers) {
return nullptr;
}
for (const auto &bot : m_bots) {
if (bot->m_index == index) {
return bot.get ();
}
}
return nullptr; // no bot
return nullptr; // no bot``
}
Bot *BotManager::findBotByEntity (edict_t *ent) {
@ -501,12 +502,10 @@ void BotManager::serverFill (int selection, int personality, int difficulty, int
void BotManager::kickEveryone (bool instant, bool zeroQuota) {
// this function drops all bot clients from server (this function removes only yapb's)`q
if (!hasBotsOnline () || !yb_quota.bool_ ()) {
return;
if (yb_quota.bool_ ()) {
ctrl.msg ("Bots are removed from server.");
}
ctrl.msg ("Bots are removed from server.");
if (zeroQuota) {
decrementQuota (0);
}
@ -592,7 +591,7 @@ bool BotManager::kickRandom (bool decQuota, Team fromTeam) {
// if no dead bots found try to find one with lowest amount of frags
Bot *selected = nullptr;
float score = 9999.0f;
float score = kInfiniteDistance;
// search bots in this team
for (const auto &bot : m_bots) {
@ -702,10 +701,10 @@ Twin <int, int> BotManager::countTeamPlayers () {
for (const auto &client : util.getClients ()) {
if (client.flags & ClientFlags::Used) {
if (client.team2 == Team::Terrorist) {
ts++;
++ts;
}
else if (client.team2 == Team::CT) {
cts++;
++cts;
}
}
}
@ -748,9 +747,9 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
for (const auto &bot : m_bots) {
if (bot->m_team == team) {
if (bot->m_moneyAmount <= econLimit[EcoLimit::PrimaryGreater]) {
numPoorPlayers++;
++numPoorPlayers;
}
numTeamPlayers++; // update count of team
++numTeamPlayers; // update count of team
}
}
m_economicsGood[team] = true;
@ -920,7 +919,7 @@ int BotManager::getHumansCount (bool ignoreSpectators) {
if (ignoreSpectators && client.team2 != Team::Terrorist && client.team2 != Team::CT) {
continue;
}
count++;
++count;
}
}
return count;
@ -933,7 +932,7 @@ int BotManager::getAliveHumansCount () {
for (const auto &client : util.getClients ()) {
if ((client.flags & (ClientFlags::Used | ClientFlags::Alive)) && bots[client.ent] == nullptr && !(client.ent->v.flags & FL_FAKECLIENT)) {
count++;
++count;
}
}
return count;
@ -952,7 +951,7 @@ bool BotManager::isTeamStacked (int team) {
for (const auto &client : util.getClients ()) {
if ((client.flags & ClientFlags::Used) && client.team2 != Team::Unassigned && client.team2 != Team::Spectator) {
teamCount[client.team2]++;
++teamCount[client.team2];
}
}
return teamCount[team] + 1 > teamCount[team == Team::CT ? Team::Terrorist : Team::CT] + limitTeams;
@ -1036,7 +1035,7 @@ void Bot::newRound () {
m_askCheckTime = rg.float_ (30.0f, 90.0f);
m_minSpeed = 260.0f;
m_prevSpeed = 0.0f;
m_prevOrigin = Vector (9999.0f, 9999.0f, 9999.0f);
m_prevOrigin = Vector (kInfiniteDistance, kInfiniteDistance, kInfiniteDistance);
m_prevTime = game.timebase ();
m_lookUpdateTime = game.timebase ();
m_aimErrorTime = game.timebase ();
@ -1962,9 +1961,11 @@ void BotConfig::loadChatConfig () {
keywords.clear ();
replies.clear ();
}
keywords.clear ();
keywords = cr::move (line.substr (4).split (","));
for (const auto &key : line.substr (4).split (",")) {
keywords.emplace (utf8tools.strToUpper (key));
}
for (auto &keyword : keywords) {
keyword.trim ().trim ("\"");
@ -2007,7 +2008,7 @@ void BotConfig::loadLanguageConfig () {
Twin <String, String> lang;
// clear all the translations before new load
game.clearTranslation ();
m_language.clear ();
while (file.getLine (line)) {
if (isCommentLine (line)) {
@ -2020,7 +2021,7 @@ void BotConfig::loadLanguageConfig () {
}
if (!lang.second.empty () && !lang.first.empty ()) {
game.addTranslation (lang.first.trim (), lang.second.trim ());
m_language.push (lang.first.trim (), lang.second.trim ());
}
}
else if (line.startsWith ("[TRANSLATED]") && !temp.empty ()) {
@ -2179,3 +2180,18 @@ WeaponInfo &BotConfig::findWeaponById (const int id) {
}
return m_weapons.at (0);
}
const char *BotConfig::translate (const char *input) {
// this function translate input string into needed language
if (game.isDedicated ()) {
return input;
}
static String result;
if (m_language.find (input, result)) {
return result.chars ();
}
return input; // nothing found
}

View file

@ -168,7 +168,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
{
// force bomber to select closest goal, if round-start goal was reset by something
if (m_hasC4 && bots.getRoundStartTime () + 20.0f < game.timebase ()) {
float minDist = 9999999.0f;
float minDist = kInfiniteDistance;
int count = 0;
for (auto &point : graph.m_goalPoints) {
@ -236,7 +236,7 @@ void Bot::postprocessGoals (const IntArray &goals, int *result) {
if (index > 0) {
index--;
}
searchCount++;
++searchCount;
continue;
}
result[index] = rand;
@ -350,9 +350,6 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
m_isStuck = false;
if (doPlayerAvoidance (dirNormal) || m_avoidTime > game.timebase ()) {
return;
}
TraceResult tr;
// Standing still, no need to check?
@ -625,6 +622,11 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
}
}
}
// avoid players if not already stuck
if (!m_isStuck) {
doPlayerAvoidance (dirNormal);
}
}
bool Bot::updateNavigation () {
@ -1536,7 +1538,7 @@ bool Bot::findBestNearestNode () {
int busy = kInvalidNodeIndex;
float lessDist[3] = { 9999.0f, 9999.0f , 9999.0f };
float lessDist[3] = { kInfiniteDistance, kInfiniteDistance, kInfiniteDistance };
int lessIndex[3] = { kInvalidNodeIndex, kInvalidNodeIndex , kInvalidNodeIndex };
auto &bucket = graph.getNodesInBucket (pev->origin);
@ -1695,7 +1697,7 @@ void Bot::findValidNode () {
}
else {
findBestNearestNode ();
m_rechoiceGoalCount++;
++m_rechoiceGoalCount;
}
};
@ -1809,7 +1811,7 @@ int Bot::findBombNode () {
}
int goal = 0, count = 0;
float lastDistance = 999999.0f;
float lastDistance = kInfiniteDistance;
// find nearest goal node either to bomb (if "heard" or player)
for (auto &point : goals) {
@ -2811,7 +2813,7 @@ int Bot::findCampingDirection () {
distTab[count] = (pev->origin - path.origin).lengthSq ();
visibility[count] = path.vis.crouch + path.vis.stand;
count++;
++count;
}
else {
float distance = (pev->origin - path.origin).lengthSq ();
@ -3029,6 +3031,11 @@ bool Bot::isOccupiedPoint (int index) {
if (!(client.flags & (ClientFlags::Used | ClientFlags::Alive)) || client.team != m_team || client.ent == ent ()) {
continue;
}
// do not check clients far away from us
if ((pev->origin - client.origin).lengthSq () > cr::square (320.0f)) {
continue;
}
auto bot = bots[client.ent];
if (bot == this) {
@ -3058,7 +3065,7 @@ edict_t *Bot::lookupButton (const char *targetName) {
if (util.isEmptyStr (targetName)) {
return nullptr;
}
float nearestDistance = 99999.0f;
float nearestDistance = kInfiniteDistance;
edict_t *searchEntity = nullptr, *foundEntity = nullptr;
// find the nearest button which can open our target

View file

@ -330,7 +330,7 @@ void BotUtils::attachSoundsToClients (edict_t *ent, const char *sample, float vo
int index = game.indexOfPlayer (ent);
if (index < 0 || index >= game.maxClients ()) {
float nearestDistance = 99999.0f;
float nearestDistance = kInfiniteDistance;
// loop through all players
for (int i = 0; i < game.maxClients (); ++i) {
@ -523,7 +523,7 @@ void BotUtils::calculatePings () {
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping / 2 : rg.int_ (8, 16)); // getting player ping sometimes fails
client.pingUpdate = true; // force resend ping
numHumans++;
++numHumans;
average.first += ping;
average.second += loss;
@ -578,7 +578,7 @@ void BotUtils::sendPings (edict_t *to) {
if (!client.ping) {
client.ping = getPingBitmask (client.ent, rg.int_ (5, 10), rg.int_ (15, 40));
}
msg.start (MSG_ONE_UNRELIABLE, kGamePingSVC, nullvec, to)
.writeLong (client.ping)
.end ();
@ -635,7 +635,7 @@ int32 BotUtils::sendTo (int socket, const void *message, size_t length, int flag
buffer.skip <uint8> (); // protocol
// skip server name, folder, map game
for (size_t i = 0; i < 4; i++) {
for (size_t i = 0; i < 4; ++i) {
buffer.skipString ();
}
buffer.skip <short> (); // steam app id