.:: Bots United ::.  
filebase forums discord server github wiki web
cubebot epodbot fritzbot gravebot grogbot hpbbot ivpbot jkbotti joebot
meanmod podbotmm racc rcbot realbot sandbot shrikebot soulfathermaps yapb

Go Back   .:: Bots United ::. > Developer's Farm > General Bot Coding
General Bot Coding See what a pain it is to get those little mechs shooting around

Reply
 
Thread Tools
Another IsShootableThruObstacle() function!!!!!!!!
Old
  (#1)
Immortal_BLG
Member
 
Status: Offline
Posts: 171
Join Date: Nov 2007
Location: Russian Federation
Thumbs up Another IsShootableThruObstacle() function!!!!!!!! - 26-08-2009

I wrote the function, placed below, that's 99,99% more accuracy than functions from PoDBot, YaPB or another bot!!!!!!!! - It based on cheat's CanPenetrate() function.

Code:
const bool Bot::IsShootableThruObstacle (const Math::Vector3D &destination)
{
	// This function returns true if enemy can be shoot through some obstacle, false otherwise.

	if (m_profile->skill <= 70u)
		return false;

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

	if (currentWeaponPenetrationPower == 0u)
		return false;

	// set conditions....
	Math::Vector3D source (m_edict->GetEyePosition ());
	const Math::Vector3D &direction ((destination - source).Normalize () * 8.0f);	// 8 units long

	do
	{
		// trace from the bot's eyes to destination...
		HalfLifeEngine::Globals::g_halfLifeEngine->TraceLine (source, destination, HalfLifeEngine::SDK::Constants::TraceIgnore_Monsters, m_edict, m_traceResult);

		if (m_traceResult.isStartSolid)
		{
			if (m_traceResult.isAllSolid)
				return false;

			// move 8 units closer to the destination....
			source += direction;
		}
		else
		{
			// check if line hit anything
			if (m_traceResult.fraction == 1.0f)
				return true;

			--currentWeaponPenetrationPower;

			// move 8 units closer to the destination....
			source = m_traceResult.endPosition + direction;
		}
	} while (currentWeaponPenetrationPower > 0u);

	return false;
}
There 'm_traceResult' it's a HL engine TraceResult structure, placed in main bot class for memory economy .
'currentWeaponPenetrationPower' it's a number, that's can be calculated with below function (from cheat, too)
Code:
int CorrectGun(int weaponID)
{
	if (weaponID == WEAPONLIST_SG550 || weaponID == WEAPONLIST_G3SG1 || weaponID == WEAPONLIST_SCOUT || weaponID == WEAPONLIST_AWP) 
		return 3; 
	if (weaponID == WEAPONLIST_AUG || weaponID == WEAPONLIST_M249 || weaponID == WEAPONLIST_M4A1 || weaponID == WEAPONLIST_DEAGLE || weaponID == WEAPONLIST_SG552 || weaponID == WEAPONLIST_AK47|| weaponID == WEAPONLIST_FAMAS || weaponID == WEAPONLIST_GALIL) 
		return 2; 

	return 0; 
}
- but for me it's too slow, and I placed the numbers above into the WeaponProperties_t structure.
  
Reply With Quote
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 07:04..
  
Reply With Quote
Re: Another IsShootableThruObstacle() function!!!!!!!!
Old
  (#3)
Whistler
Summoner
 
Whistler's Avatar
 
Status: Offline
Posts: 1,499
Join Date: Feb 2004
Location: Mist Village
Default Re: Another IsShootableThruObstacle() function!!!!!!!! - 20-12-2009

well this looks much more detailed than the original PB function don't know how you figured this out but good job anyway
  
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump



Powered by vBulletin® Version 3.8.2
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
vBulletin Skin developed by: vBStyles.com