// #################################### // # # // # Ping of Death - Bot # // # by # // # Markus Klinge aka Count Floyd # // # # // #################################### // // Started from the HPB-Bot Alpha Source // by Botman so Credits for a lot of the basic // HL Server/Client Stuff goes to him // // util.cpp // // Misc utility Functions. Really not optional after all. #include "bot_globals.h" Vector UTIL_VecToAngles (const Vector &vec) { float rgflVecOut[3]; VEC_TO_ANGLES (vec, rgflVecOut); return (Vector(rgflVecOut)); } // Overloaded to add IGNORE_GLASS void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr) { TRACE_LINE (vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE) | (ignoreGlass ? 0x100 : 0), pentIgnore, ptr); } void UTIL_TraceLine (const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr) { TRACE_LINE (vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), pentIgnore, ptr); } unsigned short FixedUnsigned16 (float value, float scale) { int output; output = value * scale; if (output < 0) output = 0; if (output > 0xFFFF) output = 0xFFFF; return ((unsigned short) output); } short FixedSigned16 (float value, float scale) { int output; output = value * scale; if (output > 32767) output = 32767; if (output < -32768) output = -32768; return ((short) output); } int UTIL_GetTeam (edict_t *pEntity) { // return team number 0 through 3 based what MOD uses for team numbers char model_name[32]; strcpy (model_name, (INFOKEY_VALUE (GET_INFOKEYBUFFER (pEntity), "model"))); if ((model_name[2] == 'b') // urBan || (model_name[2] == 'g') // gsG9, giGn || (model_name[2] == 's') // saS || (model_name[2] == 'p')) // viP return (TEAM_CS_COUNTER); return (TEAM_CS_TERRORIST); // teRror, leEt, guErilla, arCtic } bot_t *UTIL_GetBotPointer (edict_t *pEdict) { if (FNullEnt (pEdict)) return (NULL); // reliability check int index = ENTINDEX (pEdict) - 1; if ((index >= 0) && (index < gpGlobals->maxClients) && (bots[index].pEdict == pEdict)) return (&bots[index]); return (NULL); // return NULL if edict is not a bot } bool IsAlive (edict_t *pEdict) { return ((pEdict->v.deadflag == DEAD_NO) && (pEdict->v.health > 0) && (pEdict->v.movetype != MOVETYPE_NOCLIP)); } bool FInViewCone (Vector *pOrigin, edict_t *pEdict) { Vector2D vec2LOS; float flDot; float fov; MAKE_VECTORS (pEdict->v.v_angle); vec2LOS = (*pOrigin - pEdict->v.origin).Make2D ().Normalize (); flDot = DotProduct (vec2LOS, gpGlobals->v_forward.Make2D ()); if (pEdict->v.fov > 0) fov = pEdict->v.fov; else fov = 90; if (flDot >= cos ((fov / 2) * M_PI / 180)) return (TRUE); return (FALSE); } float GetShootingConeDeviation (edict_t *pEdict, Vector *pvecPosition) { Vector vecDir = (*pvecPosition - GetGunPosition (pEdict)).Normalize (); Vector vecAngle = pEdict->v.v_angle; MAKE_VECTORS (vecAngle); // He's facing it, he meant it return (DotProduct (gpGlobals->v_forward, vecDir)); } bool IsShootableBreakable (edict_t *pent) { return ((pent->v.impulse == 0) && (pent->v.takedamage > 0) && (pent->v.health < 1000.0) && !(pent->v.spawnflags & SF_BREAK_TRIGGER_ONLY)); } bool FBoxVisible (edict_t *pEdict, edict_t *pTargetEdict, Vector *pvHit, unsigned char *ucBodyPart) { int i; *ucBodyPart = 0; // don't look through water if (((pEdict->v.waterlevel != 3) && (pTargetEdict->v.waterlevel == 3)) || ((pEdict->v.waterlevel == 3) && (pTargetEdict->v.waterlevel == 0))) return (FALSE); TraceResult tr; Vector vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs; Vector vecTarget = pTargetEdict->v.origin; // Check direct Line to waist UTIL_TraceLine (vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, pEdict, &tr); if (tr.flFraction == 1.0) { *pvHit = tr.vecEndPos; *ucBodyPart |= WAIST_VISIBLE; } // Check direct Line to head vecTarget = vecTarget + pTargetEdict->v.view_ofs; UTIL_TraceLine (vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, pEdict, &tr); if (tr.flFraction == 1.0) { *pvHit = tr.vecEndPos; *ucBodyPart |= HEAD_VISIBLE; } if (*ucBodyPart != 0) return (TRUE); // Nothing visible - check randomly other Parts of Body for (i = 0; i < 5; i++) { Vector vecTarget = pTargetEdict->v.origin; vecTarget.x += RANDOM_FLOAT (pTargetEdict->v.mins.x, pTargetEdict->v.maxs.x); vecTarget.y += RANDOM_FLOAT (pTargetEdict->v.mins.y, pTargetEdict->v.maxs.y); vecTarget.z += RANDOM_FLOAT (pTargetEdict->v.mins.z, pTargetEdict->v.maxs.z); UTIL_TraceLine (vecLookerOrigin, vecTarget, ignore_monsters, ignore_glass, pEdict, &tr); if (tr.flFraction == 1.0) { // Return seen position *pvHit = tr.vecEndPos; *ucBodyPart |= CUSTOM_VISIBLE; return (TRUE); } } return (FALSE); } bool FVisible (const Vector &vecOrigin, edict_t *pEdict) { TraceResult tr; Vector vecLookerOrigin; // look through caller's eyes vecLookerOrigin = pEdict->v.origin + pEdict->v.view_ofs; // don't look through water if ((POINT_CONTENTS (vecOrigin) == CONTENTS_WATER) != (POINT_CONTENTS (vecLookerOrigin) == CONTENTS_WATER)) return (FALSE); UTIL_TraceLine (vecLookerOrigin, vecOrigin, ignore_monsters, ignore_glass, pEdict, &tr); if (tr.flFraction != 1.0) return (FALSE); // Line of sight is not established return (TRUE); // line of sight is valid. } Vector GetGunPosition (edict_t *pEdict) { return (pEdict->v.origin + pEdict->v.view_ofs); } int UTIL_GetNearestPlayerIndex (Vector vecOrigin) { float fDistance; float fMinDistance = 9999.0; int index = 0; int i; for (i = 0; i < gpGlobals->maxClients; i++) { if (!clients[i].IsAlive || !clients[i].IsUsed) continue; fDistance = (clients[i].pEdict->v.origin - vecOrigin).Length(); if (fDistance < fMinDistance) { index = i; fMinDistance = fDistance; } } return (index); } Vector VecBModelOrigin (edict_t *pEdict) { return (pEdict->v.absmin + (pEdict->v.size * 0.5)); } void UTIL_ShowMenu (menutext_t *pMenu) { if (FNullEnt (pHostEdict)) return; if (GET_USER_MSG_ID (PLID, "ShowMenu", NULL) == 0) REG_USER_MSG ("ShowMenu", -1); if (pMenu != NULL) { MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, GET_USER_MSG_ID (PLID, "ShowMenu", NULL), NULL, pHostEdict); WRITE_SHORT (pMenu->ValidSlots); WRITE_CHAR (-1); WRITE_BYTE (0); WRITE_STRING (pMenu->szMenuText); MESSAGE_END(); pUserMenu = pMenu; } else { MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, GET_USER_MSG_ID (PLID, "ShowMenu", NULL), NULL, pHostEdict); WRITE_SHORT (0); WRITE_CHAR (0); WRITE_BYTE (0); WRITE_STRING (""); MESSAGE_END(); pUserMenu = NULL; } EMIT_SOUND_DYN2 (pHostEdict, CHAN_WEAPON, "player/geiger1.wav", 1.0, ATTN_NORM, 0, 100); } void UTIL_DisplayWpMenuWelcomeMessage (void) { if (FNullEnt (pHostEdict)) return; MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, NULL, pHostEdict); WRITE_BYTE (TE_TEXTMESSAGE); WRITE_BYTE (1); // channel WRITE_SHORT (0); // x coordinates * 8192 WRITE_SHORT (0); // y coordinates * 8192 WRITE_BYTE (0); // effect (fade in/out) WRITE_BYTE (128); // initial RED WRITE_BYTE (0); // initial GREEN WRITE_BYTE (0); // initial BLUE WRITE_BYTE (1); // initial ALPHA WRITE_BYTE (255); // effect RED WRITE_BYTE (255); // effect GREEN WRITE_BYTE (255); // effect BLUE WRITE_BYTE (1); // effect ALPHA WRITE_SHORT (256); // fade-in time in seconds * 256 WRITE_SHORT (256); // fade-out time in seconds * 256 WRITE_SHORT (1280); // hold time in seconds * 256 WRITE_STRING (WPMENU_WELCOMEMSG); // write message MESSAGE_END (); // end } void UTIL_DecalTrace (TraceResult *pTrace, char *pszDecalName) { short entityIndex; int index; int message; index = DECAL_INDEX(pszDecalName); if (index<0) index = 0; if (pTrace->flFraction == 1.0) return; // Only decal BSP models if (pTrace->pHit) { edict_t *pHit = pTrace->pHit; if (FNullEnt (pHit)) return; // reliability check if ((pHit->v.solid == SOLID_BSP) || (pHit->v.movetype == MOVETYPE_PUSHSTEP)) entityIndex = ENTINDEX (pHit); else return; } else entityIndex = 0; message = TE_DECAL; if (entityIndex != 0) { if (index > 255) { message = TE_DECALHIGH; index -= 256; } } else { message = TE_WORLDDECAL; if (index > 255) { message = TE_WORLDDECALHIGH; index -= 256; } } MESSAGE_BEGIN (MSG_BROADCAST, SVC_TEMPENTITY); WRITE_BYTE (message); WRITE_COORD (pTrace->vecEndPos.x); WRITE_COORD (pTrace->vecEndPos.y); WRITE_COORD (pTrace->vecEndPos.z); WRITE_BYTE (index); if (entityIndex) WRITE_SHORT (entityIndex); MESSAGE_END(); } void UTIL_HostPrint (const char *fmt, ...) { va_list argptr; static char pszMessage[1024]; // concatenate all the arguments in one string va_start (argptr, fmt); vsprintf (pszMessage, fmt, argptr); va_end (argptr); if (!FNullEnt (pHostEdict)) { if (GET_USER_MSG_ID (PLID, "TextMsg", NULL) == 0) REG_USER_MSG ("TextMsg", -1); MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, GET_USER_MSG_ID (PLID, "TextMsg", NULL), NULL, pHostEdict); WRITE_BYTE (HUD_PRINTCENTER); WRITE_STRING (pszMessage); MESSAGE_END (); SERVER_PRINT (pszMessage); } else SERVER_PRINT (pszMessage); } void UTIL_ServerPrint (const char *fmt, ...) { va_list argptr; static char pszMessage[1024]; // concatenate all the arguments in one string va_start (argptr, fmt); vsprintf (pszMessage, fmt, argptr); va_end (argptr); SERVER_PRINT (pszMessage); } void UTIL_ClampAngle (float *fAngle) { // Whistler, TEST your bugfixes before submitting them!!! :D if (*fAngle >= 180) *fAngle -= 360 * ((int) (*fAngle / 360) + 1); // and not 0.5 if (*fAngle < -180) *fAngle += 360 * ((int) (-*fAngle / 360) + 1); // and not 0.5 if ((*fAngle >= 180) || (*fAngle < -180)) *fAngle = 0; // heck, if we're still above the limit then something's REALLY fuckedup! } void UTIL_ClampVector (Vector *vecAngles) { // Whistler, TEST your bugfixes before submitting them!!! :D if (vecAngles->x >= 180) vecAngles->x -= 360 * ((int) (vecAngles->x / 360) + 1); // and not 0.5 if (vecAngles->x < -180) vecAngles->x += 360 * ((int) (-vecAngles->x / 360) + 1); // and not 0.5 if (vecAngles->y >= 180) vecAngles->y -= 360 * ((int) (vecAngles->y / 360) + 1); // and not 0.5 if (vecAngles->y < -180) vecAngles->y += 360 * ((int) (-vecAngles->y / 360) + 1); // and not 0.5 vecAngles->z = 0.0; if (vecAngles->x > 89) vecAngles->x = 89; else if (vecAngles->x < -89) vecAngles->x = -89; if ((vecAngles->x >= 180) || (vecAngles->x < -180)) vecAngles->x = 0; // heck, if we're still above the limit then something's REALLY fuckedup! if ((vecAngles->y >= 180) || (vecAngles->y < -180)) vecAngles->y = 0; // heck, if we're still above the limit then something's REALLY fuckedup! } void UTIL_RoundStart (void) { // function to be called each time a round starts in CS 1.5 or 1.6 int i; for (i = 0; i < 32; i++) { if (bots[i].is_used == TRUE) BotSpawnInit (&bots[i]); iRadioSelect[i] = 0; } g_bBombPlanted = FALSE; g_bBombSayString = FALSE; g_fTimeBombPlanted = 0.0; g_vecBomb = g_vecZero; // Clear Waypoint Indices of visited Bomb Spots for (i = 0; i < MAXNUMBOMBSPOTS; i++) g_rgiBombSpotsVisited[i] = -1; g_iLastBombPoint = -1; g_fTimeNextBombUpdate = 0.0; g_bLeaderChosenT = FALSE; g_bLeaderChosenCT = FALSE; g_bHostageRescued = FALSE; g_rgfLastRadioTime[0] = 0.0; g_rgfLastRadioTime[1] = 0.0; g_bBotsCanPause = FALSE; // Clear Array of Player Stats for (i = 0; i < gpGlobals->maxClients; i++) { clients[i].vecSoundPosition = g_vecZero; clients[i].fHearingDistance = 0.0; clients[i].fTimeSoundLasting = 0.0; } // Update Experience Data on Round Start UpdateGlobalExperienceData (); // Calculate the Round Mid/End in World Time g_fTimeRoundStart = gpGlobals->time + CVAR_GET_FLOAT ("mp_freezetime"); g_fTimeRoundMid = g_fTimeRoundStart + CVAR_GET_FLOAT ("mp_roundtime") * 60 / 2; g_fTimeRoundEnd = g_fTimeRoundStart + CVAR_GET_FLOAT ("mp_roundtime") * 60; // Show the Waypoint copyright Message right at round start g_bMapInitialised = TRUE; return; } int printf (const char *fmt, ...) { va_list argptr; static char string[1024]; // concatenate all the arguments in one string va_start (argptr, fmt); vsprintf (string, fmt, argptr); va_end (argptr); // are we running a listen server ? if (!FNullEnt (pHostEdict)) { MESSAGE_BEGIN (MSG_ONE_UNRELIABLE, GET_USER_MSG_ID (PLID, "SayText", NULL), NULL, pHostEdict); // then print to HUD WRITE_BYTE (ENTINDEX (pHostEdict)); WRITE_STRING (string); MESSAGE_END (); } else SERVER_PRINT (string); // else print to console return (0); // printf() HAS to return a value }