/*** * * Copyright (c) 1996-2002, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * Valve LLC. All other use, distribution, or modification is prohibited * without written permission from Valve LLC. * ****/ #include "stdafx.h" #include "cbase.h" #include "saverestore.h" #include #include "shake.h" #include "decals.h" #include "player.h" #include "weapons.h" #include "gamerules.h" #ifndef min #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #endif float UTIL_WeaponTimeBase(void) { #ifdef CLIENT_WEAPONS return 0; #else return gpGlobals->time; #endif } static unsigned int glSeed = 0; unsigned int seed_table[256] = { 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 }; unsigned int U_Random(void) { glSeed *= 69069; glSeed += seed_table[glSeed & 0xFF]; return (++glSeed & 0x0FFFFFFF); } void U_Srand(unsigned int seed) { glSeed = seed_table[seed & 0xFF]; } int UTIL_SharedRandomLong(unsigned int seed, int low, int high) { U_Srand((int)seed + low + high); unsigned int range = high - low + 1; if (!(range - 1)) return low; int rnum = U_Random(); int offset = rnum % range; return (low + offset); } float UTIL_SharedRandomFloat(unsigned int seed, float low, float high) { U_Srand((int)seed + *(int *)&low + *(int *)&high); U_Random(); U_Random(); unsigned range = (int)(high - low); if (!range) return low; int tensixrand = U_Random() & 65535; float offset = (float)tensixrand / 65536; return (low + offset * range); } void UTIL_ParametricRocket(entvars_t *pev, Vector vecOrigin, Vector vecAngles, edict_t *owner) { pev->startpos = vecOrigin; TraceResult tr; UTIL_MakeVectors(vecAngles); UTIL_TraceLine(pev->startpos, pev->startpos + gpGlobals->v_forward * 8192, ignore_monsters, owner, &tr); pev->endpos = tr.vecEndPos; Vector vecTravel = pev->endpos - pev->startpos; float travelTime = 0; if (pev->velocity.Length() > 0) travelTime = vecTravel.Length() / pev->velocity.Length(); pev->starttime = gpGlobals->time; pev->impacttime = gpGlobals->time + travelTime; } int g_groupmask = 0; int g_groupop = 0; void UTIL_SetGroupTrace(int groupmask, int op) { g_groupmask = groupmask; g_groupop = op; ENGINE_SETGROUPMASK(g_groupmask, g_groupop); } void UTIL_UnsetGroupTrace(void) { g_groupmask = 0; g_groupop = 0; ENGINE_SETGROUPMASK(0, 0); } UTIL_GroupTrace::UTIL_GroupTrace(int groupmask, int op) { m_oldgroupmask = g_groupmask; m_oldgroupop = g_groupop; g_groupmask = groupmask; g_groupop = op; ENGINE_SETGROUPMASK(g_groupmask, g_groupop); } UTIL_GroupTrace::~UTIL_GroupTrace(void) { g_groupmask = m_oldgroupmask; g_groupop = m_oldgroupop; ENGINE_SETGROUPMASK(g_groupmask, g_groupop); } TYPEDESCRIPTION gEntvarsDescription[] = { DEFINE_ENTITY_FIELD(classname, FIELD_STRING), DEFINE_ENTITY_GLOBAL_FIELD(globalname, FIELD_STRING), DEFINE_ENTITY_FIELD(origin, FIELD_POSITION_VECTOR), DEFINE_ENTITY_FIELD(oldorigin, FIELD_POSITION_VECTOR), DEFINE_ENTITY_FIELD(velocity, FIELD_VECTOR), DEFINE_ENTITY_FIELD(basevelocity, FIELD_VECTOR), DEFINE_ENTITY_FIELD(movedir, FIELD_VECTOR), DEFINE_ENTITY_FIELD(angles, FIELD_VECTOR), DEFINE_ENTITY_FIELD(avelocity, FIELD_VECTOR), DEFINE_ENTITY_FIELD(punchangle, FIELD_VECTOR), DEFINE_ENTITY_FIELD(v_angle, FIELD_VECTOR), DEFINE_ENTITY_FIELD(fixangle, FIELD_FLOAT), DEFINE_ENTITY_FIELD(idealpitch, FIELD_FLOAT), DEFINE_ENTITY_FIELD(pitch_speed, FIELD_FLOAT), DEFINE_ENTITY_FIELD(ideal_yaw, FIELD_FLOAT), DEFINE_ENTITY_FIELD(yaw_speed, FIELD_FLOAT), DEFINE_ENTITY_FIELD(modelindex, FIELD_INTEGER), DEFINE_ENTITY_GLOBAL_FIELD(model, FIELD_MODELNAME), DEFINE_ENTITY_FIELD(viewmodel, FIELD_MODELNAME), DEFINE_ENTITY_FIELD(weaponmodel, FIELD_MODELNAME), DEFINE_ENTITY_FIELD(absmin, FIELD_POSITION_VECTOR), DEFINE_ENTITY_FIELD(absmax, FIELD_POSITION_VECTOR), DEFINE_ENTITY_GLOBAL_FIELD(mins, FIELD_VECTOR), DEFINE_ENTITY_GLOBAL_FIELD(maxs, FIELD_VECTOR), DEFINE_ENTITY_GLOBAL_FIELD(size, FIELD_VECTOR), DEFINE_ENTITY_FIELD(ltime, FIELD_TIME), DEFINE_ENTITY_FIELD(nextthink, FIELD_TIME), DEFINE_ENTITY_FIELD(solid, FIELD_INTEGER), DEFINE_ENTITY_FIELD(movetype, FIELD_INTEGER), DEFINE_ENTITY_FIELD(skin, FIELD_INTEGER), DEFINE_ENTITY_FIELD(body, FIELD_INTEGER), DEFINE_ENTITY_FIELD(effects, FIELD_INTEGER), DEFINE_ENTITY_FIELD(gravity, FIELD_FLOAT), DEFINE_ENTITY_FIELD(friction, FIELD_FLOAT), DEFINE_ENTITY_FIELD(light_level, FIELD_FLOAT), DEFINE_ENTITY_FIELD(frame, FIELD_FLOAT), DEFINE_ENTITY_FIELD(scale, FIELD_FLOAT), DEFINE_ENTITY_FIELD(sequence, FIELD_INTEGER), DEFINE_ENTITY_FIELD(animtime, FIELD_TIME), DEFINE_ENTITY_FIELD(framerate, FIELD_FLOAT), DEFINE_ENTITY_FIELD(controller, FIELD_INTEGER), DEFINE_ENTITY_FIELD(blending, FIELD_INTEGER), DEFINE_ENTITY_FIELD(rendermode, FIELD_INTEGER), DEFINE_ENTITY_FIELD(renderamt, FIELD_FLOAT), DEFINE_ENTITY_FIELD(rendercolor, FIELD_VECTOR), DEFINE_ENTITY_FIELD(renderfx, FIELD_INTEGER), DEFINE_ENTITY_FIELD(health, FIELD_FLOAT), DEFINE_ENTITY_FIELD(frags, FIELD_FLOAT), DEFINE_ENTITY_FIELD(weapons, FIELD_INTEGER), DEFINE_ENTITY_FIELD(takedamage, FIELD_FLOAT), DEFINE_ENTITY_FIELD(deadflag, FIELD_FLOAT), DEFINE_ENTITY_FIELD(view_ofs, FIELD_VECTOR), DEFINE_ENTITY_FIELD(button, FIELD_INTEGER), DEFINE_ENTITY_FIELD(impulse, FIELD_INTEGER), DEFINE_ENTITY_FIELD(chain, FIELD_EDICT), DEFINE_ENTITY_FIELD(dmg_inflictor, FIELD_EDICT), DEFINE_ENTITY_FIELD(enemy, FIELD_EDICT), DEFINE_ENTITY_FIELD(aiment, FIELD_EDICT), DEFINE_ENTITY_FIELD(owner, FIELD_EDICT), DEFINE_ENTITY_FIELD(groundentity, FIELD_EDICT), DEFINE_ENTITY_FIELD(spawnflags, FIELD_INTEGER), DEFINE_ENTITY_FIELD(flags, FIELD_FLOAT), DEFINE_ENTITY_FIELD(colormap, FIELD_INTEGER), DEFINE_ENTITY_FIELD(team, FIELD_INTEGER), DEFINE_ENTITY_FIELD(max_health, FIELD_FLOAT), DEFINE_ENTITY_FIELD(teleport_time, FIELD_TIME), DEFINE_ENTITY_FIELD(armortype, FIELD_FLOAT), DEFINE_ENTITY_FIELD(armorvalue, FIELD_FLOAT), DEFINE_ENTITY_FIELD(waterlevel, FIELD_INTEGER), DEFINE_ENTITY_FIELD(watertype, FIELD_INTEGER), DEFINE_ENTITY_GLOBAL_FIELD(target, FIELD_STRING), DEFINE_ENTITY_GLOBAL_FIELD(targetname, FIELD_STRING), DEFINE_ENTITY_FIELD(netname, FIELD_STRING), DEFINE_ENTITY_FIELD(message, FIELD_STRING), DEFINE_ENTITY_FIELD(dmg_take, FIELD_FLOAT), DEFINE_ENTITY_FIELD(dmg_save, FIELD_FLOAT), DEFINE_ENTITY_FIELD(dmg, FIELD_FLOAT), DEFINE_ENTITY_FIELD(dmgtime, FIELD_TIME), DEFINE_ENTITY_FIELD(noise, FIELD_SOUNDNAME), DEFINE_ENTITY_FIELD(noise1, FIELD_SOUNDNAME), DEFINE_ENTITY_FIELD(noise2, FIELD_SOUNDNAME), DEFINE_ENTITY_FIELD(noise3, FIELD_SOUNDNAME), DEFINE_ENTITY_FIELD(speed, FIELD_FLOAT), DEFINE_ENTITY_FIELD(air_finished, FIELD_TIME), DEFINE_ENTITY_FIELD(pain_finished, FIELD_TIME), DEFINE_ENTITY_FIELD(radsuit_finished, FIELD_TIME), }; #define ENTVARS_COUNT (sizeof(gEntvarsDescription) / sizeof(gEntvarsDescription[0])) #ifdef _DEBUG edict_t *DBG_EntOfVars(const entvars_t *pev) { if (pev->pContainingEntity != NULL) return pev->pContainingEntity; ALERT(at_console, "entvars_t pContainingEntity is NULL, calling into engine"); edict_t *pent = (*g_engfuncs.pfnFindEntityByVars)((entvars_t*)pev); if (pent == NULL) ALERT(at_console, "DAMN! Even the engine couldn't FindEntityByVars!"); ((entvars_t *)pev)->pContainingEntity = pent; return pent; } #endif #ifdef _DEBUG void DBG_AssertFunction(BOOL fExpr, const char *szExpr, const char *szFile, int szLine, const char *szMessage) { if (fExpr) return; char szOut[512]; if (szMessage != NULL) sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage); else sprintf(szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine); ALERT(at_console, szOut); } #endif BOOL UTIL_GetNextBestWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon) { return g_pGameRules->GetNextBestWeapon(pPlayer, pCurrentWeapon); } float UTIL_AngleMod(float a) { if (a < 0) a = a + 360 * ((int)(a / 360) + 1); else if (a >= 360) a = a - 360 * ((int)(a / 360)); return a; } float UTIL_AngleDiff(float destAngle, float srcAngle) { float delta = destAngle - srcAngle; if (destAngle > srcAngle) { if (delta >= 180) delta -= 360; } else { if (delta <= -180) delta += 360; } return delta; } Vector UTIL_VecToAngles(const Vector &vec) { float rgflVecOut[3]; VEC_TO_ANGLES(vec, rgflVecOut); return Vector(rgflVecOut); } void UTIL_MoveToOrigin(edict_t *pent, const Vector &vecGoal, float flDist, int iMoveType) { float rgfl[3]; vecGoal.CopyToArray(rgfl); MOVE_TO_ORIGIN(pent, rgfl, flDist, iMoveType); } int UTIL_EntitiesInBox(CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask) { edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(1); int count = 0; if (!pEdict) return count; for (int i = 1; i < gpGlobals->maxEntities; i++, pEdict++) { if (pEdict->free) continue; if (flagMask && !(pEdict->v.flags & flagMask)) continue; if (mins.x > pEdict->v.absmax.x || mins.y > pEdict->v.absmax.y || mins.z > pEdict->v.absmax.z || maxs.x < pEdict->v.absmin.x || maxs.y < pEdict->v.absmin.y || maxs.z < pEdict->v.absmin.z) continue; CBaseEntity *pEntity = CBaseEntity::Instance(pEdict); if (!pEntity) continue; pList[count++] = pEntity; if (count >= listMax) return count; } return count; } int UTIL_MonstersInSphere(CBaseEntity **pList, int listMax, const Vector ¢er, float radius) { edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(1); int count = 0; float radiusSquared = radius * radius; if (!pEdict) return count; for (int i = 1; i < gpGlobals->maxEntities; i++, pEdict++) { if (pEdict->free) continue; if (!(pEdict->v.flags & (FL_CLIENT | FL_MONSTER))) continue; float delta = center.x - pEdict->v.origin.x; delta *= delta; if (delta > radiusSquared) continue; float distance = delta; delta = center.y - pEdict->v.origin.y; delta *= delta; distance += delta; if (distance > radiusSquared) continue; delta = center.z - (pEdict->v.absmin.z + pEdict->v.absmax.z) * 0.5; delta *= delta; distance += delta; if (distance > radiusSquared) continue; CBaseEntity *pEntity = CBaseEntity::Instance(pEdict); if (!pEntity) continue; pList[count++] = pEntity; if (count >= listMax) return count; } return count; } CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius) { edict_t *pentEntity = pStartEntity ? pStartEntity->edict() : NULL; pentEntity = FIND_ENTITY_IN_SPHERE(pentEntity, vecCenter, flRadius); if (!FNullEnt(pentEntity)) return CBaseEntity::Instance(pentEntity); return NULL; } CBaseEntity *UTIL_FindEntityByString_Old(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue) { edict_t *pentEntity = pStartEntity ? pStartEntity->edict() : NULL; pentEntity = FIND_ENTITY_BY_STRING(pentEntity, szKeyword, szValue); if (!FNullEnt(pentEntity)) return CBaseEntity::Instance(pentEntity); return NULL; } CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue) { edict_t *pentEntity = pStartEntity ? pStartEntity->edict() : NULL; int startEntityIndex = ENTINDEX(pentEntity); if (*szKeyword != 'c') { pentEntity = FIND_ENTITY_BY_STRING(pentEntity, szKeyword, szValue); } else { int hash = 0; hash_item_t *item; int count; hash = CaseInsensitiveHash(szValue, stringsHashTable.Count()); count = stringsHashTable.Count(); item = &stringsHashTable[hash]; while (item->pev) { if (!strcmp(STRING(item->pev->classname), szValue)) break; hash = (hash + 1) % count; item = &stringsHashTable[hash]; } if (!item->pev) { item->lastHash = NULL; return NULL; } if (pStartEntity) { if (item->lastHash && item->lastHash->pevIndex <= startEntityIndex) item = item->lastHash; while (item->pevIndex <= startEntityIndex) { if (!item->next) break; item = item->next; if (!(item->pevIndex <= startEntityIndex)) break; } if (item->pevIndex == startEntityIndex) { stringsHashTable[hash].lastHash = NULL; return NULL; } } stringsHashTable[hash].lastHash = item; pentEntity = ENT(item->pev); } if (!FNullEnt(pentEntity)) return CBaseEntity::Instance(pentEntity); return NULL; } CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName) { return UTIL_FindEntityByString(pStartEntity, "classname", szName); } CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName) { return UTIL_FindEntityByString(pStartEntity, "targetname", szName); } CBaseEntity *UTIL_FindEntityGeneric(const char *szWhatever, Vector &vecSrc, float flRadius) { CBaseEntity *pEntity = UTIL_FindEntityByTargetname(NULL, szWhatever); if (pEntity) return pEntity; CBaseEntity *pSearch = NULL; float flMaxDist2 = flRadius * flRadius; while ((pSearch = UTIL_FindEntityByClassname(pSearch, szWhatever)) != NULL) { float flDist2 = (pSearch->pev->origin - vecSrc).Length(); flDist2 = flDist2 * flDist2; if (flMaxDist2 > flDist2) { pEntity = pSearch; flMaxDist2 = flDist2; } } return pEntity; } CBaseEntity *UTIL_PlayerByIndex(int playerIndex) { CBaseEntity *pPlayer = NULL; if (playerIndex > 0 && playerIndex <= gpGlobals->maxClients) { edict_t *pPlayerEdict = INDEXENT(playerIndex); if (pPlayerEdict && !pPlayerEdict->free) pPlayer = CBaseEntity::Instance(pPlayerEdict); } return pPlayer; } void UTIL_MakeVectors(const Vector &vecAngles) { MAKE_VECTORS(vecAngles); } void UTIL_MakeAimVectors(const Vector &vecAngles) { float rgflVec[3]; vecAngles.CopyToArray(rgflVec); rgflVec[0] = -rgflVec[0]; MAKE_VECTORS(rgflVec); } #define SWAP(a, b, temp) ((temp)=(a),(a)=(b),(b)=(temp)) void UTIL_MakeInvVectors(const Vector &vec, globalvars_t *pgv) { MAKE_VECTORS(vec); float tmp; pgv->v_right = pgv->v_right * -1; SWAP(pgv->v_forward.y, pgv->v_right.x, tmp); SWAP(pgv->v_forward.z, pgv->v_up.x, tmp); SWAP(pgv->v_right.z, pgv->v_up.y, tmp); } void UTIL_EmitAmbientSound(edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch) { float rgfl[3]; vecOrigin.CopyToArray(rgfl); if (samp && *samp == '!') { char name[32]; if (SENTENCEG_Lookup(samp, name) >= 0) EMIT_AMBIENT_SOUND(entity, rgfl, name, vol, attenuation, fFlags, pitch); } else EMIT_AMBIENT_SOUND(entity, rgfl, samp, vol, attenuation, fFlags, pitch); } static unsigned short FixedUnsigned16(float value, float scale) { int output = (int)(value * scale); if (output < 0) output = 0; if (output > 0xFFFF) output = 0xFFFF; return (unsigned short)output; } static short FixedSigned16(float value, float scale) { int output = (int)(value * scale); if (output > 32767) output = 32767; if (output < -32768) output = -32768; return (short)output; } void UTIL_ScreenShake(const Vector ¢er, float amplitude, float frequency, float duration, float radius) { ScreenShake shake; shake.duration = FixedUnsigned16(duration, 1 << 12); shake.frequency = FixedUnsigned16(frequency, 1 << 8); for (int i = 1; i <= gpGlobals->maxClients; i++) { CBaseEntity *pPlayer = UTIL_PlayerByIndex(i); if (!pPlayer || !(pPlayer->pev->flags & FL_ONGROUND)) continue; float localAmplitude = 0; if (radius > 0) { Vector delta = center - pPlayer->pev->origin; float distance = delta.Length(); if (distance < radius) localAmplitude = amplitude; } else localAmplitude = amplitude; if (localAmplitude) { shake.amplitude = FixedUnsigned16(localAmplitude, 1 << 12); MESSAGE_BEGIN(MSG_ONE, gmsgShake, NULL, pPlayer->edict()); WRITE_SHORT(shake.amplitude); WRITE_SHORT(shake.duration); WRITE_SHORT(shake.frequency); MESSAGE_END(); } } } void UTIL_ScreenShakeAll(const Vector ¢er, float amplitude, float frequency, float duration) { UTIL_ScreenShake(center, amplitude, frequency, duration, 0); } void UTIL_ScreenFadeBuild(ScreenFade &fade, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags) { fade.duration = FixedUnsigned16(fadeTime, 1 << 12); fade.holdTime = FixedUnsigned16(fadeHold, 1 << 12); fade.r = (int)color.x; fade.g = (int)color.y; fade.b = (int)color.z; fade.a = alpha; fade.fadeFlags = flags; } void UTIL_ScreenFadeWrite(const ScreenFade &fade, CBaseEntity *pEntity) { if (!pEntity || !pEntity->IsNetClient()) return; MESSAGE_BEGIN(MSG_ONE, gmsgFade, NULL, pEntity->edict()); WRITE_SHORT(fade.duration); WRITE_SHORT(fade.holdTime); WRITE_SHORT(fade.fadeFlags); WRITE_BYTE(fade.r); WRITE_BYTE(fade.g); WRITE_BYTE(fade.b); WRITE_BYTE(fade.a); MESSAGE_END(); } void UTIL_ScreenFadeAll(const Vector &color, float fadeTime, float fadeHold, int alpha, int flags) { ScreenFade fade; UTIL_ScreenFadeBuild(fade, color, fadeTime, fadeHold, alpha, flags); for (int i = 1; i <= gpGlobals->maxClients; i++) { CBaseEntity *pPlayer = UTIL_PlayerByIndex(i); UTIL_ScreenFadeWrite(fade, pPlayer); } } void UTIL_ScreenFade(CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags) { ScreenFade fade; UTIL_ScreenFadeBuild(fade, color, fadeTime, fadeHold, alpha, flags); UTIL_ScreenFadeWrite(fade, pEntity); } void UTIL_HudMessage(CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage) { if (!pEntity || !pEntity->IsNetClient()) return; MESSAGE_BEGIN(MSG_ONE, SVC_TEMPENTITY, NULL, pEntity->edict()); WRITE_BYTE(TE_TEXTMESSAGE); WRITE_BYTE(textparms.channel & 0xFF); WRITE_SHORT(FixedSigned16(textparms.x, 1 << 13)); WRITE_SHORT(FixedSigned16(textparms.y, 1 << 13)); WRITE_BYTE(textparms.effect); WRITE_BYTE(textparms.r1); WRITE_BYTE(textparms.g1); WRITE_BYTE(textparms.b1); WRITE_BYTE(textparms.a1); WRITE_BYTE(textparms.r2); WRITE_BYTE(textparms.g2); WRITE_BYTE(textparms.b2); WRITE_BYTE(textparms.a2); WRITE_SHORT(FixedUnsigned16(textparms.fadeinTime, 1 << 8)); WRITE_SHORT(FixedUnsigned16(textparms.fadeoutTime, 1 << 8)); WRITE_SHORT(FixedUnsigned16(textparms.holdTime, 1 << 8)); if (textparms.effect == 2) WRITE_SHORT(FixedUnsigned16(textparms.fxTime, 1 << 8)); if (strlen(pMessage) >= 512) { char tmp[512]; strncpy(tmp, pMessage, 511); tmp[511] = '\0'; WRITE_STRING(tmp); } else WRITE_STRING(pMessage); MESSAGE_END(); } void UTIL_HudMessageAll(const hudtextparms_t &textparms, const char *pMessage) { for (int i = 1; i <= gpGlobals->maxClients; i++) { CBaseEntity *pPlayer = UTIL_PlayerByIndex(i); if (pPlayer) UTIL_HudMessage(pPlayer, textparms, pMessage); } } extern int gmsgTextMsg, gmsgSayText; void UTIL_ClientPrintAll(int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4) { MESSAGE_BEGIN(MSG_ALL, gmsgTextMsg); WRITE_BYTE(msg_dest); WRITE_STRING(msg_name); if (param1) WRITE_STRING(param1); if (param2) WRITE_STRING(param2); if (param3) WRITE_STRING(param3); if (param4) WRITE_STRING(param4); MESSAGE_END(); } void ClientPrint(entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4) { MESSAGE_BEGIN(MSG_ONE, gmsgTextMsg, NULL, client); WRITE_BYTE(msg_dest); WRITE_STRING(msg_name); if (param1) WRITE_STRING(param1); if (param2) WRITE_STRING(param2); if (param3) WRITE_STRING(param3); if (param4) WRITE_STRING(param4); MESSAGE_END(); } void UTIL_SayText(const char *pText, CBaseEntity *pEntity) { if (!pEntity->IsNetClient()) return; MESSAGE_BEGIN(MSG_ONE, gmsgSayText, NULL, pEntity->edict()); WRITE_BYTE(pEntity->entindex()); WRITE_STRING(pText); MESSAGE_END(); } void UTIL_SayTextAll(const char *pText, CBaseEntity *pEntity) { MESSAGE_BEGIN(MSG_ALL, gmsgSayText, NULL); WRITE_BYTE(pEntity->entindex()); WRITE_STRING(pText); MESSAGE_END(); } char *UTIL_dtos1(int d) { static char buf[8]; sprintf(buf, "%d", d); return buf; } char *UTIL_dtos2(int d) { static char buf[8]; sprintf(buf, "%d", d); return buf; } char *UTIL_dtos3(int d) { static char buf[8]; sprintf(buf, "%d", d); return buf; } char *UTIL_dtos4(int d) { static char buf[8]; sprintf(buf, "%d", d); return buf; } extern int gmsgHudTextArgs; extern int gmsgHudText; void UTIL_ShowMessageArgs(const char *pString, CBaseEntity *pPlayer, CUtlVector *args, bool isHint) { if (!pPlayer) return; if (!pPlayer->IsNetClient()) return; if (args) { MESSAGE_BEGIN(MSG_ONE, gmsgHudTextArgs, NULL, pPlayer->pev); WRITE_STRING(pString); WRITE_BYTE(isHint); WRITE_BYTE(args->Count()); for (int i = 0; i < args->Count(); i++) WRITE_STRING((*args)[i]); MESSAGE_END(); } else { MESSAGE_BEGIN(MSG_ONE, gmsgHudText, NULL, pPlayer->pev); WRITE_STRING(pString); WRITE_BYTE(isHint); MESSAGE_END(); } } void UTIL_ShowMessage(const char *pString, CBaseEntity *pEntity) { if (!pEntity || !pEntity->IsNetClient()) return; MESSAGE_BEGIN(MSG_ONE, gmsgHudText, NULL, pEntity->edict()); WRITE_STRING(pString); MESSAGE_END(); } void UTIL_ShowMessageAll(const char *pString) { for (int i = 1; i <= gpGlobals->maxClients; i++) { CBaseEntity *pPlayer = UTIL_PlayerByIndex(i); if (pPlayer) UTIL_ShowMessage(pString, pPlayer); } } 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); } void UTIL_TraceHull(const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr) { TRACE_HULL(vecStart, vecEnd, (igmon == ignore_monsters ? TRUE : FALSE), hullNumber, pentIgnore, ptr); } void UTIL_TraceModel(const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr) { g_engfuncs.pfnTraceModel(vecStart, vecEnd, hullNumber, pentModel, ptr); } TraceResult UTIL_GetGlobalTrace(void) { TraceResult tr; tr.fAllSolid = (int)gpGlobals->trace_allsolid; tr.fStartSolid = (int)gpGlobals->trace_startsolid; tr.fInOpen = (int)gpGlobals->trace_inopen; tr.fInWater = (int)gpGlobals->trace_inwater; tr.flFraction = gpGlobals->trace_fraction; tr.flPlaneDist = gpGlobals->trace_plane_dist; tr.pHit = gpGlobals->trace_ent; tr.vecEndPos = gpGlobals->trace_endpos; tr.vecPlaneNormal = gpGlobals->trace_plane_normal; tr.iHitgroup = gpGlobals->trace_hitgroup; return tr; } void UTIL_SetSize(entvars_t *pev, const Vector &vecMin, const Vector &vecMax) { SET_SIZE(ENT(pev), vecMin, vecMax); } float UTIL_VecToYaw(const Vector &vec) { return VEC_TO_YAW(vec); } void UTIL_SetOrigin(entvars_t *pev, const Vector &vecOrigin) { SET_ORIGIN(ENT(pev), vecOrigin); } void UTIL_ParticleEffect(const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount) { PARTICLE_EFFECT(vecOrigin, vecDirection, (float)ulColor, (float)ulCount); } float UTIL_Approach(float target, float value, float speed) { float delta = target - value; if (delta > speed) value += speed; else if (delta < -speed) value -= speed; else value = target; return value; } float UTIL_ApproachAngle(float target, float value, float speed) { target = UTIL_AngleMod(target); value = UTIL_AngleMod(target); float delta = target - value; if (speed < 0) speed = -speed; if (delta < -180) delta += 360; else if (delta > 180) delta -= 360; if (delta > speed) value += speed; else if (delta < -speed) value -= speed; else value = target; return value; } float UTIL_AngleDistance(float next, float cur) { float delta = next - cur; if (delta < -180) delta += 360; else if (delta > 180) delta -= 360; return delta; } float UTIL_SplineFraction(float value, float scale) { value = scale * value; float valueSquared = value * value; return 3 * valueSquared - 2 * valueSquared * value; } char *UTIL_VarArgs(char *format, ...) { va_list argptr; static char string[1024]; va_start(argptr, format); vsprintf(string, format, argptr); va_end(argptr); return string; } Vector UTIL_GetAimVector(edict_t *pent, float flSpeed) { Vector tmp; GET_AIM_VECTOR(pent, flSpeed, tmp); return tmp; } int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator) { if (sMaster) { edict_t *pentTarget = FIND_ENTITY_BY_TARGETNAME(NULL, STRING(sMaster)); if (!FNullEnt(pentTarget)) { CBaseEntity *pMaster = CBaseEntity::Instance(pentTarget); if (pMaster && (pMaster->ObjectCaps() & FCAP_MASTER)) return pMaster->IsTriggered(pActivator); } ALERT(at_console, "Master was null or not a master!\n"); } return 1; } BOOL UTIL_ShouldShowBlood(int color) { if (color != DONT_BLEED) { if (color == BLOOD_COLOR_RED) { if (CVAR_GET_FLOAT("violence_hblood") != 0) return TRUE; } else { if (CVAR_GET_FLOAT("violence_ablood") != 0) return TRUE; } } return FALSE; } int UTIL_PointContents(const Vector &vec) { return POINT_CONTENTS(vec); } void UTIL_BloodStream(const Vector &origin, const Vector &direction, int color, int amount) { if (!UTIL_ShouldShowBlood(color)) return; if (g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED) color = 0; MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin); WRITE_BYTE(TE_BLOODSTREAM); WRITE_COORD(origin.x); WRITE_COORD(origin.y); WRITE_COORD(origin.z); WRITE_COORD(direction.x); WRITE_COORD(direction.y); WRITE_COORD(direction.z); WRITE_BYTE(color); WRITE_BYTE(min(amount, 255)); MESSAGE_END(); } void UTIL_BloodDrips(const Vector &origin, const Vector &direction, int color, int amount) { if (!UTIL_ShouldShowBlood(color)) return; if (color == DONT_BLEED || !amount) return; if (g_Language == LANGUAGE_GERMAN && color == BLOOD_COLOR_RED) color = 0; if (g_pGameRules->IsMultiplayer()) amount *= 2; if (amount > 255) amount = 255; MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin); WRITE_BYTE(TE_BLOODSPRITE); WRITE_COORD(origin.x); WRITE_COORD(origin.y); WRITE_COORD(origin.z); WRITE_SHORT(g_sModelIndexBloodSpray); WRITE_SHORT(g_sModelIndexBloodDrop); WRITE_BYTE(color); WRITE_BYTE(min(max(3, amount / 10), 16)); MESSAGE_END(); } Vector UTIL_RandomBloodVector(void) { Vector direction; direction.x = RANDOM_FLOAT(-1, 1); direction.y = RANDOM_FLOAT(-1, 1); direction.z = RANDOM_FLOAT(0, 1); return direction; } void UTIL_BloodDecalTrace(TraceResult *pTrace, int bloodColor) { if (UTIL_ShouldShowBlood(bloodColor)) { if (bloodColor == BLOOD_COLOR_RED) UTIL_DecalTrace(pTrace, DECAL_BLOOD1 + RANDOM_LONG(0, 5)); else UTIL_DecalTrace(pTrace, DECAL_YBLOOD1 + RANDOM_LONG(0, 5)); } } void UTIL_DecalTrace(TraceResult *pTrace, int decalNumber) { if (decalNumber < 0) return; int index = gDecals[decalNumber].index; if (index < 0) return; if (pTrace->flFraction == 1) return; short entityIndex; if (pTrace->pHit) { CBaseEntity *pEntity = CBaseEntity::Instance(pTrace->pHit); if (pEntity && !pEntity->IsBSPModel()) return; entityIndex = ENTINDEX(pTrace->pHit); } else entityIndex = 0; int 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_PlayerDecalTrace(TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom) { int index; if (!bIsCustom) { if (decalNumber < 0) return; index = gDecals[decalNumber].index; if (index < 0) return; } else index = decalNumber; if (pTrace->flFraction == 1) return; MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); WRITE_BYTE(TE_PLAYERDECAL); WRITE_BYTE(playernum); WRITE_COORD(pTrace->vecEndPos.x); WRITE_COORD(pTrace->vecEndPos.y); WRITE_COORD(pTrace->vecEndPos.z); WRITE_SHORT((short)ENTINDEX(pTrace->pHit)); WRITE_BYTE(index); MESSAGE_END(); } void UTIL_GunshotDecalTrace(TraceResult *pTrace, int decalNumber) { if (decalNumber < 0) return; int index = gDecals[decalNumber].index; if (index < 0) return; if (pTrace->flFraction == 1) return; MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, pTrace->vecEndPos); WRITE_BYTE(TE_GUNSHOTDECAL); WRITE_COORD(pTrace->vecEndPos.x); WRITE_COORD(pTrace->vecEndPos.y); WRITE_COORD(pTrace->vecEndPos.z); WRITE_SHORT((short)ENTINDEX(pTrace->pHit)); WRITE_BYTE(index); MESSAGE_END(); } void UTIL_Sparks(const Vector &position) { MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, position); WRITE_BYTE(TE_SPARKS); WRITE_COORD(position.x); WRITE_COORD(position.y); WRITE_COORD(position.z); MESSAGE_END(); } void UTIL_Ricochet(const Vector &position, float scale) { MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, position); WRITE_BYTE(TE_ARMOR_RICOCHET); WRITE_COORD(position.x); WRITE_COORD(position.y); WRITE_COORD(position.z); WRITE_BYTE((int)(scale * 10)); MESSAGE_END(); } BOOL UTIL_TeamsMatch(const char *pTeamName1, const char *pTeamName2) { if (!g_pGameRules->IsTeamplay()) return TRUE; if (*pTeamName1 != '\0' && *pTeamName2 != '\0') { if (!stricmp(pTeamName1, pTeamName2)) return TRUE; } return FALSE; } void UTIL_StringToVector(float *pVector, const char *pString) { char *pstr, *pfront, tempString[128]; strcpy(tempString, pString); pstr = pfront = tempString; int j = 0; for (; j < 3; j++) { pVector[j] = atof(pfront); while (*pstr && *pstr != ' ') pstr++; if (!*pstr) break; pstr++; pfront = pstr; } if (j < 2) { for (j = j + 1;j < 3; j++) pVector[j] = 0; } } void UTIL_StringToIntArray(int *pVector, int count, const char *pString) { char *pstr, *pfront, tempString[128]; strcpy(tempString, pString); pstr = pfront = tempString; int j = 0; for (j = 0; j < count; j++) { pVector[j] = atoi(pfront); while (*pstr && *pstr != ' ') pstr++; if (!*pstr) break; pstr++; pfront = pstr; } for (j++; j < count; j++) pVector[j] = 0; } Vector UTIL_ClampVectorToBox(const Vector &input, const Vector &clampSize) { Vector sourceVector = input; if (sourceVector.x > clampSize.x) sourceVector.x -= clampSize.x; else if (sourceVector.x < -clampSize.x) sourceVector.x += clampSize.x; else sourceVector.x = 0; if (sourceVector.y > clampSize.y) sourceVector.y -= clampSize.y; else if (sourceVector.y < -clampSize.y) sourceVector.y += clampSize.y; else sourceVector.y = 0; if (sourceVector.z > clampSize.z) sourceVector.z -= clampSize.z; else if (sourceVector.z < -clampSize.z) sourceVector.z += clampSize.z; else sourceVector.z = 0; return sourceVector.Normalize(); } float UTIL_WaterLevel(const Vector &position, float minz, float maxz) { Vector midUp = position; midUp.z = minz; if (UTIL_PointContents(midUp) != CONTENTS_WATER) return minz; midUp.z = maxz; if (UTIL_PointContents(midUp) == CONTENTS_WATER) return maxz; float diff = maxz - minz; while (diff > 1) { midUp.z = minz + diff / 2; if (UTIL_PointContents(midUp) == CONTENTS_WATER) minz = midUp.z; else maxz = midUp.z; diff = maxz - minz; } return midUp.z; } extern DLL_GLOBAL short g_sModelIndexBubbles; void UTIL_Bubbles(Vector mins, Vector maxs, int count) { Vector mid = (mins + maxs) * 0.5; float flHeight = UTIL_WaterLevel(mid, mid.z, mid.z + 1024); flHeight = flHeight - mins.z; MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, mid); WRITE_BYTE(TE_BUBBLES); WRITE_COORD(mins.x); WRITE_COORD(mins.y); WRITE_COORD(mins.z); WRITE_COORD(maxs.x); WRITE_COORD(maxs.y); WRITE_COORD(maxs.z); WRITE_COORD(flHeight); WRITE_SHORT(g_sModelIndexBubbles); WRITE_BYTE(count); WRITE_COORD(8); MESSAGE_END(); } void UTIL_BubbleTrail(Vector from, Vector to, int count) { float flHeight = UTIL_WaterLevel(from, from.z, from.z + 256) - from.z; if (flHeight < 8) { flHeight = UTIL_WaterLevel(to, to.z, to.z + 256) - to.z; if (flHeight < 8) return; flHeight = flHeight + to.z - from.z; } if (count > 255) count = 255; MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY); WRITE_BYTE(TE_BUBBLETRAIL); WRITE_COORD(from.x); WRITE_COORD(from.y); WRITE_COORD(from.z); WRITE_COORD(to.x); WRITE_COORD(to.y); WRITE_COORD(to.z); WRITE_COORD(flHeight); WRITE_SHORT(g_sModelIndexBubbles); WRITE_BYTE(count); WRITE_COORD(8); MESSAGE_END(); } void UTIL_Remove(CBaseEntity *pEntity) { if (!pEntity) return; pEntity->UpdateOnRemove(); pEntity->pev->flags |= FL_KILLME; pEntity->pev->targetname = 0; } BOOL UTIL_IsValidEntity(edict_t *pent) { if (!pent || pent->free || (pent->v.flags & FL_KILLME)) return FALSE; return TRUE; } void UTIL_PrecacheOther(const char *szClassname) { edict_t *pent = CREATE_NAMED_ENTITY(MAKE_STRING(szClassname)); if (FNullEnt(pent)) { ALERT(at_console, "NULL Ent in UTIL_PrecacheOther\n"); return; } CBaseEntity *pEntity = CBaseEntity::Instance(VARS(pent)); if (pEntity) pEntity->Precache(); REMOVE_ENTITY(pent); } void UTIL_LogPrintf(char *fmt, ...) { va_list argptr; static char string[1024]; memset(string, 0, sizeof(string)); va_start(argptr, fmt); vsnprintf(string, 1023, fmt, argptr); va_end(argptr); ALERT(at_logged, "%s", string); } float UTIL_DotPoints(const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir) { Vector2D vec2LOS = (vecCheck - vecSrc).Make2D(); vec2LOS = vec2LOS.Normalize(); return DotProduct(vec2LOS, (vecDir.Make2D())); } void UTIL_StripToken(const char *pKey, char *pDest) { int i = 0; while (pKey[i] && pKey[i] != '#') { pDest[i] = pKey[i]; i++; } pDest[i] = 0; } static int gSizes[FIELD_TYPECOUNT] = { sizeof(float), // FIELD_FLOAT sizeof(int), // FIELD_STRING sizeof(int), // FIELD_ENTITY sizeof(int), // FIELD_CLASSPTR sizeof(int), // FIELD_EHANDLE sizeof(int), // FIELD_entvars_t sizeof(int), // FIELD_EDICT sizeof(float) * 3, // FIELD_VECTOR sizeof(float) * 3, // FIELD_POSITION_VECTOR sizeof(int *), // FIELD_POINTER sizeof(int), // FIELD_INTEGER sizeof(int *), // FIELD_FUNCTION sizeof(int), // FIELD_BOOLEAN sizeof(short), // FIELD_SHORT sizeof(char), // FIELD_CHARACTER sizeof(float), // FIELD_TIME sizeof(int), // FIELD_MODELNAME sizeof(int), // FIELD_SOUNDNAME }; CSaveRestoreBuffer::CSaveRestoreBuffer(void) { m_pdata = NULL; } CSaveRestoreBuffer::CSaveRestoreBuffer(SAVERESTOREDATA *pdata) { m_pdata = pdata; } CSaveRestoreBuffer::~CSaveRestoreBuffer(void) { } int CSaveRestoreBuffer::EntityIndex(CBaseEntity *pEntity) { if (!pEntity) return -1; return EntityIndex(pEntity->pev); } int CSaveRestoreBuffer::EntityIndex(entvars_t *pevLookup) { if (!pevLookup) return -1; return EntityIndex(ENT(pevLookup)); } int CSaveRestoreBuffer::EntityIndex(EOFFSET eoLookup) { return EntityIndex(ENT(eoLookup)); } int CSaveRestoreBuffer::EntityIndex(edict_t *pentLookup) { if (!m_pdata || !pentLookup) return -1; for (int i = 0; i < m_pdata->tableCount; i++) { ENTITYTABLE *pTable = m_pdata->pTable + i; if (pTable->pent == pentLookup) return i; } return -1; } edict_t *CSaveRestoreBuffer::EntityFromIndex(int entityIndex) { if (!m_pdata || entityIndex < 0) return NULL; for (int i = 0; i < m_pdata->tableCount; i++) { ENTITYTABLE *pTable = m_pdata->pTable + i; if (pTable->id == entityIndex) return pTable->pent; } return NULL; } int CSaveRestoreBuffer::EntityFlagsSet(int entityIndex, int flags) { if (!m_pdata || entityIndex < 0) return 0; if (entityIndex > m_pdata->tableCount) return 0; m_pdata->pTable[entityIndex].flags |= flags; return m_pdata->pTable[entityIndex].flags; } void CSaveRestoreBuffer::BufferRewind(int size) { if (!m_pdata) return; if (m_pdata->size < size) size = m_pdata->size; m_pdata->pCurrentData -= size; m_pdata->size -= size; } #ifndef _WIN32 extern "C" { unsigned _rotr(unsigned val, int shift) { register unsigned lobit; register unsigned num = val; shift &= 0x1F; while (shift--) { lobit = num & 1; num >>= 1; if (lobit) num |= 0x80000000; } return num; } } #endif unsigned int CSaveRestoreBuffer::HashString(const char *pszToken) { unsigned int hash = 0; while (*pszToken) hash = _rotr(hash, 4) ^ *pszToken++; return hash; } unsigned short CSaveRestoreBuffer::TokenHash(const char *pszToken) { unsigned short hash = (unsigned short)(HashString(pszToken) % (unsigned)m_pdata->tokenCount); for (int i = 0; i < m_pdata->tokenCount; i++) { int index = hash + i; if (index >= m_pdata->tokenCount) index -= m_pdata->tokenCount; if (!m_pdata->pTokens[index] || !strcmp(pszToken, m_pdata->pTokens[index])) { m_pdata->pTokens[index] = (char *)pszToken; return index; } } ALERT(at_error, "CSaveRestoreBuffer :: TokenHash() is COMPLETELY FULL!"); return 0; } void CSave::WriteData(const char *pname, int size, const char *pdata) { BufferField(pname, size, pdata); } void CSave::WriteShort(const char *pname, const short *data, int count) { BufferField(pname, sizeof(short) * count, (const char *)data); } void CSave::WriteInt(const char *pname, const int *data, int count) { BufferField(pname, sizeof(int) * count, (const char *)data); } void CSave::WriteFloat(const char *pname, const float *data, int count) { BufferField(pname, sizeof(float) * count, (const char *)data); } void CSave::WriteTime(const char *pname, const float *data, int count) { BufferHeader(pname, sizeof(float) * count); for (int i = 0; i < count; i++) { float tmp = data[0]; if (m_pdata) tmp -= m_pdata->time; BufferData((const char *)&tmp, sizeof(float)); data++; } } void CSave::WriteString(const char *pname, const char *pdata) { BufferField(pname, strlen(pdata) + 1, pdata); } void CSave::WriteString(const char *pname, const int *stringId, int count) { int i; int size = 0; for (i = 0; i < count; i++) size += strlen(STRING(stringId[i])) + 1; BufferHeader(pname, size); for (i = 0; i < count; i++) { const char *pString = STRING(stringId[i]); BufferData(pString, strlen(pString)+1); } } void CSave::WriteVector(const char *pname, const Vector &value) { WriteVector(pname, &value.x, 1); } void CSave::WriteVector(const char *pname, const float *value, int count) { BufferHeader(pname, sizeof(float) * 3 * count); BufferData((const char *)value, sizeof(float) * 3 * count); } void CSave::WritePositionVector(const char *pname, const Vector &value) { if (m_pdata && m_pdata->fUseLandmark) { Vector tmp = value - m_pdata->vecLandmarkOffset; WriteVector(pname, tmp); } WriteVector(pname, value); } void CSave::WritePositionVector(const char *pname, const float *value, int count) { BufferHeader(pname, sizeof(float) * 3 * count); for (int i = 0; i < count; i++) { Vector tmp(value[0], value[1], value[2]); if (m_pdata && m_pdata->fUseLandmark) tmp = tmp - m_pdata->vecLandmarkOffset; BufferData((const char *)&tmp.x, sizeof(float) * 3); value += 3; } } void CSave::WriteFunction(const char *pname, const int *data, int count) { const char *functionName = NAME_FOR_FUNCTION(*data); if (functionName) BufferField(pname, strlen(functionName) + 1, functionName); else ALERT(at_error, "Invalid function pointer in entity!"); } void EntvarsKeyvalue(entvars_t *pev, KeyValueData *pkvd) { for (int i = 0; i < (int)(ENTVARS_COUNT); i++) { TYPEDESCRIPTION *pField = &gEntvarsDescription[i]; if (!stricmp(pField->fieldName, pkvd->szKeyName)) { switch (pField->fieldType) { case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: (*(int *)((char *)pev + pField->fieldOffset)) = ALLOC_STRING(pkvd->szValue); break; case FIELD_TIME: case FIELD_FLOAT: (*(float *)((char *)pev + pField->fieldOffset)) = atof(pkvd->szValue); break; case FIELD_INTEGER: (*(int *)((char *)pev + pField->fieldOffset)) = atoi(pkvd->szValue); break; case FIELD_POSITION_VECTOR: case FIELD_VECTOR: UTIL_StringToVector((float *)((char *)pev + pField->fieldOffset), pkvd->szValue); break; default: case FIELD_EVARS: case FIELD_CLASSPTR: case FIELD_EDICT: case FIELD_ENTITY: case FIELD_POINTER: ALERT(at_error, "Bad field in entity!!\n"); break; } pkvd->fHandled = TRUE; return; } } } int CSave::WriteEntVars(const char *pname, entvars_t *pev) { return WriteFields(pname, pev, gEntvarsDescription, ENTVARS_COUNT); } int CSave::WriteFields(const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount) { int i; int emptyCount = 0; for (i = 0; i < fieldCount; i++) { void *pOutputData = ((char *)pBaseData + pFields[i].fieldOffset); if (DataEmpty((const char *)pOutputData, pFields[i].fieldSize * gSizes[pFields[i].fieldType])) emptyCount++; } int entityArray[MAX_ENTITYARRAY]; int actualCount = fieldCount - emptyCount; WriteInt(pname, &actualCount, 1); for (i = 0; i < fieldCount; i++) { TYPEDESCRIPTION *pTest = &pFields[i]; void *pOutputData = ((char *)pBaseData + pTest->fieldOffset); if (DataEmpty((const char *)pOutputData, pTest->fieldSize * gSizes[pTest->fieldType])) continue; switch (pTest->fieldType) { case FIELD_FLOAT: WriteFloat(pTest->fieldName, (float *)pOutputData, pTest->fieldSize); break; case FIELD_TIME: WriteTime(pTest->fieldName, (float *)pOutputData, pTest->fieldSize); break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: WriteString(pTest->fieldName, (int *)pOutputData, pTest->fieldSize); break; case FIELD_CLASSPTR: case FIELD_EVARS: case FIELD_EDICT: case FIELD_ENTITY: case FIELD_EHANDLE: { if (pTest->fieldSize > MAX_ENTITYARRAY) ALERT(at_error, "Can't save more than %d entities in an array!!!\n", MAX_ENTITYARRAY); for (int j = 0; j < pTest->fieldSize; j++) { switch (pTest->fieldType) { case FIELD_EVARS: entityArray[j] = EntityIndex(((entvars_t **)pOutputData)[j]); break; case FIELD_CLASSPTR: entityArray[j] = EntityIndex(((CBaseEntity **)pOutputData)[j]); break; case FIELD_EDICT: entityArray[j] = EntityIndex(((edict_t **)pOutputData)[j]); break; case FIELD_ENTITY: entityArray[j] = EntityIndex(((EOFFSET *)pOutputData)[j]); break; case FIELD_EHANDLE: entityArray[j] = EntityIndex((CBaseEntity *)(((EHANDLE *)pOutputData)[j])); break; default: break; } } WriteInt(pTest->fieldName, entityArray, pTest->fieldSize); break; } case FIELD_POSITION_VECTOR: WritePositionVector(pTest->fieldName, (float *)pOutputData, pTest->fieldSize); break; case FIELD_VECTOR: WriteVector(pTest->fieldName, (float *)pOutputData, pTest->fieldSize); break; case FIELD_BOOLEAN: case FIELD_INTEGER: WriteInt(pTest->fieldName, (int *)pOutputData, pTest->fieldSize); break; case FIELD_SHORT: WriteData(pTest->fieldName, 2 * pTest->fieldSize, ((char *)pOutputData)); break; case FIELD_CHARACTER: WriteData(pTest->fieldName, pTest->fieldSize, ((char *)pOutputData)); break; case FIELD_POINTER: WriteInt(pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize); break; case FIELD_FUNCTION: WriteFunction(pTest->fieldName, (int *)(char *)pOutputData, pTest->fieldSize); break; default: ALERT(at_error, "Bad field type\n"); } } return 1; } void CSave::BufferString(char *pdata, int len) { char c = 0; BufferData(pdata, len); BufferData(&c, 1); } int CSave::DataEmpty(const char *pdata, int size) { for (int i = 0; i < size; i++) { if (pdata[i]) return 0; } return 1; } void CSave::BufferField(const char *pname, int size, const char *pdata) { BufferHeader(pname, size); BufferData(pdata, size); } void CSave::BufferHeader(const char *pname, int size) { short hashvalue = TokenHash(pname); if (size > 1 << (sizeof(short) * 8)) ALERT(at_error, "CSave :: BufferHeader() size parameter exceeds 'short'!"); BufferData((const char *)&size, sizeof(short)); BufferData((const char *)&hashvalue, sizeof(short)); } void CSave::BufferData(const char *pdata, int size) { if (!m_pdata) return; if (m_pdata->size + size > m_pdata->bufferSize) { ALERT(at_error, "Save/Restore overflow!"); m_pdata->size = m_pdata->bufferSize; return; } memcpy(m_pdata->pCurrentData, pdata, size); m_pdata->pCurrentData += size; m_pdata->size += size; } int CRestore::ReadField(void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount, int startField, int size, char *pName, void *pData) { float time = 0; Vector position = Vector(0, 0, 0); if (m_pdata) { time = m_pdata->time; if (m_pdata->fUseLandmark) position = m_pdata->vecLandmarkOffset; } for (int i = 0; i < fieldCount; i++) { int fieldNumber = (i + startField) % fieldCount; TYPEDESCRIPTION *pTest = &pFields[fieldNumber]; if (!stricmp(pTest->fieldName, pName)) { if (!m_global || !(pTest->flags & FTYPEDESC_GLOBAL)) { for (int j = 0; j < pTest->fieldSize; j++) { void *pOutputData = ((char *)pBaseData + pTest->fieldOffset + (j * gSizes[pTest->fieldType])); void *pInputData = (char *)pData + j * gSizes[pTest->fieldType]; switch (pTest->fieldType) { case FIELD_TIME: { float timeData = *(float *)pInputData; timeData += time; *((float *)pOutputData) = timeData; break; } case FIELD_FLOAT: *((float *)pOutputData) = *(float *)pInputData; break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: { char *pString = (char *)pData; for (int stringCount = 0; stringCount < j; stringCount++) { while (*pString) pString++; pString++; } pInputData = pString; if (!strlen((char *)pInputData)) *((int *)pOutputData) = 0; else { int string = ALLOC_STRING((char *)pInputData); *((int *)pOutputData) = string; if (!FStringNull(string) && m_precache) { if (pTest->fieldType == FIELD_MODELNAME) PRECACHE_MODEL((char *)STRING(string)); else if (pTest->fieldType == FIELD_SOUNDNAME) PRECACHE_SOUND((char *)STRING(string)); } } break; } case FIELD_EVARS: { int entityIndex = *(int *)pInputData; edict_t *pent = EntityFromIndex(entityIndex); if (pent) *((entvars_t **)pOutputData) = VARS(pent); else *((entvars_t **)pOutputData) = NULL; break; } case FIELD_CLASSPTR: { int entityIndex = *(int *)pInputData; edict_t *pent = EntityFromIndex(entityIndex); if (pent) *((CBaseEntity **)pOutputData) = CBaseEntity::Instance(pent); else *((CBaseEntity **)pOutputData) = NULL; break; } case FIELD_EDICT: { int entityIndex = *(int *)pInputData; edict_t *pent = EntityFromIndex(entityIndex); *((edict_t **)pOutputData) = pent; break; } case FIELD_EHANDLE: { pOutputData = (char *)pOutputData + j * (sizeof(EHANDLE) - gSizes[pTest->fieldType]); int entityIndex = *(int *)pInputData; edict_t *pent = EntityFromIndex(entityIndex); if (pent) *((EHANDLE *)pOutputData) = CBaseEntity::Instance(pent); else *((EHANDLE *)pOutputData) = NULL; break; } case FIELD_ENTITY: { int entityIndex = *(int *)pInputData; edict_t *pent = EntityFromIndex(entityIndex); if (pent) *((EOFFSET *)pOutputData) = OFFSET(pent); else *((EOFFSET *)pOutputData) = 0; break; } case FIELD_VECTOR: { ((float *)pOutputData)[0] = ((float *)pInputData)[0]; ((float *)pOutputData)[1] = ((float *)pInputData)[1]; ((float *)pOutputData)[2] = ((float *)pInputData)[2]; break; } case FIELD_POSITION_VECTOR: { ((float *)pOutputData)[0] = ((float *)pInputData)[0] + position.x; ((float *)pOutputData)[1] = ((float *)pInputData)[1] + position.y; ((float *)pOutputData)[2] = ((float *)pInputData)[2] + position.z; break; } case FIELD_BOOLEAN: case FIELD_INTEGER: *((int *)pOutputData) = *(int *)pInputData; break; case FIELD_SHORT: *((short *)pOutputData) = *(short *)pInputData; break; case FIELD_CHARACTER: *((char *)pOutputData) = *(char *)pInputData; break; case FIELD_POINTER: *((int *)pOutputData) = *(int *)pInputData; break; case FIELD_FUNCTION: { if (!strlen((char *)pInputData)) *((int *)pOutputData) = 0; else *((int *)pOutputData) = FUNCTION_FROM_NAME((char *)pInputData); break; } default: ALERT(at_error, "Bad field type\n"); } } } return fieldNumber; } } return -1; } int CRestore::ReadEntVars(const char *pname, entvars_t *pev) { return ReadFields(pname, pev, gEntvarsDescription, ENTVARS_COUNT); } int CRestore::ReadFields(const char *pname, void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCount) { unsigned short i = ReadShort(); ASSERT(i == sizeof(int)); unsigned short token = ReadShort(); if (token != TokenHash(pname)) { BufferRewind(2 * sizeof(short)); return 0; } int fileCount = ReadInt(); int lastField = 0; for (i = 0; i < fieldCount; i++) { if (!m_global || !(pFields[i].flags & FTYPEDESC_GLOBAL)) memset(((char *)pBaseData + pFields[i].fieldOffset), 0, pFields[i].fieldSize * gSizes[pFields[i].fieldType]); } for (i = 0; i < fileCount; i++) { HEADER header; BufferReadHeader(&header); lastField = ReadField(pBaseData, pFields, fieldCount, lastField, header.size, m_pdata->pTokens[header.token], header.pData); lastField++; } return 1; } void CRestore::BufferReadHeader(HEADER *pheader) { ASSERT(pheader != NULL); pheader->size = ReadShort(); pheader->token = ReadShort(); pheader->pData = BufferPointer(); BufferSkipBytes(pheader->size); } short CRestore::ReadShort(void) { short tmp = 0; BufferReadBytes((char *)&tmp, sizeof(short)); return tmp; } int CRestore::ReadInt(void) { int tmp = 0; BufferReadBytes((char *)&tmp, sizeof(int)); return tmp; } int CRestore::ReadNamedInt(const char *pName) { HEADER header; BufferReadHeader(&header); return ((int *)header.pData)[0]; } char *CRestore::ReadNamedString(const char *pName) { HEADER header; BufferReadHeader(&header); return (char *)header.pData; } char *CRestore::BufferPointer(void) { if (!m_pdata) return NULL; return m_pdata->pCurrentData; } void CRestore::BufferReadBytes(char *pOutput, int size) { ASSERT(m_pdata != NULL); if (!m_pdata || Empty()) return; if ((m_pdata->size + size) > m_pdata->bufferSize) { ALERT(at_error, "Restore overflow!"); m_pdata->size = m_pdata->bufferSize; return; } if (pOutput) memcpy(pOutput, m_pdata->pCurrentData, size); m_pdata->pCurrentData += size; m_pdata->size += size; } void CRestore::BufferSkipBytes(int bytes) { BufferReadBytes(NULL, bytes); } int CRestore::BufferSkipZString(void) { if (!m_pdata) return 0; int maxLen = m_pdata->bufferSize - m_pdata->size; int len = 0; char *pszSearch = m_pdata->pCurrentData; while (*pszSearch++ && len < maxLen) len++; len++; BufferSkipBytes(len); return len; } int CRestore::BufferCheckZString(const char *string) { if (!m_pdata) return 0; int maxLen = m_pdata->bufferSize - m_pdata->size; int len = strlen(string); if (len <= maxLen) { if (!strncmp(string, m_pdata->pCurrentData, len)) return 1; } return 0; } char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd) { char chTextureType; float rgfl1[3], rgfl2[3]; const char *pTextureName; char szbuffer[64]; CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); if (pEntity && pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE) return CHAR_TEX_FLESH; vecSrc.CopyToArray(rgfl1); vecEnd.CopyToArray(rgfl2); if (pEntity) pTextureName = TRACE_TEXTURE(ENT(pEntity->pev), rgfl1, rgfl2); else pTextureName = TRACE_TEXTURE(ENT(0), rgfl1, rgfl2); if (pTextureName) { if (*pTextureName == '-' || *pTextureName == '+') pTextureName += 2; if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') pTextureName++; strcpy(szbuffer, pTextureName); szbuffer[CBTEXTURENAMEMAX - 1] = 0; chTextureType = TEXTURETYPE_Find(szbuffer); } else chTextureType = 0; return chTextureType; } bool UTIL_IsGame(const char *gameName) { char gameDir[4096]; GET_GAME_DIR(gameDir); if (!gameName) return false; return stricmp(gameName, gameDir) == 0; } float UTIL_GetPlayerGaitYaw(int playerIndex) { CBasePlayer *pPlayer = NULL; if (playerIndex > 0 && playerIndex <= gpGlobals->maxClients) { edict_t *pPlayerEdict = INDEXENT(playerIndex); if (pPlayerEdict && !pPlayerEdict->free) { pPlayer = (CBasePlayer *)CBaseEntity::Instance(pPlayerEdict); if (pPlayer) return pPlayer->m_flGaityaw; } } return 0; } int UTIL_HumansInGame(bool ignoreSpectators) { int iCount = 0; for (int i = 1; i <= gpGlobals->maxClients; i++) { CBaseEntity *entity = UTIL_PlayerByIndex(i); if (!entity) continue; if (FNullEnt(entity->pev)) continue; if (!strcmp(STRING(entity->pev->netname), "")) continue; CBasePlayer *player = (CBasePlayer *)entity; if (player->IsBot()) continue; if (ignoreSpectators || (!ignoreSpectators && (player->m_iTeam == TEAM_TERRORIST || player->m_iTeam == TEAM_CT) && player->m_iJoiningState == JOINED)) iCount++; } return iCount; }