From 5a7dbc24631ba9113864e86f0453e8ed8cda6e57 Mon Sep 17 00:00:00 2001 From: jeefo Date: Mon, 13 May 2019 21:41:14 +0300 Subject: [PATCH] Fixed detection mp_freeforall for regamedll. Added missing addon entities for regamedll. Fixed bots keep adding to game event when there is now spawn points left on map. Reduced a little bot difficulty at higher levels. --- include/corelib.h | 2 +- include/engine.h | 6 ++++ include/yapb.h | 9 ++++-- source/basecode.cpp | 14 +++++----- source/combat.cpp | 8 ++++-- source/engine.cpp | 10 ++++++- source/interface.cpp | 66 ++++++++++++++++++++++++++++++++++---------- source/manager.cpp | 25 ++++++++++++++++- 8 files changed, 110 insertions(+), 30 deletions(-) diff --git a/include/corelib.h b/include/corelib.h index 5dab881..f8448f8 100644 --- a/include/corelib.h +++ b/include/corelib.h @@ -607,7 +607,7 @@ public: return; } #ifdef PLATFORM_WIN32 - FreeLibrary ((HMODULE)m_ptr); + FreeLibrary (static_cast (m_ptr)); #else dlclose (m_ptr); #endif diff --git a/include/engine.h b/include/engine.h index 8aa6c61..f962d20 100644 --- a/include/engine.h +++ b/include/engine.h @@ -99,6 +99,7 @@ struct LangComprarer { class Engine : public Singleton { private: int m_drawModels[DRAW_NUM]; + int m_spawnCount[TEAM_UNASSIGNED]; // bot client command char m_arguments[256]; @@ -243,6 +244,11 @@ public: return m_startEntity; } + // get spawn count for team + inline int getSpawnCount (int team) { + return m_spawnCount[team]; + } + // gets the player team inline int getTeam (edict_t *ent) { extern Client g_clients[MAX_ENGINE_PLAYERS]; diff --git a/include/yapb.h b/include/yapb.h index 42b2618..1f24449 100644 --- a/include/yapb.h +++ b/include/yapb.h @@ -55,11 +55,12 @@ enum GameFlags { GAME_LEGACY = (1 << 3), // counter-strike 1.3-1.5 with/without steam GAME_MOBILITY = (1 << 4), // additional flag that bot is running on android (additional flag) GAME_OFFICIAL_CSBOT = (1 << 5), // additional flag that indicates official cs bots are in game - GAME_METAMOD = (1 << 6), // game running under metamod + GAME_METAMOD = (1 << 6), // game running under meta\mod GAME_CSDM = (1 << 7), // csdm mod currently in use GAME_CSDM_FFA = (1 << 8), // csdm mod with ffa mode - GAME_SUPPORT_SVC_PINGS = (1 << 9), // on that game version we can fake bots pings - GAME_SUPPORT_BOT_VOICE = (1 << 10) // on that game version we can use chatter + GAME_REGAMEDLL = (1 << 9), // server dll is a regamedll + GAME_SUPPORT_SVC_PINGS = (1 << 10), // on that game version we can fake bots pings + GAME_SUPPORT_BOT_VOICE = (1 << 11) // on that game version we can use chatter }; // bot menu ids @@ -1297,6 +1298,7 @@ private: float m_entityUpdateTime; // time to update intresting entities int m_lastWinner; // the team who won previous round + int m_lastDifficulty; // last bots difficulty bool m_leaderChoosen[MAX_TEAM_COUNT]; // is team leader choose theese round bool m_economicsGood[MAX_TEAM_COUNT]; // is team able to buy anything @@ -1371,6 +1373,7 @@ public: void listBots (void); void setWeaponMode (int selection); void updateTeamEconomics (int team, bool setTrue = false); + void updateBotDifficulties (void); static void execGameEntity (entvars_t *vars); diff --git a/source/basecode.cpp b/source/basecode.cpp index 634a809..ff7767d 100644 --- a/source/basecode.cpp +++ b/source/basecode.cpp @@ -2868,13 +2868,13 @@ void Bot::checkDarkness (void) { 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; - } + 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) { diff --git a/source/combat.cpp b/source/combat.cpp index b1df487..8337a2e 100644 --- a/source/combat.cpp +++ b/source/combat.cpp @@ -201,6 +201,8 @@ bool Bot::lookupEnemies (void) { edict_t *player, *newEnemy = nullptr; float nearestDistance = cr::square (m_viewDistance); + extern ConVar yb_whose_your_daddy; + // clear suspected flag if (!engine.isNullEntity (m_enemy) && (m_states & STATE_SEEING_ENEMY)) { m_states &= ~STATE_SUSPECT_ENEMY; @@ -272,8 +274,8 @@ bool Bot::lookupEnemies (void) { m_aimFlags |= AIM_ENEMY; m_states |= STATE_SEEING_ENEMY; + // if enemy is still visible and in field of view, keep it keep track of when we last saw an enemy if (newEnemy == m_enemy) { - // if enemy is still visible and in field of view, keep it keep track of when we last saw an enemy m_seeEnemyTime = engine.timebase (); // zero out reaction time @@ -284,12 +286,12 @@ bool Bot::lookupEnemies (void) { return true; } else { - if (m_seeEnemyTime + 3.0 < engine.timebase () && (m_hasC4 || hasHostage () || !engine.isNullEntity (m_targetEntity))) { + if (m_seeEnemyTime + 3.0f < engine.timebase () && (m_hasC4 || hasHostage () || !engine.isNullEntity (m_targetEntity))) { pushRadioMessage (RADIO_ENEMY_SPOTTED); } m_targetEntity = nullptr; // stop following when we see an enemy... - if (rng.getInt (0, 100) < m_difficulty * 25) { + if (yb_whose_your_daddy.boolean ()) { m_enemySurpriseTime = m_actualReactionTime * 0.5f; } else { diff --git a/source/engine.cpp b/source/engine.cpp index 09344a3..a4de9f0 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -28,6 +28,7 @@ Engine::Engine (void) { memset (m_arguments, 0, sizeof (m_arguments)); memset (m_drawModels, 0, sizeof (m_drawModels)); + memset (m_spawnCount, 0, sizeof (m_spawnCount)); m_cvars.clear (); } @@ -69,6 +70,9 @@ void Engine::levelInitialize (void) { // this function precaches needed models and initialize class variables m_localEntity = nullptr; + + m_spawnCount[TEAM_COUNTER] = 0; + m_spawnCount[TEAM_TERRORIST] = 0; // go thru the all entities on map, and do whatever we're want for (int i = 0; i < g_pGlobals->maxEntities; i++) { @@ -101,6 +105,8 @@ void Engine::levelInitialize (void) { ent->v.rendermode = kRenderTransAlpha; // set its render mode to transparency ent->v.renderamt = 127; // set its transparency amount ent->v.effects |= EF_NODRAW; + + m_spawnCount[TEAM_COUNTER]++; } else if (strcmp (classname, "info_player_deathmatch") == 0) { g_engfuncs.pfnSetModel (ent, ENGINE_STR ("models/player/terror/terror.mdl")); @@ -108,6 +114,8 @@ void Engine::levelInitialize (void) { ent->v.rendermode = kRenderTransAlpha; // set its render mode to transparency ent->v.renderamt = 127; // set its transparency amount ent->v.effects |= EF_NODRAW; + + m_spawnCount[TEAM_TERRORIST]++; } else if (strcmp (classname, "info_vip_start") == 0) { @@ -1280,5 +1288,5 @@ float LightMeasure::getLightLevel (const Vector &point) { } float LightMeasure::getSkyColor (void) { - return (sv_skycolor_r.flt () + sv_skycolor_g.flt () + sv_skycolor_b.flt ()) / 3; + return sv_skycolor_r.flt () + sv_skycolor_g.flt () + sv_skycolor_b.flt (); } diff --git a/source/interface.cpp b/source/interface.cpp index ca799f1..039e36e 100644 --- a/source/interface.cpp +++ b/source/interface.cpp @@ -2247,18 +2247,22 @@ void StartFrame (void) { // calculate light levels for all waypoints if needed waypoints.initLightLevels (); - if (g_gameFlags & GAME_METAMOD) { + if (g_gameFlags & (GAME_METAMOD | GAME_REGAMEDLL)) { static auto dmActive = g_engfuncs.pfnCVarGetPointer ("csdm_active"); static auto freeForAll = g_engfuncs.pfnCVarGetPointer ("mp_freeforall"); - if (dmActive && freeForAll) { + // csdm is only with amxx and metamod + if (dmActive) { if (dmActive->value > 0.0f) { g_gameFlags |= GAME_CSDM; } else if (g_gameFlags & GAME_CSDM) { g_gameFlags &= ~GAME_CSDM; } - + } + + // but this can be provided by regamedll + if (freeForAll) { if (freeForAll->value > 0.0f) { g_gameFlags |= GAME_CSDM_FFA; } @@ -3031,8 +3035,9 @@ SHARED_LIBRARAY_EXPORT void Meta_Init (void) { Library *LoadCSBinary (void) { const char *modname = engine.getModName (); - if (!modname) + if (!modname) { return nullptr; + } #if defined(PLATFORM_WIN32) const char *libs[] = {"mp.dll", "cs.dll"}; @@ -3042,6 +3047,22 @@ Library *LoadCSBinary (void) { const char *libs[] = {"cs.dylib"}; #endif + auto libCheck = [] (Library *lib, const char *modname, const char *dll) { + // try to load gamedll + if (!lib->isValid ()) { + logEntry (true, LL_FATAL | LL_IGNORE, "Unable to load gamedll \"%s\". Exiting... (gamedir: %s)", dll, modname); + + return false; + } + auto ent = lib->resolve ("trigger_random_unique"); + + // detect regamedll by addon entity they provide + if (ent != nullptr) { + g_gameFlags |= GAME_REGAMEDLL; + } + return true; + }; + // search the libraries inside game dlls directory for (size_t i = 0; i < cr::arrsize (libs); i++) { auto *path = format ("%s/dlls/%s", modname, libs[i]); @@ -3058,18 +3079,24 @@ Library *LoadCSBinary (void) { if (g_gameFlags & GAME_METAMOD) { return nullptr; } - return new Library (path); - } - else { - Library *game = new Library (path); - - // try to load gamedll - if (!game->isValid ()) { - logEntry (true, LL_FATAL | LL_IGNORE, "Unable to load gamedll \"%s\". Exiting... (gamedir: %s)", libs[i], modname); + auto game = new Library (path); + // verify dll is OK + if (!libCheck (game, modname, libs[i])) { delete game; return nullptr; } + return game; + } + else { + auto game = new Library (path); + + // verify dll is OK + if (!libCheck (game, modname, libs[i])) { + delete game; + return nullptr; + } + // detect if we're running modern game auto entity = game->resolve ("weapon_famas"); @@ -3159,8 +3186,7 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t delete g_gameLib; } #else - g_gameLib = LoadCSBinary (); - { + g_gameLib = LoadCSBinary (); { if (!g_gameLib && !(g_gameFlags & GAME_METAMOD)) { logEntry (true, LL_FATAL | LL_IGNORE, "Mod that you has started, not supported by this bot (gamedir: %s)", engine.getModName ()); return; @@ -3178,6 +3204,7 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t else if (g_gameFlags & GAME_CSTRIKE16) { gameVersionStr.assign ("v1.6"); } + if (g_gameFlags & GAME_XASH_ENGINE) { gameVersionStr.append (" @ Xash3D Engine"); @@ -3191,6 +3218,10 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t gameVersionStr.append (" (BV)"); } + if (g_gameFlags & GAME_REGAMEDLL) { + gameVersionStr.append (" (RE)"); + } + if (g_gameFlags & GAME_SUPPORT_SVC_PINGS) { gameVersionStr.append (" (SVC)"); } @@ -3357,6 +3388,7 @@ LINK_ENTITY (info_teleport_destination) LINK_ENTITY (info_vip_start) LINK_ENTITY (infodecal) LINK_ENTITY (item_airtank) +LINK_ENTITY (item_airbox) LINK_ENTITY (item_antidote) LINK_ENTITY (item_assaultsuit) LINK_ENTITY (item_battery) @@ -3382,6 +3414,8 @@ LINK_ENTITY (path_track) LINK_ENTITY (player) LINK_ENTITY (player_loadsaved) LINK_ENTITY (player_weaponstrip) +LINK_ENTITY (point_clientcommand) +LINK_ENTITY (point_servercommand) LINK_ENTITY (soundent) LINK_ENTITY (spark_shower) LINK_ENTITY (speaker) @@ -3402,7 +3436,11 @@ LINK_ENTITY (trigger_monsterjump) LINK_ENTITY (trigger_multiple) LINK_ENTITY (trigger_once) LINK_ENTITY (trigger_push) +LINK_ENTITY (trigger_random) +LINK_ENTITY (trigger_random_time) +LINK_ENTITY (trigger_random_unique) LINK_ENTITY (trigger_relay) +LINK_ENTITY (trigger_setorigin) LINK_ENTITY (trigger_teleport) LINK_ENTITY (trigger_transition) LINK_ENTITY (weapon_ak47) diff --git a/source/manager.cpp b/source/manager.cpp index 11586a5..03deef8 100644 --- a/source/manager.cpp +++ b/source/manager.cpp @@ -31,6 +31,7 @@ ConVar mp_autoteambalance ("mp_autoteambalance", nullptr, VT_NOREGISTER); BotManager::BotManager (void) { // this is a bot manager class constructor + m_lastDifficulty = 0; m_lastWinner = -1; m_deathMsgSent = false; @@ -385,6 +386,10 @@ void BotManager::maintainQuota (void) { if (m_quotaMaintainTime > engine.timebase ()) { return; } + + // not a best place for this, but whatever + updateBotDifficulties (); + yb_quota.set (cr::clamp (yb_quota.integer (), 0, engine.maxClients ())); int totalHumansInGame = getHumansCount (); @@ -417,9 +422,10 @@ void BotManager::maintainQuota (void) { else { desiredBotCount = cr::min (desiredBotCount, maxClients - humanPlayersInGame); } + int maxSpawnCount = engine.getSpawnCount (TEAM_TERRORIST) + engine.getSpawnCount (TEAM_COUNTER); // add bots if necessary - if (desiredBotCount > botsInGame) { + if (desiredBotCount > botsInGame && botsInGame < maxSpawnCount) { createRandom (); } else if (desiredBotCount < botsInGame) { @@ -825,6 +831,23 @@ void BotManager::updateTeamEconomics (int team, bool forceGoodEconomics) { } } +void BotManager::updateBotDifficulties (void) { + int difficulty = yb_difficulty.integer (); + + if (difficulty != m_lastDifficulty) { + + // sets new difficulty for all bots + for (int i = 0; i < engine.maxClients (); i++) { + auto bot = m_bots[i]; + + if (bot != nullptr) { + m_bots[i]->m_difficulty = difficulty; + } + } + m_lastDifficulty = difficulty; + } +} + void BotManager::destroy (void) { // this function free all bots slots (used on server shutdown)