add: implemented #122.
fix: bots try to defuse already beeing defused bomb (fixes #116). fix: line ending in source code. fix: do not retreat with sniper weapon, if currently shooting and have ammo. crlib: added deque class.
This commit is contained in:
parent
420ab6f6d3
commit
fa47e418b2
19 changed files with 420 additions and 73 deletions
|
|
@ -413,4 +413,3 @@ public:
|
||||||
template <typename T> using SmallArray = Array <T, ReservePolicy::Single, 64>;
|
template <typename T> using SmallArray = Array <T, ReservePolicy::Single, 64>;
|
||||||
|
|
||||||
CR_NAMESPACE_END
|
CR_NAMESPACE_END
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,4 +156,4 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
CR_NAMESPACE_END
|
CR_NAMESPACE_END
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#include <crlib/cr-basic.h>
|
#include <crlib/cr-basic.h>
|
||||||
#include <crlib/cr-alloc.h>
|
#include <crlib/cr-alloc.h>
|
||||||
#include <crlib/cr-array.h>
|
#include <crlib/cr-array.h>
|
||||||
|
#include <crlib/cr-deque.h>
|
||||||
#include <crlib/cr-binheap.h>
|
#include <crlib/cr-binheap.h>
|
||||||
#include <crlib/cr-files.h>
|
#include <crlib/cr-files.h>
|
||||||
#include <crlib/cr-lambda.h>
|
#include <crlib/cr-lambda.h>
|
||||||
|
|
|
||||||
232
ext/crlib/cr-deque.h
Normal file
232
ext/crlib/cr-deque.h
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
//
|
||||||
|
// CRLib - Simple library for STL replacement in private projects.
|
||||||
|
// Copyright © 2020 YaPB Development Team <team@yapb.ru>.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-alloc.h>
|
||||||
|
#include <crlib/cr-uniqueptr.h>
|
||||||
|
#include <crlib/cr-twin.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
template <typename T> class Deque : private DenyCopying {
|
||||||
|
private:
|
||||||
|
size_t capacity_ {};
|
||||||
|
|
||||||
|
UniquePtr <T[]> contents_ {};
|
||||||
|
Twin <size_t, size_t> index_ {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t pickFrontIndex () {
|
||||||
|
if (index_.first == 0) {
|
||||||
|
if (capacity_ && index_.second != capacity_ - 1) {
|
||||||
|
return capacity_ - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (index_.first - 1 != index_.second) {
|
||||||
|
return index_.first - 1;
|
||||||
|
}
|
||||||
|
extendCapacity ();
|
||||||
|
|
||||||
|
return capacity_ - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pickRearIndex () {
|
||||||
|
if (index_.second < index_.first) {
|
||||||
|
if (index_.second + 1 != index_.first) {
|
||||||
|
return index_.second + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (index_.second + 1 < capacity_) {
|
||||||
|
return index_.second + 1;
|
||||||
|
}
|
||||||
|
if (index_.first != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extendCapacity ();
|
||||||
|
|
||||||
|
return index_.second + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void extendCapacity () {
|
||||||
|
auto capacity = capacity_ ? capacity_ * 2 : 8;
|
||||||
|
auto contents = cr::makeUnique <T[]> (sizeof (T) * capacity);
|
||||||
|
|
||||||
|
if (index_.first < index_.second) {
|
||||||
|
for (size_t i = 0; i < index_.second - index_.first; ++i) {
|
||||||
|
contents[i] = cr::move (contents_[index_.first + i]);
|
||||||
|
}
|
||||||
|
index_.second = index_.second - index_.first;
|
||||||
|
index_.first = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (size_t i = 0; i < capacity_ - index_.first; ++i) {
|
||||||
|
contents[i] = cr::move (contents_[index_.first + i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < index_.second; ++i) {
|
||||||
|
contents[capacity_ - index_.first + i] = cr::move (contents_[i]);
|
||||||
|
}
|
||||||
|
index_.second = index_.second + (capacity_ - index_.first);
|
||||||
|
index_.first = 0;
|
||||||
|
}
|
||||||
|
contents_ = cr::move (contents);
|
||||||
|
capacity_ = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy () {
|
||||||
|
auto destruct = [&] (size_t start, size_t end) {
|
||||||
|
for (size_t i = start; i < end; ++i) {
|
||||||
|
cr::alloc.destruct (&contents_[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (index_.first <= index_.second) {
|
||||||
|
destruct (index_.first, index_.second);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
destruct (index_.first, capacity_);
|
||||||
|
destruct (0, index_.second);
|
||||||
|
}
|
||||||
|
contents_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset () {
|
||||||
|
contents_ = nullptr;
|
||||||
|
capacity_ = 0;
|
||||||
|
index_ = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Deque () : contents_ (nullptr), capacity_ (0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Deque (Deque &&rhs) : contents_ (cr::move (rhs.contents_)), capacity_ (rhs.capacity_) {
|
||||||
|
index_.first (rhs.index_.first);
|
||||||
|
index_.second (rhs.index_.second);
|
||||||
|
|
||||||
|
rhs.reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Deque () {
|
||||||
|
destroy ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool empty () const {
|
||||||
|
return index_.first == index_.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> void emplaceLast (U &&object) {
|
||||||
|
auto rear = pickRearIndex ();
|
||||||
|
|
||||||
|
cr::alloc.construct (&contents_[index_.second], cr::forward <U> (object));
|
||||||
|
index_.second = rear;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> void emplaceFront (U &&object) {
|
||||||
|
index_.first = pickFrontIndex ();
|
||||||
|
|
||||||
|
cr::alloc.construct (&contents_[index_.first], cr::forward <U> (object));
|
||||||
|
}
|
||||||
|
|
||||||
|
void discardFront () {
|
||||||
|
cr::alloc.destruct (&contents_[index_.first]);
|
||||||
|
|
||||||
|
if (index_.first == capacity_ - 1) {
|
||||||
|
index_.first = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index_.first++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void discardLast () {
|
||||||
|
if (index_.second == 0) {
|
||||||
|
index_.second = capacity_ - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index_.second--;
|
||||||
|
}
|
||||||
|
cr::alloc.destruct (&contents_[index_.second]);
|
||||||
|
}
|
||||||
|
|
||||||
|
T popFront () {
|
||||||
|
auto first (front ());
|
||||||
|
discardFront ();
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
T popLast () {
|
||||||
|
auto last (back ());
|
||||||
|
discardLast ();
|
||||||
|
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
const T &front () const {
|
||||||
|
return contents_[index_.first];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &last () const {
|
||||||
|
if (index_.second == 0) {
|
||||||
|
return contents_[capacity_ - 1];
|
||||||
|
}
|
||||||
|
return contents_[index_.second - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &front () {
|
||||||
|
return contents_[index_.first];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &last () {
|
||||||
|
if (index_.second == 0) {
|
||||||
|
return contents_[capacity_ - 1];
|
||||||
|
}
|
||||||
|
return contents_[index_.second - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length () const {
|
||||||
|
if (index_.first == index_.second) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return index_.first < index_.second ? index_.second - index_.first : index_.second + (capacity_ - index_.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear () {
|
||||||
|
index_.first = 0;
|
||||||
|
index_.second = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Deque &operator = (Deque &&rhs) {
|
||||||
|
destroy ();
|
||||||
|
|
||||||
|
contents_ = cr::move (rhs.contents_);
|
||||||
|
capacity_ = rhs.capacity_;
|
||||||
|
|
||||||
|
index_.first = rhs.index_.first;
|
||||||
|
index_.second = rhs.index_.second;
|
||||||
|
|
||||||
|
rhs.reset ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
|
|
@ -186,7 +186,23 @@ public:
|
||||||
detour_ = nullptr;
|
detour_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class DetourSwitch final {
|
||||||
|
private:
|
||||||
|
Detour <T> *detour_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DetourSwitch (Detour *detour) : detour_ (detour) {
|
||||||
|
detour_->restore ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~DetourSwitch () {
|
||||||
|
detour_->detour ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void install (void *detour, const bool enable = false) {
|
void install (void *detour, const bool enable = false) {
|
||||||
if (!original_) {
|
if (!original_) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -228,11 +244,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args > decltype (auto) operator () (Args &&...args) {
|
template <typename... Args > decltype (auto) operator () (Args &&...args) {
|
||||||
restore ();
|
DetourSwitch sw (this);
|
||||||
auto res = reinterpret_cast <T *> (original_) (args...);
|
return reinterpret_cast <T *> (original_) (args...);
|
||||||
detour ();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,4 +105,4 @@ public:
|
||||||
// expose global instance
|
// expose global instance
|
||||||
CR_EXPOSE_GLOBAL_SINGLETON (SimpleLogger, logger);
|
CR_EXPOSE_GLOBAL_SINGLETON (SimpleLogger, logger);
|
||||||
|
|
||||||
CR_NAMESPACE_END
|
CR_NAMESPACE_END
|
||||||
|
|
|
||||||
|
|
@ -211,4 +211,3 @@ typedef struct entvars_s {
|
||||||
edict_t *euser3;
|
edict_t *euser3;
|
||||||
edict_t *euser4;
|
edict_t *euser4;
|
||||||
} entvars_t;
|
} entvars_t;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,11 @@ public:
|
||||||
return !m_breakables.empty ();
|
return !m_breakables.empty ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find variable value by variable name
|
||||||
|
StringRef findCvar (StringRef name) {
|
||||||
|
return engfuncs.pfnCVarGetString (name.chars ());
|
||||||
|
}
|
||||||
|
|
||||||
// helper to sending the client message
|
// helper to sending the client message
|
||||||
void sendClientMessage (bool console, edict_t *ent, const char *message);
|
void sendClientMessage (bool console, edict_t *ent, const char *message);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ public:
|
||||||
int getAliveHumansCount ();
|
int getAliveHumansCount ();
|
||||||
|
|
||||||
float getConnectTime (int botId, float original);
|
float getConnectTime (int botId, float original);
|
||||||
|
float getAverageTeamKPD (bool calcForBots);
|
||||||
|
|
||||||
void setBombPlanted (bool isPlanted);
|
void setBombPlanted (bool isPlanted);
|
||||||
void frame ();
|
void frame ();
|
||||||
|
|
@ -142,6 +143,7 @@ public:
|
||||||
void setWeaponMode (int selection);
|
void setWeaponMode (int selection);
|
||||||
void updateTeamEconomics (int team, bool setTrue = false);
|
void updateTeamEconomics (int team, bool setTrue = false);
|
||||||
void updateBotDifficulties ();
|
void updateBotDifficulties ();
|
||||||
|
void balanceBotDifficulties ();
|
||||||
void reset ();
|
void reset ();
|
||||||
void initFilters ();
|
void initFilters ();
|
||||||
void resetFilters ();
|
void resetFilters ();
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ CR_DECLARE_SCOPED_ENUM (NetMsg,
|
||||||
NVGToggle = 19,
|
NVGToggle = 19,
|
||||||
FlashBat = 20,
|
FlashBat = 20,
|
||||||
Fashlight = 21,
|
Fashlight = 21,
|
||||||
ItemStatus = 22
|
ItemStatus = 22,
|
||||||
|
ScoreInfo = 23
|
||||||
)
|
)
|
||||||
|
|
||||||
// vgui menus (since latest steam updates is obsolete, but left for old cs)
|
// vgui menus (since latest steam updates is obsolete, but left for old cs)
|
||||||
|
|
@ -124,6 +125,7 @@ private:
|
||||||
void netMsgItemStatus ();
|
void netMsgItemStatus ();
|
||||||
void netMsgNVGToggle ();
|
void netMsgNVGToggle ();
|
||||||
void netMsgFlashBat ();
|
void netMsgFlashBat ();
|
||||||
|
void netMsgScoreInfo ();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MessageDispatcher ();
|
MessageDispatcher ();
|
||||||
|
|
|
||||||
|
|
@ -760,7 +760,6 @@ private:
|
||||||
int findDefendNode (const Vector &origin);
|
int findDefendNode (const Vector &origin);
|
||||||
int findBestGoal ();
|
int findBestGoal ();
|
||||||
int findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive);
|
int findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive);
|
||||||
int getMsgQueue ();
|
|
||||||
int bestPrimaryCarried ();
|
int bestPrimaryCarried ();
|
||||||
int bestSecondaryCarried ();
|
int bestSecondaryCarried ();
|
||||||
int bestGrenadeCarried ();
|
int bestGrenadeCarried ();
|
||||||
|
|
@ -975,6 +974,8 @@ public:
|
||||||
float m_firePause; // time to pause firing
|
float m_firePause; // time to pause firing
|
||||||
float m_shootTime; // time to shoot
|
float m_shootTime; // time to shoot
|
||||||
float m_timeLastFired; // time to last firing
|
float m_timeLastFired; // time to last firing
|
||||||
|
float m_difficultyChange; // time when auto-difficulty was last applied to this bot
|
||||||
|
float m_kpdRatio; // kill per death ratio
|
||||||
|
|
||||||
int m_basePing; // base ping for bot
|
int m_basePing; // base ping for bot
|
||||||
int m_numEnemiesLeft; // number of enemies alive left on map
|
int m_numEnemiesLeft; // number of enemies alive left on map
|
||||||
|
|
@ -988,8 +989,6 @@ public:
|
||||||
int m_buyState; // current count in buying
|
int m_buyState; // current count in buying
|
||||||
int m_blindButton; // buttons bot press, when blind
|
int m_blindButton; // buttons bot press, when blind
|
||||||
int m_radioOrder; // actual command
|
int m_radioOrder; // actual command
|
||||||
int m_actMessageIndex; // current processed message
|
|
||||||
int m_pushMessageIndex; // offset for next pushed message
|
|
||||||
int m_prevGoalIndex; // holds destination goal node
|
int m_prevGoalIndex; // holds destination goal node
|
||||||
int m_chosenGoalIndex; // used for experience, same as above
|
int m_chosenGoalIndex; // used for experience, same as above
|
||||||
int m_lastDamageType; // stores last damage
|
int m_lastDamageType; // stores last damage
|
||||||
|
|
@ -1034,6 +1033,7 @@ public:
|
||||||
BurstMode m_weaponBurstMode; // bot using burst mode? (famas/glock18, but also silencer mode)
|
BurstMode m_weaponBurstMode; // bot using burst mode? (famas/glock18, but also silencer mode)
|
||||||
Personality m_personality; // bots type
|
Personality m_personality; // bots type
|
||||||
Array <BotTask> m_tasks;
|
Array <BotTask> m_tasks;
|
||||||
|
Deque <int32> m_msgQueue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Bot (edict_t *bot, int difficulty, int personality, int team, int member);
|
Bot (edict_t *bot, int difficulty, int personality, int team, int member);
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,6 @@ ConVar mp_footsteps ("mp_footsteps", nullptr, Var::GameRef);
|
||||||
|
|
||||||
ConVar sv_gravity ("sv_gravity", nullptr, Var::GameRef);
|
ConVar sv_gravity ("sv_gravity", nullptr, Var::GameRef);
|
||||||
|
|
||||||
int Bot::getMsgQueue () {
|
|
||||||
// this function get the current message from the bots message queue
|
|
||||||
|
|
||||||
int message = m_messageQueue[m_actMessageIndex++];
|
|
||||||
m_actMessageIndex &= 0x1f; // wraparound
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Bot::pushMsgQueue (int message) {
|
void Bot::pushMsgQueue (int message) {
|
||||||
// this function put a message into the bot message queue
|
// this function put a message into the bot message queue
|
||||||
|
|
||||||
|
|
@ -71,8 +62,7 @@ void Bot::pushMsgQueue (int message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_messageQueue[m_pushMessageIndex++] = message;
|
m_msgQueue.emplaceLast (message);
|
||||||
m_pushMessageIndex &= 0x1f; // wraparound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Bot::isInFOV (const Vector &destination) {
|
float Bot::isInFOV (const Vector &destination) {
|
||||||
|
|
@ -1016,11 +1006,12 @@ void Bot::checkMsgQueue () {
|
||||||
extern ConVar mp_freezetime;
|
extern ConVar mp_freezetime;
|
||||||
|
|
||||||
// no new message?
|
// no new message?
|
||||||
if (m_actMessageIndex == m_pushMessageIndex) {
|
if (m_msgQueue.empty ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// get message from stack
|
|
||||||
int state = getMsgQueue ();
|
// get message from deque
|
||||||
|
auto state = m_msgQueue.popFront ();
|
||||||
|
|
||||||
// nothing to do?
|
// nothing to do?
|
||||||
if (state == BotMsg::None || (state == BotMsg::Radio && game.is (GameFlags::FreeForAll))) {
|
if (state == BotMsg::None || (state == BotMsg::Radio && game.is (GameFlags::FreeForAll))) {
|
||||||
|
|
@ -1072,7 +1063,7 @@ void Bot::checkMsgQueue () {
|
||||||
|
|
||||||
// prevent terrorists from buying on es maps
|
// prevent terrorists from buying on es maps
|
||||||
if (game.mapIs (MapFlags::Escape) && m_team == Team::Terrorist) {
|
if (game.mapIs (MapFlags::Escape) && m_team == Team::Terrorist) {
|
||||||
m_buyState = BuyState::Done;;
|
m_buyState = BuyState::Done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent teams from buying on fun maps
|
// prevent teams from buying on fun maps
|
||||||
|
|
@ -1184,20 +1175,25 @@ bool Bot::isWeaponRestricted (int weaponIndex) {
|
||||||
bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
|
bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
|
||||||
// this function checks restriction set by AMX Mod, this function code is courtesy of KWo.
|
// this function checks restriction set by AMX Mod, this function code is courtesy of KWo.
|
||||||
|
|
||||||
|
if (!game.is (GameFlags::Metamod)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// check for weapon restrictions
|
// check for weapon restrictions
|
||||||
if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
|
if (cr::bit (weaponIndex) & (kPrimaryWeaponMask | kSecondaryWeaponMask | Weapon::Shield)) {
|
||||||
auto restrictedWeapons = engfuncs.pfnCVarGetString ("amx_restrweapons");
|
auto restrictedWeapons = game.findCvar ("amx_restrweapons");
|
||||||
|
|
||||||
if (strings.isEmpty (restrictedWeapons)) {
|
if (restrictedWeapons.empty ()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int indices[] = {4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11};
|
constexpr int indices[] = {4, 25, 20, -1, 8, -1, 12, 19, -1, 5, 6, 13, 23, 17, 18, 1, 2, 21, 9, 24, 7, 16, 10, 22, -1, 3, 15, 14, 0, 11};
|
||||||
|
|
||||||
// find the weapon index
|
// find the weapon index
|
||||||
int index = indices[weaponIndex - 1];
|
int index = indices[weaponIndex - 1];
|
||||||
|
|
||||||
// validate index range
|
// validate index range
|
||||||
if (index < 0 || index >= static_cast <int> (strlen (restrictedWeapons))) {
|
if (index < 0 || index >= static_cast <int> (restrictedWeapons.length ())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return restrictedWeapons[index] != '0';
|
return restrictedWeapons[index] != '0';
|
||||||
|
|
@ -1205,18 +1201,18 @@ bool Bot::isWeaponRestrictedAMX (int weaponIndex) {
|
||||||
|
|
||||||
// check for equipment restrictions
|
// check for equipment restrictions
|
||||||
else {
|
else {
|
||||||
auto restrictedEquipment = engfuncs.pfnCVarGetString ("amx_restrequipammo");
|
auto restrictedEquipment = game.findCvar ("amx_restrequipammo");
|
||||||
|
|
||||||
if (strings.isEmpty (restrictedEquipment)) {
|
if (restrictedEquipment.empty ()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int indices[] = {-1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 0, 1, 5};
|
constexpr int indices[] = {-1, -1, -1, 3, -1, -1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, -1, -1, -1, -1, -1, 0, 1, 5};
|
||||||
|
|
||||||
// find the weapon index
|
// find the weapon index
|
||||||
int index = indices[weaponIndex - 1];
|
int index = indices[weaponIndex - 1];
|
||||||
|
|
||||||
// validate index range
|
// validate index range
|
||||||
if (index < 0 || index >= static_cast <int> (strlen (restrictedEquipment))) {
|
if (index < 0 || index >= static_cast <int> (restrictedEquipment.length ())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return restrictedEquipment[index] != '0';
|
return restrictedEquipment[index] != '0';
|
||||||
|
|
@ -1517,7 +1513,7 @@ void Bot::buyStuff () {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon
|
case BuyState::SecondaryWeapon: // if bot has still some money, buy a better secondary weapon
|
||||||
if (isPistolMode || (isFirstRound && hasDefaultPistols) || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.int_ (2000, 3000)) || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.int_ (7500, 9000))) {
|
if (isPistolMode || (isFirstRound && hasDefaultPistols && rg.chance (50)) || (hasDefaultPistols && bots.getLastWinner () == m_team && m_moneyAmount > rg.int_ (2000, 3000)) || (hasPrimaryWeapon () && hasDefaultPistols && m_moneyAmount > rg.int_ (7500, 9000))) {
|
||||||
do {
|
do {
|
||||||
pref--;
|
pref--;
|
||||||
|
|
||||||
|
|
@ -1952,11 +1948,12 @@ void Bot::filterTasks () {
|
||||||
ratio = timeHeard * 0.1f;
|
ratio = timeHeard * 0.1f;
|
||||||
}
|
}
|
||||||
bool lowAmmo = m_ammoInClip[m_currentWeapon] < conf.findWeaponById (m_currentWeapon).maxClip * 0.18f;
|
bool lowAmmo = m_ammoInClip[m_currentWeapon] < conf.findWeaponById (m_currentWeapon).maxClip * 0.18f;
|
||||||
|
bool sniping = m_sniperStopTime <= game.time () && lowAmmo;
|
||||||
|
|
||||||
if (bots.isBombPlanted () || m_isStuck || usesKnife ()) {
|
if (bots.isBombPlanted () || m_isStuck || usesKnife ()) {
|
||||||
ratio /= 3.0f; // reduce the seek cover desire if bomb is planted
|
ratio /= 3.0f; // reduce the seek cover desire if bomb is planted
|
||||||
}
|
}
|
||||||
else if (m_isVIP || m_isReloading || (lowAmmo && usesSniper ())) {
|
else if (m_isVIP || m_isReloading || (sniping && usesSniper ())) {
|
||||||
ratio *= 3.0f; // triple the seek cover desire if bot is VIP or reloading
|
ratio *= 3.0f; // triple the seek cover desire if bot is VIP or reloading
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -3000,7 +2997,7 @@ void Bot::update () {
|
||||||
else if (m_buyingFinished && !(pev->maxspeed < 10.0f && getCurrentTaskId () != Task::PlantBomb && getCurrentTaskId () != Task::DefuseBomb) && !cv_freeze_bots.bool_ () && !graph.hasChanged ()) {
|
else if (m_buyingFinished && !(pev->maxspeed < 10.0f && getCurrentTaskId () != Task::PlantBomb && getCurrentTaskId () != Task::DefuseBomb) && !cv_freeze_bots.bool_ () && !graph.hasChanged ()) {
|
||||||
botMovement = true;
|
botMovement = true;
|
||||||
}
|
}
|
||||||
checkMsgQueue (); // check for pending messages
|
checkMsgQueue ();
|
||||||
|
|
||||||
if (botMovement) {
|
if (botMovement) {
|
||||||
logic (); // execute main code
|
logic (); // execute main code
|
||||||
|
|
@ -3147,7 +3144,7 @@ void Bot::normal_ () {
|
||||||
m_timeCamping = game.time () + rg.float_ (10.0f, 25.0f);
|
m_timeCamping = game.time () + rg.float_ (10.0f, 25.0f);
|
||||||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true);
|
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, m_timeCamping, true);
|
||||||
|
|
||||||
m_camp = m_path->origin + m_path->start.forward () * 500.0f;;
|
m_camp = m_path->origin + m_path->start.forward () * 500.0f;
|
||||||
m_aimFlags |= AimFlags::Camp;
|
m_aimFlags |= AimFlags::Camp;
|
||||||
m_campDirection = 0;
|
m_campDirection = 0;
|
||||||
|
|
||||||
|
|
@ -5796,32 +5793,34 @@ bool Bot::isBombDefusing (const Vector &bombOrigin) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool defusingInProgress = false;
|
bool defusingInProgress = false;
|
||||||
|
constexpr auto distanceToBomb = cr::square (140.0f);
|
||||||
|
|
||||||
for (const auto &client : util.getClients ()) {
|
for (const auto &client : util.getClients ()) {
|
||||||
auto bot = bots[client.ent];
|
auto bot = bots[client.ent];
|
||||||
|
auto bombDistance = (client.ent->v.origin - bombOrigin).lengthSq ();
|
||||||
|
|
||||||
if (bot == nullptr || bot == this || !bot->m_notKilled) {
|
if (bot && !bot->m_notKilled) {
|
||||||
continue; // skip invalid bots
|
if (m_team != bot->m_team || bot->getCurrentTaskId () == Task::EscapeFromBomb) {
|
||||||
}
|
continue; // skip other mess
|
||||||
|
}
|
||||||
if (m_team != bot->m_team || bot->getCurrentTaskId () == Task::EscapeFromBomb) {
|
|
||||||
continue; // skip other mess
|
// if close enough, mark as progressing
|
||||||
}
|
if (bombDistance < distanceToBomb && (bot->getCurrentTaskId () == Task::DefuseBomb || bot->m_hasProgressBar)) {
|
||||||
float bombDistance = (client.ent->v.origin - bombOrigin).lengthSq ();
|
defusingInProgress = true;
|
||||||
|
break;
|
||||||
if (bombDistance < cr::square (140.0f) && (bot->getCurrentTaskId () == Task::DefuseBomb || bot->m_hasProgressBar)) {
|
}
|
||||||
defusingInProgress = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// take in account peoples too
|
|
||||||
if (defusingInProgress || !(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.team != m_team || util.isFakeClient (client.ent)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bombDistance < cr::square (140.0f) && ((client.ent->v.button | client.ent->v.oldbuttons) & IN_USE)) {
|
// take in account peoples too
|
||||||
defusingInProgress = true;
|
if ((client.flags & ClientFlags::Used) && (client.flags & ClientFlags::Alive) && client.team == m_team) {
|
||||||
break;
|
|
||||||
|
// if close enough, mark as progressing
|
||||||
|
if (bombDistance < distanceToBomb && ((client.ent->v.button | client.ent->v.oldbuttons) & IN_USE)) {
|
||||||
|
defusingInProgress = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defusingInProgress;
|
return defusingInProgress;
|
||||||
|
|
@ -5880,4 +5879,4 @@ bool Bot::isEnemyInFrustum (edict_t *enemy) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -505,7 +505,7 @@ float Bot::getEnemyBodyOffsetCorrection (float distance) {
|
||||||
{ 6.5f, 6.5f, 4.5f }, // pistol
|
{ 6.5f, 6.5f, 4.5f }, // pistol
|
||||||
{ 9.5f, 9.0f, -5.0f }, // shotgun
|
{ 9.5f, 9.0f, -5.0f }, // shotgun
|
||||||
{ 4.5f, 3.5f, -5.0f }, // zoomrifle
|
{ 4.5f, 3.5f, -5.0f }, // zoomrifle
|
||||||
{ 5.5f, 1.0f, -4.5f }, // rifle
|
{ 4.5f, 1.0f, -4.5f }, // rifle
|
||||||
{ 5.5f, 3.5f, -4.5f }, // smg
|
{ 5.5f, 3.5f, -4.5f }, // smg
|
||||||
{ 3.5f, 3.5f, 4.5f }, // sniper
|
{ 3.5f, 3.5f, 4.5f }, // sniper
|
||||||
{ 2.5f, -2.0f, -6.0f } // heavy
|
{ 2.5f, -2.0f, -6.0f } // heavy
|
||||||
|
|
@ -1243,7 +1243,7 @@ bool Bot::usesPistol () {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::usesSubmachine () {
|
bool Bot::usesSubmachine () {
|
||||||
return m_weaponType == WeaponType::SMG;;
|
return m_weaponType == WeaponType::SMG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::usesShotgun () {
|
bool Bot::usesShotgun () {
|
||||||
|
|
|
||||||
|
|
@ -960,4 +960,3 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
|
||||||
|
|
||||||
// add linkents for android
|
// add linkents for android
|
||||||
#include "android.cpp"
|
#include "android.cpp"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,14 @@ ConVar cv_autokill_delay ("yb_autokill_delay", "0.0", "Specifies amount of time
|
||||||
ConVar cv_join_after_player ("yb_join_after_player", "0", "Specifies whether bots should join server, only when at least one human player in game.");
|
ConVar cv_join_after_player ("yb_join_after_player", "0", "Specifies whether bots should join server, only when at least one human player in game.");
|
||||||
ConVar cv_join_team ("yb_join_team", "any", "Forces all bots to join team specified here.", false);
|
ConVar cv_join_team ("yb_join_team", "any", "Forces all bots to join team specified here.", false);
|
||||||
ConVar cv_join_delay ("yb_join_delay", "5.0", "Specifies after how many seconds bots should start to join the game after the changelevel.", true, 0.0f, 30.0f);
|
ConVar cv_join_delay ("yb_join_delay", "5.0", "Specifies after how many seconds bots should start to join the game after the changelevel.", true, 0.0f, 30.0f);
|
||||||
|
|
||||||
ConVar cv_name_prefix ("yb_name_prefix", "", "All the bot names will be prefixed with string specified with this cvar.", false);
|
ConVar cv_name_prefix ("yb_name_prefix", "", "All the bot names will be prefixed with string specified with this cvar.", false);
|
||||||
|
|
||||||
ConVar cv_difficulty ("yb_difficulty", "4", "All bots difficulty level. Changing at runtime will affect already created bots.", true, 0.0f, 4.0f);
|
ConVar cv_difficulty ("yb_difficulty", "4", "All bots difficulty level. Changing at runtime will affect already created bots.", true, 0.0f, 4.0f);
|
||||||
|
|
||||||
|
ConVar cv_difficulty_min ("yb_difficulty_min", "-1", "Lower bound of random difficulty on bot creation. Only affects newly created bots. -1 means yb_difficulty only used.", true, -1.0f, 4.0f);
|
||||||
|
ConVar cv_difficulty_max ("yb_difficulty_max", "-1", "Upper bound of random difficulty on bot creation. Only affects newly created bots. -1 means yb_difficulty only used.", true, -1.0f, 4.0f);
|
||||||
|
ConVar cv_difficulty_auto ("yb_difficulty_auto", "0", "Enables each bot balances own difficulty based kd-ratio of team.", true, 0.0f, 1.0f);
|
||||||
|
|
||||||
ConVar cv_show_avatars ("yb_show_avatars", "1", "Enables or disabels displaying bot avatars in front of their names in scoreboard. Note, that is currently you can see only avatars of your steam friends.");
|
ConVar cv_show_avatars ("yb_show_avatars", "1", "Enables or disabels displaying bot avatars in front of their names in scoreboard. Note, that is currently you can see only avatars of your steam friends.");
|
||||||
ConVar cv_show_latency ("yb_show_latency", "2", "Enables latency display in scoreboard.\nAllowed values: '0', '1', '2'.\nIf '0', there is nothing displayed.\nIf '1', there is a 'BOT' is displayed.\nIf '2' fake ping is displayed.", true, 0.0f, 2.0f);
|
ConVar cv_show_latency ("yb_show_latency", "2", "Enables latency display in scoreboard.\nAllowed values: '0', '1', '2'.\nIf '0', there is nothing displayed.\nIf '1', there is a 'BOT' is displayed.\nIf '2' fake ping is displayed.", true, 0.0f, 2.0f);
|
||||||
|
|
||||||
|
|
@ -187,7 +191,6 @@ BotCreateResult BotManager::create (StringRef name, int difficulty, int personal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BotName *botName = nullptr;
|
BotName *botName = nullptr;
|
||||||
|
|
||||||
// setup name
|
// setup name
|
||||||
|
|
@ -765,6 +768,27 @@ float BotManager::getConnectTime (int botId, float original) {
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float BotManager::getAverageTeamKPD (bool calcForBots) {
|
||||||
|
Twin <float, int32> calc {};
|
||||||
|
|
||||||
|
for (const auto &client : util.getClients ()) {
|
||||||
|
if (!(client.flags & ClientFlags::Used)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto bot = bots[client.ent];
|
||||||
|
|
||||||
|
if ((calcForBots && bot) || (!calcForBots && !bot)) {
|
||||||
|
calc.first += client.ent->v.frags;
|
||||||
|
calc.second++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calc.second > 0) {
|
||||||
|
return calc.first / calc.second;
|
||||||
|
}
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
Twin <int, int> BotManager::countTeamPlayers () {
|
Twin <int, int> BotManager::countTeamPlayers () {
|
||||||
int ts = 0, cts = 0;
|
int ts = 0, cts = 0;
|
||||||
|
|
||||||
|
|
@ -839,7 +863,11 @@ void BotManager::updateTeamEconomics (int team, bool setTrue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::updateBotDifficulties () {
|
void BotManager::updateBotDifficulties () {
|
||||||
int difficulty = cv_difficulty.int_ ();
|
// if min/max difficulty is specified this should not have effect
|
||||||
|
if (cv_difficulty_min.int_ () != Difficulty::Invalid || cv_difficulty_max.int_ () != Difficulty::Invalid || cv_difficulty_auto.bool_ ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto difficulty = cv_difficulty.int_ ();
|
||||||
|
|
||||||
if (difficulty != m_lastDifficulty) {
|
if (difficulty != m_lastDifficulty) {
|
||||||
|
|
||||||
|
|
@ -851,6 +879,35 @@ void BotManager::updateBotDifficulties () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BotManager::balanceBotDifficulties () {
|
||||||
|
extern ConVar cv_whose_your_daddy;
|
||||||
|
|
||||||
|
// with nightmare difficulty, there is no balance
|
||||||
|
if (cv_whose_your_daddy.bool_ ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// difficulty chaning once per round (time)
|
||||||
|
auto updateDifficulty = [] (Bot *bot, int32 offset) {
|
||||||
|
bot->m_difficulty = cr::clamp (static_cast <Difficulty> (bot->m_difficulty + offset), Difficulty::Noob, Difficulty::Expert);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto ratioPlayer = getAverageTeamKPD (false);
|
||||||
|
auto ratioBots = getAverageTeamKPD (true);
|
||||||
|
|
||||||
|
// calculate for each the bot
|
||||||
|
for (auto &bot : m_bots) {
|
||||||
|
float score = bot->m_kpdRatio;
|
||||||
|
|
||||||
|
// if kd ratio is going to go to low, we need to try to set higher difficulty
|
||||||
|
if (score < 0.8 || (score <= 1.2 && ratioBots < ratioPlayer)) {
|
||||||
|
updateDifficulty (bot.get (), +1);
|
||||||
|
}
|
||||||
|
else if (score > 4.0f || (score >= 2.5 && ratioBots > ratioPlayer)) {
|
||||||
|
updateDifficulty (bot.get (), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BotManager::destroy () {
|
void BotManager::destroy () {
|
||||||
// this function free all bots slots (used on server shutdown)
|
// this function free all bots slots (used on server shutdown)
|
||||||
|
|
||||||
|
|
@ -922,13 +979,25 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
|
||||||
|
|
||||||
m_notKilled = false;
|
m_notKilled = false;
|
||||||
m_weaponBurstMode = BurstMode::Off;
|
m_weaponBurstMode = BurstMode::Off;
|
||||||
m_difficulty = cr::clamp (difficulty, 0, 4);
|
m_difficulty = cr::clamp (static_cast <Difficulty> (difficulty), Difficulty::Noob, Difficulty::Expert);
|
||||||
|
|
||||||
|
auto minDifficulty = cv_difficulty_min.int_ ();
|
||||||
|
auto maxDifficulty = cv_difficulty_max.int_ ();
|
||||||
|
|
||||||
|
// if we're have min/max difficulty specified, choose value from they
|
||||||
|
if (minDifficulty != Difficulty::Invalid && maxDifficulty != Difficulty::Invalid) {
|
||||||
|
if (maxDifficulty > minDifficulty) {
|
||||||
|
cr::swap (maxDifficulty, minDifficulty);
|
||||||
|
}
|
||||||
|
m_difficulty = rg.int_ (minDifficulty, maxDifficulty);
|
||||||
|
}
|
||||||
m_basePing = rg.int_ (7, 14);
|
m_basePing = rg.int_ (7, 14);
|
||||||
|
|
||||||
m_lastCommandTime = game.time () - 0.1f;
|
m_lastCommandTime = game.time () - 0.1f;
|
||||||
m_frameInterval = game.time ();
|
m_frameInterval = game.time ();
|
||||||
m_heavyTimestamp = game.time ();
|
m_heavyTimestamp = game.time ();
|
||||||
m_slowFrameTimestamp = 0.0f;
|
m_slowFrameTimestamp = 0.0f;
|
||||||
|
m_kpdRatio = 0.0f;
|
||||||
|
|
||||||
// stuff from jk_botti
|
// stuff from jk_botti
|
||||||
m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f);
|
m_playServerTime = 60.0f * rg.float_ (30.0f, 240.0f);
|
||||||
|
|
@ -968,8 +1037,7 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int member) {
|
||||||
m_nextEmotionUpdate = game.time () + 0.5f;
|
m_nextEmotionUpdate = game.time () + 0.5f;
|
||||||
|
|
||||||
// just to be sure
|
// just to be sure
|
||||||
m_actMessageIndex = 0;
|
m_msgQueue.clear ();
|
||||||
m_pushMessageIndex = 0;
|
|
||||||
|
|
||||||
// assign team and class
|
// assign team and class
|
||||||
m_wantedTeam = team;
|
m_wantedTeam = team;
|
||||||
|
|
@ -1304,9 +1372,7 @@ void Bot::newRound () {
|
||||||
for (auto &msg : m_messageQueue) {
|
for (auto &msg : m_messageQueue) {
|
||||||
msg = BotMsg::None;
|
msg = BotMsg::None;
|
||||||
}
|
}
|
||||||
|
m_msgQueue.clear ();
|
||||||
m_actMessageIndex = 0;
|
|
||||||
m_pushMessageIndex = 0;
|
|
||||||
|
|
||||||
// clear last trace
|
// clear last trace
|
||||||
for (auto i = 0; i < TraceChannel::Num; ++i) {
|
for (auto i = 0; i < TraceChannel::Num; ++i) {
|
||||||
|
|
@ -1690,6 +1756,11 @@ void BotManager::initRound () {
|
||||||
m_timeRoundStart = game.time () + mp_freezetime.float_ ();
|
m_timeRoundStart = game.time () + mp_freezetime.float_ ();
|
||||||
m_timeRoundMid = m_timeRoundStart + mp_roundtime.float_ () * 60.0f * 0.5f;
|
m_timeRoundMid = m_timeRoundStart + mp_roundtime.float_ () * 60.0f * 0.5f;
|
||||||
m_timeRoundEnd = m_timeRoundStart + mp_roundtime.float_ () * 60.0f;
|
m_timeRoundEnd = m_timeRoundStart + mp_roundtime.float_ () * 60.0f;
|
||||||
|
|
||||||
|
// update difficulty balance, if needed
|
||||||
|
if (cv_difficulty_auto.bool_ ()) {
|
||||||
|
balanceBotDifficulties ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotManager::setBombPlanted (bool isPlanted) {
|
void BotManager::setBombPlanted (bool isPlanted) {
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,26 @@ void MessageDispatcher::netMsgTeamInfo () {
|
||||||
client.team = game.is (GameFlags::FreeForAll) ? m_args[index].long_ : client.team2;
|
client.team = game.is (GameFlags::FreeForAll) ? m_args[index].long_ : client.team2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageDispatcher::netMsgScoreInfo () {
|
||||||
|
// this message gets sent when scoreboard info is update, we're use it to track k-d ratio
|
||||||
|
|
||||||
|
enum args { index = 0, score = 1, deaths = 2, class_id = 3, team_id = 4, min = 5 };
|
||||||
|
|
||||||
|
// check the minimum states
|
||||||
|
if (m_args.length () < min) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &client = util.getClient (m_args[index].long_ - 1);
|
||||||
|
|
||||||
|
// get the bot in this msg
|
||||||
|
auto bot = bots[client.ent];
|
||||||
|
|
||||||
|
// if we're have bot, set the kd ratio
|
||||||
|
if (bot != nullptr) {
|
||||||
|
bot->m_kpdRatio = bot->pev->frags / cr::max <long> (m_args[deaths].long_, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MessageDispatcher::netMsgBarTime () {
|
void MessageDispatcher::netMsgBarTime () {
|
||||||
enum args { enabled = 0, min = 1 };
|
enum args { enabled = 0, min = 1 };
|
||||||
|
|
||||||
|
|
@ -415,6 +435,7 @@ MessageDispatcher::MessageDispatcher () {
|
||||||
addWanted ("ItemStatus", NetMsg::ItemStatus, &MessageDispatcher::netMsgItemStatus);
|
addWanted ("ItemStatus", NetMsg::ItemStatus, &MessageDispatcher::netMsgItemStatus);
|
||||||
addWanted ("NVGToggle", NetMsg::NVGToggle, &MessageDispatcher::netMsgNVGToggle);
|
addWanted ("NVGToggle", NetMsg::NVGToggle, &MessageDispatcher::netMsgNVGToggle);
|
||||||
addWanted ("FlashBat", NetMsg::FlashBat, &MessageDispatcher::netMsgFlashBat);
|
addWanted ("FlashBat", NetMsg::FlashBat, &MessageDispatcher::netMsgFlashBat);
|
||||||
|
addWanted ("ScoreInfo", NetMsg::ScoreInfo, &MessageDispatcher::netMsgScoreInfo);
|
||||||
|
|
||||||
// we're need next messages IDs but we're won't handle them, so they will be removed from wanted list as soon as they get engine IDs
|
// we're need next messages IDs but we're won't handle them, so they will be removed from wanted list as soon as they get engine IDs
|
||||||
addWanted ("BotVoice", NetMsg::BotVoice, nullptr);
|
addWanted ("BotVoice", NetMsg::BotVoice, nullptr);
|
||||||
|
|
|
||||||
|
|
@ -44,4 +44,4 @@ FILETYPE 0x2 {
|
||||||
BLOCK "VarFileInfo" {
|
BLOCK "VarFileInfo" {
|
||||||
VALUE "Translation", 0x400, 1200
|
VALUE "Translation", 0x400, 1200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
<ClInclude Include="..\ext\crlib\cr-binheap.h" />
|
<ClInclude Include="..\ext\crlib\cr-binheap.h" />
|
||||||
<ClInclude Include="..\ext\crlib\cr-color.h" />
|
<ClInclude Include="..\ext\crlib\cr-color.h" />
|
||||||
<ClInclude Include="..\ext\crlib\cr-complete.h" />
|
<ClInclude Include="..\ext\crlib\cr-complete.h" />
|
||||||
|
<ClInclude Include="..\ext\crlib\cr-deque.h" />
|
||||||
<ClInclude Include="..\ext\crlib\cr-hashmap.h" />
|
<ClInclude Include="..\ext\crlib\cr-hashmap.h" />
|
||||||
<ClInclude Include="..\ext\crlib\cr-files.h" />
|
<ClInclude Include="..\ext\crlib\cr-files.h" />
|
||||||
<ClInclude Include="..\ext\crlib\cr-detour.h" />
|
<ClInclude Include="..\ext\crlib\cr-detour.h" />
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,9 @@
|
||||||
<ClInclude Include="..\ext\crlib\cr-hashmap.h">
|
<ClInclude Include="..\ext\crlib\cr-hashmap.h">
|
||||||
<Filter>inc\ext\crlib</Filter>
|
<Filter>inc\ext\crlib</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\ext\crlib\cr-deque.h">
|
||||||
|
<Filter>inc\ext\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\src\android.cpp">
|
<ClCompile Include="..\src\android.cpp">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue