diff --git a/include/corelib.h b/include/corelib.h index e121a33..f31619a 100644 --- a/include/corelib.h +++ b/include/corelib.h @@ -361,8 +361,7 @@ public: } }; -class SimpleColor final : private NonCopyable -{ +class SimpleColor final : private NonCopyable { public: int red, green, blue; diff --git a/include/engine.h b/include/engine.h index a6b9bb3..8aa6c61 100644 --- a/include/engine.h +++ b/include/engine.h @@ -54,7 +54,11 @@ enum NetMsgId { NETMSG_SENDAUDIO = 17, NETMSG_SAYTEXT = 18, NETMSG_BOTVOICE = 19, - NETMSG_NUM = 21 + NETMSG_NVGTOGGLE = 20, + NETMSG_FLASHBAT = 21, + NETMSG_FLASHLIGHT = 22, + NETMSG_ITEMSTATUS = 23, + NETMSG_NUM = 25 }; // variable reg pair @@ -418,7 +422,7 @@ public: void animateLight (void); float getLightLevel (const Vector &point); - float getSkiesColor (void); + float getSkyColor (void); private: template bool recursiveLightPoint (const M *node, const Vector &start, const Vector &end); diff --git a/include/yapb.h b/include/yapb.h index 9a80def..010b712 100644 --- a/include/yapb.h +++ b/include/yapb.h @@ -287,6 +287,7 @@ enum BuyState { BUYSTATE_GRENADES, BUYSTATE_DEFUSER, BUYSTATE_AMMO, + BUYSTATE_NIGHTVISION, BUYSTATE_FINISHED }; @@ -947,6 +948,7 @@ private: void filterGoals (const IntArray &goals, int *result); void processPickups (void); void checkTerrain (float movedDistance, const Vector &dirNormal); + void checkDarkness (void); bool doPlayerAvoidance (const Vector &normal); void getCampDir (Vector *dest); @@ -1109,20 +1111,24 @@ public: bool m_ignoreBuyDelay; // when reaching buyzone in the middle of the round don't do pauses bool m_inBombZone; // bot in the bomb zone or not - int m_buyState; // current Count in Buying + int m_buyState; // current count in buying float m_nextBuyTime; // next buy time + float m_checkDarkTime; // check for darkness time bool m_inBuyZone; // bot currently in buy zone bool m_inVIPZone; // bot in the vip satefy zone bool m_buyingFinished; // done with buying bool m_buyPending; // bot buy is pending bool m_hasDefuser; // does bot has defuser + bool m_hasNVG; // does bot has nightvision goggles + bool m_usesNVG; // does nightvision goggles turned on bool m_hasC4; // does bot has c4 bomb bool m_hasProgressBar; // has progress bar on a HUD bool m_jumpReady; // is double jump ready bool m_canChooseAimDirection; // can choose aiming direction float m_turnAwayFromFlashbang; // bot turned away from flashbang + float m_flashLevel; // flashlight level float m_blindTime; // time when bot is blinded float m_blindMoveSpeed; // mad speeds when bot is blind float m_blindSidemoveSpeed; // mad side move speeds when bot is blind diff --git a/source/basecode.cpp b/source/basecode.cpp index a97f0b9..f2c6774 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -31,8 +31,10 @@ ConVar yb_best_weapon_picker_type ("yb_best_weapon_picker_type", "1"); // game console variables ConVar mp_c4timer ("mp_c4timer", nullptr, VT_NOREGISTER); +ConVar mp_flashlight ("mp_flashlight", nullptr, VT_NOREGISTER); ConVar mp_buytime ("mp_buytime", nullptr, VT_NOREGISTER, true, "1"); ConVar mp_footsteps ("mp_footsteps", nullptr, VT_NOREGISTER); + ConVar sv_gravity ("sv_gravity", nullptr, VT_NOREGISTER); int Bot::getMsgQueue (void) { @@ -1710,6 +1712,24 @@ void Bot::buyStuff (void) { } break; + case BUYSTATE_NIGHTVISION: + if (m_moneyAmount > 2500 && !m_hasNVG && rng.getInt (1, 100) < 30) { + float skyColor = illum.getSkyColor (); + float lightLevel = waypoints.getLightLevel (m_currentWaypointIndex); + + // if it's somewhat darkm do buy nightvision goggles + if ((skyColor >= 50.0f && lightLevel <= 15.0f) || (skyColor < 50.0f && lightLevel < 40.0f)) { + if (isOldGame) { + engine.execBotCmd (ent (), "buyequip;menuselect 7"); + } + else { + engine.execBotCmd (ent (), "nvgs"); // use alias in steamcs + } + engine.print ("%s bought googles", STRING (pev->netname)); + } + } + break; + case BUYSTATE_AMMO: // buy enough primary & secondary ammo (do not check for money here) for (int i = 0; i <= 5; i++) { engine.execBotCmd (ent (), "buyammo%d", rng.getInt (1, 2)); // simulate human @@ -2828,6 +2848,46 @@ void Bot::updateAimDir (void) { } } +void Bot::checkDarkness (void) { + + // do not check for darkness at the start of the round + if (m_spawnTime + 5.0f > engine.timebase () || !waypoints.exists (m_currentWaypointIndex)) { + return; + } + + // do not check every frame + if (m_checkDarkTime + 2.5f > engine.timebase ()) { + return; + } + + float lightLevel = waypoints.getLightLevel (m_currentWaypointIndex); + float skyColor = illum.getSkyColor (); + + if (mp_flashlight.boolean () && !m_hasNVG) { + auto task = TaskID (); + + if (!(pev->effects & EF_DIMLIGHT) && task != TASK_CAMP && task != TASK_ATTACK && m_heardSoundTime + 3.0f < engine.timebase () && m_flashLevel > 30.0f && ((skyColor > 50.0f && lightLevel < 10.0f) || (skyColor <= 50.0f && lightLevel < 40.0f))) { + pev->impulse = 100; + } + else if ((pev->effects & EF_DIMLIGHT) && (((lightLevel > 15.0f && skyColor > 50.0f) || (lightLevel > 45.0f && skyColor <= 50.0f)) || task == TASK_CAMP || task == TASK_ATTACK || m_flashLevel <= 0 || m_heardSoundTime + 3.0f >= engine.timebase ())) + { + pev->impulse = 100; + } + } + else if (m_hasNVG) { + if (pev->effects & EF_DIMLIGHT) { + pev->impulse = 100; + } + else if (!m_usesNVG && ((skyColor > 50.0f && lightLevel < 15.0f) || (skyColor <= 50.0f && lightLevel < 40.0f))) { + engine.execBotCmd (ent (), "nightvision"); + } + else if (m_usesNVG && ((lightLevel > 20.0f && skyColor > 50.0f) || (lightLevel > 45.0f && skyColor <= 50.0f))) { + engine.execBotCmd (ent (), "nightvision"); + } + } + m_checkDarkTime = engine.timebase (); +} + void Bot::framePeriodic (void) { if (m_thinkFps <= engine.timebase ()) { // execute delayed think @@ -4860,6 +4920,9 @@ void Bot::ai (void) { checkTerrain (movedDistance, dirNormal); } + // check the darkness + checkDarkness (); + // must avoid a grenade? if (m_needAvoidGrenade != 0) { // don't duck to get away faster diff --git a/source/engine.cpp b/source/engine.cpp index e620044..8bbfd5d 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -849,10 +849,7 @@ void Engine::processMessages (void *ptr) { case 1: if (bot != nullptr) { - if (strcmp (strVal, "defuser") == 0) { - bot->m_hasDefuser = (enabled != 0); - } - else if (strcmp (strVal, "buyzone") == 0) { + if (strcmp (strVal, "buyzone") == 0) { bot->m_inBuyZone = (enabled != 0); // try to equip in buyzone @@ -1102,6 +1099,31 @@ void Engine::processMessages (void *ptr) { } break; + case NETMSG_ITEMSTATUS: + if (bot != nullptr && m_msgBlock.state == 0) { + + enum ItemStatus { + IS_NIGHTVISION = (1 << 0), + IS_DEFUSEKIT = (1 << 1) + }; + + bot->m_hasNVG = (intVal & IS_NIGHTVISION) ? true : false; + bot->m_hasDefuser = (intVal & IS_DEFUSEKIT) ? true : false; + } + break; + + case NETMSG_FLASHBAT: + if (bot != nullptr && m_msgBlock.state == 0) { + bot->m_flashLevel = static_cast (intVal); + } + break; + + case NETMSG_NVGTOGGLE: + if (bot != nullptr && m_msgBlock.state == 0) { + bot->m_usesNVG = intVal > 0; + } + break; + default: logEntry (true, LL_FATAL, "Network message handler error. Call to unrecognized message id (%d).\n", m_msgBlock.msg); } @@ -1257,6 +1279,6 @@ float LightMeasure::getLightLevel (const Vector &point) { return !recursiveCheck () ? 0.0f : 100 * cr::sqrtf (cr::min (75.0f, static_cast (m_point.avg ())) / 75.0f); } -float LightMeasure::getSkiesColor (void) { - return sv_skycolor_r.flt () + sv_skycolor_g.flt () + sv_skycolor_b.flt (); +float LightMeasure::getSkyColor (void) { + return (sv_skycolor_r.flt () + sv_skycolor_g.flt () + sv_skycolor_b.flt ()) / 3; } diff --git a/source/interface.cpp b/source/interface.cpp index 5dd05d1..ca799f1 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -203,7 +203,7 @@ int handleBotCommands (edict_t *ent, const char *arg0, const char *arg1, const c } else if (stricmp (arg0, "glp") == 0) { for (int i = 0; i < waypoints.length (); i++) { - engine.print ("%d - %f - %f", i, waypoints.getLightLevel (i), illum.getSkiesColor ()); + engine.print ("%d - %f - %f", i, waypoints.getLightLevel (i), illum.getSkyColor ()); } } @@ -2428,23 +2428,32 @@ void pfnMessageBegin (int msgDest, int msgType, const float *origin, edict_t *ed // store the message type in our own variables, since the GET_USER_MSG_ID () will just do a lot of strcmp()'s... if ((g_gameFlags & GAME_METAMOD) && engine.getMessageId (NETMSG_MONEY) == -1) { - engine.setMessageId (NETMSG_VGUI, GET_USER_MSG_ID (PLID, "VGUIMenu", nullptr)); - engine.setMessageId (NETMSG_SHOWMENU, GET_USER_MSG_ID (PLID, "ShowMenu", nullptr)); - engine.setMessageId (NETMSG_WEAPONLIST, GET_USER_MSG_ID (PLID, "WeaponList", nullptr)); - engine.setMessageId (NETMSG_CURWEAPON, GET_USER_MSG_ID (PLID, "CurWeapon", nullptr)); - engine.setMessageId (NETMSG_AMMOX, GET_USER_MSG_ID (PLID, "AmmoX", nullptr)); - engine.setMessageId (NETMSG_AMMOPICKUP, GET_USER_MSG_ID (PLID, "AmmoPickup", nullptr)); - engine.setMessageId (NETMSG_DAMAGE, GET_USER_MSG_ID (PLID, "Damage", nullptr)); - engine.setMessageId (NETMSG_MONEY, GET_USER_MSG_ID (PLID, "Money", nullptr)); - engine.setMessageId (NETMSG_STATUSICON, GET_USER_MSG_ID (PLID, "StatusIcon", nullptr)); - engine.setMessageId (NETMSG_DEATH, GET_USER_MSG_ID (PLID, "DeathMsg", nullptr)); - engine.setMessageId (NETMSG_SCREENFADE, GET_USER_MSG_ID (PLID, "ScreenFade", nullptr)); - engine.setMessageId (NETMSG_HLTV, GET_USER_MSG_ID (PLID, "HLTV", nullptr)); - engine.setMessageId (NETMSG_TEXTMSG, GET_USER_MSG_ID (PLID, "TextMsg", nullptr)); - engine.setMessageId (NETMSG_TEAMINFO, GET_USER_MSG_ID (PLID, "TeamInfo", nullptr)); - engine.setMessageId (NETMSG_BARTIME, GET_USER_MSG_ID (PLID, "BarTime", nullptr)); - engine.setMessageId (NETMSG_SENDAUDIO, GET_USER_MSG_ID (PLID, "SendAudio", nullptr)); - engine.setMessageId (NETMSG_SAYTEXT, GET_USER_MSG_ID (PLID, "SayText", nullptr)); + + auto setMsgId = [&] (const char *name, NetMsgId id) { + engine.setMessageId (id, GET_USER_MSG_ID (PLID, name, nullptr)); + }; + + setMsgId ("VGUIMenu", NETMSG_VGUI); + setMsgId ("ShowMenu", NETMSG_SHOWMENU); + setMsgId ("WeaponList", NETMSG_WEAPONLIST); + setMsgId ("CurWeapon", NETMSG_CURWEAPON); + setMsgId ("AmmoX", NETMSG_AMMOX); + setMsgId ("AmmoPickup", NETMSG_AMMOPICKUP); + setMsgId ("Damage", NETMSG_DAMAGE); + setMsgId ("Money", NETMSG_MONEY); + setMsgId ("StatusIcon", NETMSG_STATUSICON); + setMsgId ("DeathMsg", NETMSG_DEATH); + setMsgId ("ScreenFade", NETMSG_SCREENFADE); + setMsgId ("HLTV", NETMSG_HLTV); + setMsgId ("TextMsg", NETMSG_TEXTMSG); + setMsgId ("TeamInfo", NETMSG_TEAMINFO); + setMsgId ("BarTime", NETMSG_BARTIME); + setMsgId ("SendAudio", NETMSG_SENDAUDIO); + setMsgId ("SayText", NETMSG_SAYTEXT); + setMsgId ("FlashBat", NETMSG_FLASHBAT); + setMsgId ("Flashlight", NETMSG_FLASHLIGHT); + setMsgId ("NVGToggle", NETMSG_NVGTOGGLE); + setMsgId ("ItemStatus", NETMSG_ITEMSTATUS); if (g_gameFlags & GAME_SUPPORT_BOT_VOICE) { engine.setMessageId (NETMSG_BOTVOICE, GET_USER_MSG_ID (PLID, "BotVoice", nullptr)); @@ -2476,6 +2485,9 @@ void pfnMessageBegin (int msgDest, int msgType, const float *origin, edict_t *ed engine.captureMessage (msgType, NETMSG_BARTIME); engine.captureMessage (msgType, NETMSG_TEXTMSG); engine.captureMessage (msgType, NETMSG_SHOWMENU); + engine.captureMessage (msgType, NETMSG_FLASHBAT); + engine.captureMessage (msgType, NETMSG_NVGTOGGLE); + engine.captureMessage (msgType, NETMSG_ITEMSTATUS); } } else if (msgDest == MSG_ALL) { @@ -2769,6 +2781,18 @@ int pfnRegUserMsg (const char *name, int size) { else if (strcmp (name, "BotVoice") == 0) { engine.setMessageId (NETMSG_BOTVOICE, message); } + else if (strcmp (name, "NVGToggle") == 0) { + engine.setMessageId (NETMSG_NVGTOGGLE, message); + } + else if (strcmp (name, "FlashBat") == 0) { + engine.setMessageId (NETMSG_FLASHBAT, message); + } + else if (strcmp (name, "Flashlight") == 0) { + engine.setMessageId (NETMSG_FLASHLIGHT, message); + } + else if (strcmp (name, "ItemStatus") == 0) { + engine.setMessageId (NETMSG_ITEMSTATUS, message); + } return message; } diff --git a/source/manager.cpp b/source/manager.cpp index dfb2749..30e78aa 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -1191,6 +1191,8 @@ void Bot::newRound (void) { m_currentWeapon = 0; } + m_flashLevel = 100.0f; + m_checkDarkTime = engine.timebase (); m_knifeAttackTime = engine.timebase () + rng.getFloat (1.3f, 2.6f); m_nextBuyTime = engine.timebase () + rng.getFloat (0.6f, 2.0f);