View Single Post
Re: Another IsShootableThruObstacle() function!!!!!!!!
Old
  (#2)
Immortal_BLG
Member
 
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
Thumbs up Re: Another IsShootableThruObstacle() function!!!!!!!! - 20-12-2009

Another function to determine penetration damage.

Code:
enum WeaponBulletType_t
{
	WeaponBulletType_0,
	WeaponBulletType_1,
	WeaponBulletType_2,
	WeaponBulletType_3,
	WeaponBulletType_4,
	WeaponBulletType_5,
	WeaponBulletType_6,
	WeaponBulletType_7,
	WeaponBulletType_8,
	WeaponBulletType_9,
	WeaponBulletType_10,
	WeaponBulletType_11,
	WeaponBulletType_12,
	WeaponBulletType_13,
	WeaponBulletType_14,
	WeaponBulletType_15
};

enum WeaponObstaclePenetrationPower_t
{
	WeaponObstaclePenetrationPower_0,
	WeaponObstaclePenetrationPower_1,
	WeaponObstaclePenetrationPower_2
};

enum Constants_t
{
	HalfMapSize = 4096u,
	MapSize     = 8192u
};

enum TextureType_t
{
	TextureType_None,

	TextureType_Concrete     = 'C',
	TextureType_Metal        = 'M',
	TextureType_Dirt         = 'D',
	TextureType_Ventillation = 'V',
	TextureType_Grate        = 'G',
	TextureType_Tile         = 'T',
	TextureType_SloshLiquid  = 'S',
	TextureType_Wood         = 'W',
	TextureType_Computer     = 'P',
	TextureType_Grass        = 'X',
	TextureType_Glass        = 'Y',
	TextureType_Flesh        = 'F',
	TextureType_Snow         = 'N'
};

struct WeaponPenetrationInformation_t
{
	WeaponBulletType_t bulletType;			// weapon bullet type
	unsigned char      penetrationPower;		// can shoot thru walls
	unsigned short     maximumShootDistance;	// maximum shoot distance

	// Information: damage/obstacle pierce for usp/m4a1 - unsilenced/silenced.
	unsigned char      damage1;			// damage 1
	unsigned char      damage2;			// damage 2

	float              obstaclePierce1;			// obstacle pierce 1
	float              obstaclePierce2;			// obstacle pierce 2
} g_weaponPenetrationInformation[] =
{
	// Terminator, since weapon id's are starting from 1 in Half-Life engine. :-(
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,   0u,  0u,  0.0f,   0.0f},		// WeaponID_None

	{WeaponBulletType_15, WeaponObstaclePenetrationPower_0, HalfMapSize,  32u,  0u,  0.8f,   0.0f},		// WeaponID_P228
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,   0u,  0u,  0.0f,   0.0f},		// WeaponID_Shield
	{WeaponBulletType_11, WeaponObstaclePenetrationPower_2, MapSize,      75u,  0u,  0.98f,  0.0f},		// WeaponID_Scout
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,  97u,  0u,  0.0f,   0.0f},		// WeaponID_Esplosive
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u, 115u,  0u,  0.0f,   0.0f},		// WeaponID_XM1014
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,   0u,  0u,  0.0f,   0.0f},		// WeaponID_C4
	{WeaponBulletType_9,  WeaponObstaclePenetrationPower_0, MapSize,      29u,  0u,  0.82f,  0.0f},		// WeaponID_MAC10
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      32u,  0u,  0.96f,  0.0f},		// WeaponID_Aug
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,   0u,  0u,  0.0f,   0.0f},		// WeaponID_Smoke
	{WeaponBulletType_1,  WeaponObstaclePenetrationPower_0, MapSize,      36u,  0u,  0.75f,  0.0f},		// WeaponID_Elite
	{WeaponBulletType_15, WeaponObstaclePenetrationPower_0, HalfMapSize,  20u,  0u,  0.885f, 0.0f},		// WeaponID_FiveSeven
	{WeaponBulletType_9,  WeaponObstaclePenetrationPower_0, MapSize,      30u,  0u,  0.82f,  0.0f},		// WeaponID_UMP45
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      70u,  0u,  0.98f,  0.0f},		// WeaponID_SG550
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      30u,  0u,  0.96f,  0.0f},		// WeaponID_Galil
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      30u,  0u,  0.96f,  0.0f},		// WeaponID_Famas
	{WeaponBulletType_9,  WeaponObstaclePenetrationPower_0, HalfMapSize,  34u, 30u,  0.79f,  0.79f},	// WeaponID_USP
	{WeaponBulletType_1,  WeaponObstaclePenetrationPower_0, MapSize,      25u,  0u,  0.75f,  0.0f},		// WeaponID_Glock18
	{WeaponBulletType_10, WeaponObstaclePenetrationPower_2, MapSize,     115u,  0u,  0.99f,  0.0f},		// WeaponID_AWP
	{WeaponBulletType_1,  WeaponObstaclePenetrationPower_0, MapSize,      26u,  0u,  0.84f,  0.0f},		// WeaponID_MP5
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      32u,  0u,  0.97f,  0.0f},		// WeaponID_M249
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0, HalfMapSize, 172u,  0u,  0.0f,   0.0f},		// WeaponID_M3
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      32u, 33u,  0.97f,  0.95f},	// WeaponID_M4A1
	{WeaponBulletType_1,  WeaponObstaclePenetrationPower_0, MapSize,      20u,  0u,  0.85f,  0.0f},		// WeaponID_TMP
	{WeaponBulletType_11, WeaponObstaclePenetrationPower_1, MapSize,      80u,  0u,  0.98f,  0.0f},		// WeaponID_G3SG1
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,   0u,  0u,  0.0f,   0.0f},		// WeaponID_Flashbang
	{WeaponBulletType_13, WeaponObstaclePenetrationPower_1, MapSize,      54u,  0u,  0.81f,  0.0f},		// WeaponID_Deagle
	{WeaponBulletType_12, WeaponObstaclePenetrationPower_1, MapSize,      33u,  0u,  0.955f, 0.0f},		// WeaponID_SG552
	{WeaponBulletType_11, WeaponObstaclePenetrationPower_1, MapSize,      36u,  0u,  0.98f,  0.0f},		// WeaponID_AK47
	{WeaponBulletType_0,  WeaponObstaclePenetrationPower_0,          0u,  16u, 66u,  0.0f,   0.0f},		// WeaponID_Knife
	{WeaponBulletType_14, WeaponObstaclePenetrationPower_0, HalfMapSize,  21u,  0u,  0.885f, 0.0f}		// WeaponID_P90
};

template <typename elementType> inline void Swap (elementType &left, elementType &right)
{
	// This template function exchanges values stored at 'left' and 'right'.

	// different, worth swapping
	assert (&left != &right);

	elementType temp (left);

	// swap....
	left = right;
	right = temp;
}

inline const bool GetLineFromFileBuffer (const char *const fileBuffer, unsigned int fileSize, unsigned int &filePosition, char *const buffer, const unsigned short bufferSize)
{
	// Bullet-proofing
	assert (filePosition < fileSize);

	unsigned int index (filePosition);

	// fgets always NULL terminates, so only read bufferSize - 1 characters
	if (fileSize - filePosition > bufferSize - 1u)
		fileSize = filePosition + bufferSize - 1u;

	// Stop at the next newline (inclusive) or end of buffer
	while (index < fileSize)
		if (fileBuffer[index++] == '\n')
			break;

	// If we actually advanced the pointer, copy it over
	if (index > filePosition)
	{
		// We read in size bytes
		const unsigned short size (static_cast <unsigned short> (index - filePosition));

		// copy it out
		memcpy (buffer, fileBuffer + filePosition, size);

		buffer[size] = 0;

		// Update file pointer
		filePosition = index;

		return true;
	}

	// No data read, bail
	return false;
}

class TexturesManager
{
	private:
		enum
		{
			MaximumTextureNameLength = 13u,	// only load first n chars of name
			MaximumTexturesNumber    = 512u	// max number of textures loaded
		};

		struct Texture_t
		{
			char type;								// texture type (from 'TextureType_t' enumeration)
			char name[MaximumTextureNameLength];	// texture name
		};

		Texture_t      m_textures[MaximumTexturesNumber];
		unsigned short m_texturesNumber;

	public:
		TexturesManager (void) : m_texturesNumber (0u)
		{
			int fileSize;
			unsigned char *const file (LOAD_FILE_FOR_ME ("sound/materials.txt", &fileSize));

			if (file == NULL)
				return;

			char *buffer;
			unsigned int filePosition (0u);
			unsigned short startIndex, endIndex;

			// for each line in the file...
			while (GetLineFromFileBuffer (static_cast <const char *const> (static_cast <const void *const> (file)), fileSize, filePosition, buffer, 511u))
			{
				startIndex = 0u;

				// skip whitespaces
				while (buffer[startIndex] != 0 && isspace (buffer[startIndex]))
					++startIndex;

				if (buffer[startIndex] == 0)
					continue;

				// skip comment lines
				if (buffer[startIndex] == '/' || !isalpha (buffer[startIndex]))
					continue;

				// get texture type
				m_textures[m_texturesNumber].type = static_cast <char> (toupper (buffer[startIndex++]));

				// skip whitespace
				while (buffer[startIndex] != 0 && isspace (buffer[startIndex]))
					++startIndex;

				if (buffer[startIndex] == 0)
					continue;

				// get sentence name
				endIndex = startIndex;

				while (buffer[endIndex] != 0 && !isspace (buffer[endIndex]))
					++endIndex;

				if (buffer[endIndex] == 0)
					continue;

				// null-terminate name and save in sentences array
				buffer[min (endIndex, MaximumTextureNameLength - 1u + startIndex)] = 0;

				strcpy (m_textures[m_texturesNumber].name, buffer + startIndex);

				if (++m_texturesNumber == MaximumTexturesNumber)
					break;
			}

			// Must use engine to free since we are in a .dll
			FREE_FILE (file);

			SortTextures ();
		}

	private:
		inline void SwapTextures (const unsigned short i, const unsigned short j)
		{
			Swap (m_textures[i].type, m_textures[j].type);
			Swap (m_textures[i].name, m_textures[j].name);
		}

		inline void SortTextures (void)
		{
			// Bubble sort, yuck, but this only occurs at startup and it's only 512 elements...

			for (unsigned short i (0u), j; i < m_texturesNumber; ++i)
				for (j = i + 1u; j < m_texturesNumber; ++j)
					if (stricmp (m_textures[i].name, m_textures[j].name) > 0)
					{
						// Swap
						SwapTextures (i, j);
					}
		}

		inline const char FindTextureType (const char *const name) const
		{
			// given texture name, find texture type
			// if not found, return type 'concrete'

			unsigned short pivot, left (0u);
			int right (m_texturesNumber), value;

			do
			{
				// To start, find the subscript of the middle position.
				if ((value = strnicmp (m_textures[pivot = static_cast <unsigned short> ((left + right) / 2u)].name, name)) == 0)
					return m_textures[pivot].type;

				if (value > 0)	// If the number is > key, increase position by one.
					left = pivot + 1u;
				else	// Else (value < 0), decrease position by one.
					right = pivot - 1;
			} while (left <= right);

			return TextureType_Concrete;
		}

	public:
		inline const char GetTextureType (Edict_t *const entity, const Math::Vector3D &source, const Math::Vector3D &destination) const
		{
			const unsigned short entityIndex (ENTINDEX (entity));

			if (entityIndex == 0u)
			{
				// get texture from entity or world (world is ent(0))
				const char *textureName (TRACE_TEXTURE (entity, source, destination));

				if (textureName != NULL)
				{
					// strip leading '-0' or '+0~' or '{' or '!'
					if (*textureName == '-' || *textureName == '+')
						textureName += 2u;

					if (*textureName == '{' || *textureName == '!' || *textureName == '~' || *textureName == ' ')
						++textureName;

					// '}}'
					// get texture type
					return FindTextureType (textureName);
				}
			}
			else if (entityIndex >= 1u && entityIndex <= g_pGlobals->maxClients)	// Player
				return TextureType_Flesh;	// hit body

			return TextureType_None;
		}
};

TexturesManager *g_texturesManager;	// NOTE: Initialize this after getting the engine functions!

const unsigned char Bot::GetPenetrationDamage (const Math::Vector3D &source, const Math::Vector3D &destination)
{
	if (m_profile->skill <= 70u)
		return 0u;

	unsigned char currentWeaponPenetrationPower (static_cast <unsigned char> (g_weaponProperties[m_currentWeapon->GetID ()].penetrationPower));

	if (currentWeaponPenetrationPower == WeaponObstaclePenetrationPower_0)
		return false;

	Math::Vector3D start (source), end (destination), direction (end - start);
	float distanceFraction, damageMult (0.5f), distanceMaximum (0.0f);
	const float length (direction.GetLength ());
	unsigned char bulletVelocity (0u);
	float distance (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].maximumShootDistance);
	unsigned char currentWeaponPenetrationPower (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].currentWeaponPenetrationPower + 1u);

	// What damage/obstaclePierce (first(silenced) or second(unsilenced)) can easily identify with CS offsets (for windows=74, for linux=don't know :), flags=USP_SILENCED = (1u << 0u), M4A1_SILENCED = (1u << 2u)) - ONLY FOR USP OR M4A1!!!!!!!!!!!!
	unsigned char damage (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].damage1);
	const float obstaclePierce (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].obstaclePierce1);

	direction /= length;

	end = direction * distance + start;

	++currentWeaponPenetrationPower;

	// damage gets a randomlong added to it in first switch
	switch (g_weaponPenetrationInformation[m_currentWeapon->GetID ()].bulletType)
	{
		case WeaponBulletType_1:
			bulletVelocity = 21u;
			distanceMaximum = 800.0f;

			break;

		case WeaponBulletType_9:
			switch (yb_wall_sensitivity.GetInt ())
			{
				case 0u:
					damage -= 2u;

					break;

				case 2u:
					damage += 2u;

					break;
			}

			bulletVelocity = 15u;
			distanceMaximum = 500.0f;

			break;

		case WeaponBulletType_13:
			bulletVelocity = 30u;
			distanceMaximum = 1000.0f;

			break;

		case WeaponBulletType_11:
			switch (yb_wall_sensitivity.GetInt ())
			{
				case 0u:
					damage -= 2u;

					break;

				case 2u:
					damage += 2u;

					break;
			}

			bulletVelocity = 39u;
			distanceMaximum = 5000.0f;

			break;

		case WeaponBulletType_12:
			switch (yb_wall_sensitivity.GetInt ())
			{
				case 0u:
					damage -= 3u;

					break;

				case 2u:
					damage += 3u;

					break;
			}

			bulletVelocity = 35u;
			distanceMaximum = 4000.0f;

			break;

		case WeaponBulletType_10:
			switch (yb_wall_sensitivity.GetInt ())
			{
				case 0u:
					damage -= 4u;

					break;

				case 2u:
					damage += 4u;

					break;
			}

			bulletVelocity = 45u;
			distanceMaximum = 8000.0f;

			break;

		case WeaponBulletType_14:
			switch (yb_wall_sensitivity.GetInt ())
			{
				case 0u:
					damage -= 4u;

					break;

				case 2u:
					damage += 6u;

					break;

				default:
					++damage;

					break;
			}

			bulletVelocity = 30u;
			distanceMaximum = 2000.0f;

			break;

		case WeaponBulletType_15:
			switch (yb_wall_sensitivity.GetInt ())
			{
				case 0u:
					damage -= 4u;

					break;

				case 2u:
					damage += 6u;

					break;

				default:
					++damage;

					break;
			}

			bulletVelocity = 25u;
			distanceMaximum = 800.0f;

			break;

		default:
			break;
	}

	for (/*Empty*/; /*Empty*/; /*Empty*/)
	{
		TRACE_LINE (start, end, TraceIgnore_Monsters, m_edict, m_traceResult);

		if (m_traceResult.fraction == 1.0f)
			return 0u;

		switch (g_texturesManager->GetTextureType (m_traceResult.hitEntity, start, end))
		{
			case TextureType_Concrete:
				bulletVelocity *= 0.25f;

				break;

			case TextureType_Grate:
				bulletVelocity *= 0.5f;
				damageMult = 0.4f;

				break;

			case TextureType_Metal:
				bulletVelocity *= 0.15f;
				damageMult = 0.2f;

				break;

			case TextureType_Computer:
				bulletVelocity *= 0.4f;

				break;

			case TextureType_Tile:
				bulletVelocity *= 0.65f;
				damageMult = 0.2f;

				break;

			case TextureType_Ventillation:
				bulletVelocity *= 0.5f;
				damageMult = 0.45f;

				break;

			case TextureType_Wood:
				damageMult = 0.6f;

			default:
				break;
		}

		if ((m_traceResult.endPosition - source).GetLength () >= length)
		{
			m_traceResult.fraction = (destination - start).GetLength () / (end - start).GetLength ();

			distanceFraction = distance * m_traceResult.fraction;

			damage *= pow (obstaclePierce, distanceFraction * 0.002f);

			return damage;
		}

		if (--currentWeaponPenetrationPower == 0u || (distanceFraction = distance * m_traceResult.fraction) > distanceMaximum)
			return 0u;

		damage *= pow (obstaclePierce, distanceFraction * 0.002f);

		start = bulletVelocity * direction + m_traceResult.endPosition;
		distance = (distance - distanceFraction) * 0.5f;
		end = direction * distance + start;
		distanceFraction = damage;
		damage = static_cast <unsigned char> (distanceFraction * damageMult);
	}
}
Sorry, that without explanations - in the first place: badly with English, secondly: I badly explain
In general, anyone interested - will understand

Last edited by Immortal_BLG; 20-12-2009 at 06:04..
  
Reply With Quote